diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 583febe8..30bff204 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,3 +1,4 @@ +import com.android.build.api.artifact.SingleArtifact import com.android.build.api.dsl.ApplicationExtension import com.android.build.api.dsl.ProductFlavor import com.android.build.api.variant.FilterConfiguration @@ -5,6 +6,7 @@ import com.google.protobuf.gradle.id import com.mikepenz.aboutlibraries.plugin.DuplicateMode import com.mikepenz.aboutlibraries.plugin.DuplicateRule import org.jetbrains.kotlin.gradle.dsl.JvmTarget +import java.io.File import java.util.Base64 import java.util.Properties @@ -194,6 +196,7 @@ configure { sourceSets { getByName("main") { kotlin.directories += "$buildDir/generated/seerr_api/src/main/kotlin" + kotlin.directories += "src/wolfskin/java" } } @@ -224,6 +227,47 @@ androidComponents { "Wholphin-${variant.flavorName}-${variant.buildType}-${output.versionName.get()}-${output.versionCode.get()}$abi.apk" output.outputFileName = outputFileName } + if (variant.name == "defaultDebug") { + val packagedApks = variant.artifacts.get(SingleArtifact.APK) + val artifactLoader = variant.artifacts.getBuiltArtifactsLoader() + val aapt2 = sdkComponents.aapt2.flatMap { it.executable } + val checkWolfskinBranding = tasks.register("checkWolfskinBranding") { + inputs.dir(packagedApks) + inputs.file(aapt2) + doLast { + val artifacts = checkNotNull(artifactLoader.load(packagedApks.get())) { + "Packaged default/debug APK metadata was not found; branding is unverified" + }.elements + check(artifacts.isNotEmpty()) { "No default/debug APKs were found; branding is unverified" } + val header = Regex("""^\s*resource 0x[\da-fA-F]+ (?:[^\s:]+:)?([^\s/]+)/([^\s]+)""") + val visibleTypes = setOf("string", "plurals", "array") + // Upstream legal attribution and its project URL must survive the branding cutover. + val legalNames = setOf("wolfskin_upstream_credit", "wolfskin_upstream_url") + val violations = sortedSetOf() + artifacts.forEach { artifact -> + val dump = providers.exec { + commandLine(aapt2.get().asFile, "dump", "resources", artifact.outputFile) + }.standardOutput.asText.get() + var currentName: String? = null + var inspected = 0 + dump.lineSequence().forEach { line -> + val resource = header.find(line) + if (resource != null) { + currentName = resource.groupValues[2].takeIf { resource.groupValues[1] in visibleTypes } + if (currentName != null) inspected++ + } else if (currentName != null && currentName !in legalNames && line.contains("Wholphin", ignoreCase = true)) { + violations += "${File(artifact.outputFile).name}:$currentName" + } + } + check(inspected > 0) { "No packaged string resources were decoded; branding is unverified" } + logger.lifecycle("Inspected $inspected string/plural/array resources in ${File(artifact.outputFile).name}") + } + check(violations.isEmpty()) { "User-visible upstream branding remains: ${violations.joinToString()}" } + logger.lifecycle("Wolfskin branding check passed (${artifacts.size} packaged debug APKs; legal attribution preserved)") + } + } + tasks.matching { it.name == "assembleDefaultDebug" }.configureEach { dependsOn(checkWolfskinBranding) } + } } } @@ -288,6 +332,7 @@ tasks.named("preBuild") { } dependencies { + implementation(project(":wolfskin-design")) implementation(project(":conductarr-client")) implementation(libs.androidx.core.ktx) implementation(libs.androidx.appcompat) @@ -407,8 +452,18 @@ dependencies { testImplementation(libs.robolectric) testImplementation(libs.hilt.android.testing) testImplementation(libs.androidx.compose.ui.test.junit4) + testImplementation("io.github.takahirom.roborazzi:roborazzi:1.77.0") + testImplementation("io.github.takahirom.roborazzi:roborazzi-compose:1.77.0") androidTestImplementation(platform(libs.androidx.compose.bom)) androidTestImplementation(libs.mockk.android) androidTestImplementation(libs.hilt.android.testing) androidTestImplementation(libs.androidx.compose.ui.test.manifest) } + +tasks.withType().configureEach { + dependsOn(":wolfskin-design:testDebugUnitTest") + systemProperty("robolectric.dependency.dir", project(":wolfskin-design").layout.buildDirectory.dir("robolectric-sdk").get().asFile.absolutePath) + systemProperty("robolectric.offline", "true") + systemProperty("roborazzi.test.record", "true") + systemProperty("wolfskin.captureDirectory", rootProject.layout.buildDirectory.dir("wolfskin-captures").get().asFile.absolutePath) +} diff --git a/app/src/debug/assets/library/assets/movie-101-dalmatians-ii-patch-s-london-adventure-2003-poster.jpg b/app/src/debug/assets/library/assets/movie-101-dalmatians-ii-patch-s-london-adventure-2003-poster.jpg new file mode 100644 index 00000000..b9b72894 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-101-dalmatians-ii-patch-s-london-adventure-2003-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-12-years-a-slave-2013-poster.jpg b/app/src/debug/assets/library/assets/movie-12-years-a-slave-2013-poster.jpg new file mode 100644 index 00000000..ff1f55e6 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-12-years-a-slave-2013-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-a-bronx-tale-1993-poster.jpg b/app/src/debug/assets/library/assets/movie-a-bronx-tale-1993-poster.jpg new file mode 100644 index 00000000..f7444271 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-a-bronx-tale-1993-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-a-silent-voice-the-movie-2016-poster.jpg b/app/src/debug/assets/library/assets/movie-a-silent-voice-the-movie-2016-poster.jpg new file mode 100644 index 00000000..580b22f4 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-a-silent-voice-the-movie-2016-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-absolution-2024-poster.jpg b/app/src/debug/assets/library/assets/movie-absolution-2024-poster.jpg new file mode 100644 index 00000000..3ce49112 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-absolution-2024-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-across-the-hall-2009-poster.jpg b/app/src/debug/assets/library/assets/movie-across-the-hall-2009-poster.jpg new file mode 100644 index 00000000..52362b4e Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-across-the-hall-2009-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-addicted-2014-poster.jpg b/app/src/debug/assets/library/assets/movie-addicted-2014-poster.jpg new file mode 100644 index 00000000..e9a03c14 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-addicted-2014-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-adulterers-2016-poster.jpg b/app/src/debug/assets/library/assets/movie-adulterers-2016-poster.jpg new file mode 100644 index 00000000..8b65745b Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-adulterers-2016-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-all-the-money-in-the-world-2017-poster.jpg b/app/src/debug/assets/library/assets/movie-all-the-money-in-the-world-2017-poster.jpg new file mode 100644 index 00000000..8beb2f7f Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-all-the-money-in-the-world-2017-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-alone-with-her-2006-poster.jpg b/app/src/debug/assets/library/assets/movie-alone-with-her-2006-poster.jpg new file mode 100644 index 00000000..7ce6fa96 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-alone-with-her-2006-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-american-gangster-2007-poster.jpg b/app/src/debug/assets/library/assets/movie-american-gangster-2007-poster.jpg new file mode 100644 index 00000000..0f41d299 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-american-gangster-2007-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-annie-hall-1977-poster.jpg b/app/src/debug/assets/library/assets/movie-annie-hall-1977-poster.jpg new file mode 100644 index 00000000..9023a691 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-annie-hall-1977-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-ant-man-and-the-wasp-quantumania-2023-poster.jpg b/app/src/debug/assets/library/assets/movie-ant-man-and-the-wasp-quantumania-2023-poster.jpg new file mode 100644 index 00000000..030addf0 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-ant-man-and-the-wasp-quantumania-2023-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-apocalypse-now-1979-poster.jpg b/app/src/debug/assets/library/assets/movie-apocalypse-now-1979-poster.jpg new file mode 100644 index 00000000..09cd6aa8 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-apocalypse-now-1979-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-appleseed-alpha-2014-poster.jpg b/app/src/debug/assets/library/assets/movie-appleseed-alpha-2014-poster.jpg new file mode 100644 index 00000000..62bd0afa Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-appleseed-alpha-2014-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-aquaman-and-the-lost-kingdom-2023-poster.jpg b/app/src/debug/assets/library/assets/movie-aquaman-and-the-lost-kingdom-2023-poster.jpg new file mode 100644 index 00000000..4550bdaa Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-aquaman-and-the-lost-kingdom-2023-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-arctic-dogs-2019-poster.jpg b/app/src/debug/assets/library/assets/movie-arctic-dogs-2019-poster.jpg new file mode 100644 index 00000000..07552443 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-arctic-dogs-2019-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-arrival-2016-poster.jpg b/app/src/debug/assets/library/assets/movie-arrival-2016-poster.jpg new file mode 100644 index 00000000..fe224a15 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-arrival-2016-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-avatar-aang-the-last-airbender-2026-poster.jpg b/app/src/debug/assets/library/assets/movie-avatar-aang-the-last-airbender-2026-poster.jpg new file mode 100644 index 00000000..f57f1052 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-avatar-aang-the-last-airbender-2026-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-avengers-age-of-ultron-2015-poster.jpg b/app/src/debug/assets/library/assets/movie-avengers-age-of-ultron-2015-poster.jpg new file mode 100644 index 00000000..300840ff Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-avengers-age-of-ultron-2015-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-avengers-confidential-black-widow-punisher-2014-poster.jpg b/app/src/debug/assets/library/assets/movie-avengers-confidential-black-widow-punisher-2014-poster.jpg new file mode 100644 index 00000000..b096fff2 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-avengers-confidential-black-widow-punisher-2014-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-avengers-infinity-war-2018-poster.jpg b/app/src/debug/assets/library/assets/movie-avengers-infinity-war-2018-poster.jpg new file mode 100644 index 00000000..57df9298 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-avengers-infinity-war-2018-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-awake-2007-poster.jpg b/app/src/debug/assets/library/assets/movie-awake-2007-poster.jpg new file mode 100644 index 00000000..32595897 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-awake-2007-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-batman-ninja-2018-poster.jpg b/app/src/debug/assets/library/assets/movie-batman-ninja-2018-poster.jpg new file mode 100644 index 00000000..7f59127b Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-batman-ninja-2018-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-batman-the-dark-knight-returns-part-1-2012-poster.jpg b/app/src/debug/assets/library/assets/movie-batman-the-dark-knight-returns-part-1-2012-poster.jpg new file mode 100644 index 00000000..ce5623fe Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-batman-the-dark-knight-returns-part-1-2012-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-batman-v-superman-dawn-of-justice-2016-poster.jpg b/app/src/debug/assets/library/assets/movie-batman-v-superman-dawn-of-justice-2016-poster.jpg new file mode 100644 index 00000000..f8115170 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-batman-v-superman-dawn-of-justice-2016-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-black-adam-2022-poster.jpg b/app/src/debug/assets/library/assets/movie-black-adam-2022-poster.jpg new file mode 100644 index 00000000..dde008b5 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-black-adam-2022-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-black-bear-2020-poster.jpg b/app/src/debug/assets/library/assets/movie-black-bear-2020-poster.jpg new file mode 100644 index 00000000..61c8860f Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-black-bear-2020-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-black-panther-2018-poster.jpg b/app/src/debug/assets/library/assets/movie-black-panther-2018-poster.jpg new file mode 100644 index 00000000..6fdaa3d2 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-black-panther-2018-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-black-panther-wakanda-forever-2022-poster.jpg b/app/src/debug/assets/library/assets/movie-black-panther-wakanda-forever-2022-poster.jpg new file mode 100644 index 00000000..d0219a75 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-black-panther-wakanda-forever-2022-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-blame-2017-poster.jpg b/app/src/debug/assets/library/assets/movie-blame-2017-poster.jpg new file mode 100644 index 00000000..8d50255f Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-blame-2017-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-bleach-the-movie-fade-to-black-2008-poster.jpg b/app/src/debug/assets/library/assets/movie-bleach-the-movie-fade-to-black-2008-poster.jpg new file mode 100644 index 00000000..d3619fbd Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-bleach-the-movie-fade-to-black-2008-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-bohemian-rhapsody-2018-poster.jpg b/app/src/debug/assets/library/assets/movie-bohemian-rhapsody-2018-poster.jpg new file mode 100644 index 00000000..20d2f9ee Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-bohemian-rhapsody-2018-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-braveheart-1995-poster.jpg b/app/src/debug/assets/library/assets/movie-braveheart-1995-poster.jpg new file mode 100644 index 00000000..32fd8d4d Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-braveheart-1995-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-butterfly-on-a-wheel-2007-poster.jpg b/app/src/debug/assets/library/assets/movie-butterfly-on-a-wheel-2007-poster.jpg new file mode 100644 index 00000000..b54cc5c7 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-butterfly-on-a-wheel-2007-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-by-any-means-2026-poster.jpg b/app/src/debug/assets/library/assets/movie-by-any-means-2026-poster.jpg new file mode 100644 index 00000000..92fd601f Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-by-any-means-2026-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-captain-america-civil-war-2016-poster.jpg b/app/src/debug/assets/library/assets/movie-captain-america-civil-war-2016-poster.jpg new file mode 100644 index 00000000..426142ef Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-captain-america-civil-war-2016-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-captain-america-the-first-avenger-2011-poster.jpg b/app/src/debug/assets/library/assets/movie-captain-america-the-first-avenger-2011-poster.jpg new file mode 100644 index 00000000..bba96574 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-captain-america-the-first-avenger-2011-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-captain-america-the-winter-soldier-2014-poster.jpg b/app/src/debug/assets/library/assets/movie-captain-america-the-winter-soldier-2014-poster.jpg new file mode 100644 index 00000000..c2dc5612 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-captain-america-the-winter-soldier-2014-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-careful-what-you-wish-for-2015-poster.jpg b/app/src/debug/assets/library/assets/movie-careful-what-you-wish-for-2015-poster.jpg new file mode 100644 index 00000000..b58ce600 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-careful-what-you-wish-for-2015-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-castle-in-the-sky-1986-poster.jpg b/app/src/debug/assets/library/assets/movie-castle-in-the-sky-1986-poster.jpg new file mode 100644 index 00000000..a6a99fee Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-castle-in-the-sky-1986-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-chicago-2002-poster.jpg b/app/src/debug/assets/library/assets/movie-chicago-2002-poster.jpg new file mode 100644 index 00000000..1def9414 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-chicago-2002-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-citizen-kane-1941-poster.jpg b/app/src/debug/assets/library/assets/movie-citizen-kane-1941-poster.jpg new file mode 100644 index 00000000..f26414a7 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-citizen-kane-1941-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-coherence-2014-poster.jpg b/app/src/debug/assets/library/assets/movie-coherence-2014-poster.jpg new file mode 100644 index 00000000..f3601b9b Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-coherence-2014-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-conclave-2024-poster.jpg b/app/src/debug/assets/library/assets/movie-conclave-2024-poster.jpg new file mode 100644 index 00000000..c6aecefa Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-conclave-2024-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-crime-of-passion-1956-poster.jpg b/app/src/debug/assets/library/assets/movie-crime-of-passion-1956-poster.jpg new file mode 100644 index 00000000..4acfa871 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-crime-of-passion-1956-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-deep-water-2022-poster.jpg b/app/src/debug/assets/library/assets/movie-deep-water-2022-poster.jpg new file mode 100644 index 00000000..018d4f4b Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-deep-water-2022-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-derailed-2005-poster.jpg b/app/src/debug/assets/library/assets/movie-derailed-2005-poster.jpg new file mode 100644 index 00000000..d93f3124 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-derailed-2005-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-die-my-love-2025-poster.jpg b/app/src/debug/assets/library/assets/movie-die-my-love-2025-poster.jpg new file mode 100644 index 00000000..f6eca818 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-die-my-love-2025-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-dream-house-2011-poster.jpg b/app/src/debug/assets/library/assets/movie-dream-house-2011-poster.jpg new file mode 100644 index 00000000..d3444637 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-dream-house-2011-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-dream-lover-1994-poster.jpg b/app/src/debug/assets/library/assets/movie-dream-lover-1994-poster.jpg new file mode 100644 index 00000000..3b563cf9 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-dream-lover-1994-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-drop-2025-poster.jpg b/app/src/debug/assets/library/assets/movie-drop-2025-poster.jpg new file mode 100644 index 00000000..4cf7d66b Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-drop-2025-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-eastern-promises-2007-poster.jpg b/app/src/debug/assets/library/assets/movie-eastern-promises-2007-poster.jpg new file mode 100644 index 00000000..01a26f3b Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-eastern-promises-2007-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-easy-a-2010-poster.jpg b/app/src/debug/assets/library/assets/movie-easy-a-2010-poster.jpg new file mode 100644 index 00000000..45e13a32 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-easy-a-2010-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-el-camino-a-breaking-bad-movie-2019-poster.jpg b/app/src/debug/assets/library/assets/movie-el-camino-a-breaking-bad-movie-2019-poster.jpg new file mode 100644 index 00000000..7a62df45 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-el-camino-a-breaking-bad-movie-2019-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-emancipation-2022-poster.jpg b/app/src/debug/assets/library/assets/movie-emancipation-2022-poster.jpg new file mode 100644 index 00000000..c1bee971 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-emancipation-2022-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-faces-1968-poster.jpg b/app/src/debug/assets/library/assets/movie-faces-1968-poster.jpg new file mode 100644 index 00000000..43f996bd Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-faces-1968-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-fatale-2020-poster.jpg b/app/src/debug/assets/library/assets/movie-fatale-2020-poster.jpg new file mode 100644 index 00000000..dda9d622 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-fatale-2020-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-fighting-with-my-family-2019-poster.jpg b/app/src/debug/assets/library/assets/movie-fighting-with-my-family-2019-poster.jpg new file mode 100644 index 00000000..169c466d Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-fighting-with-my-family-2019-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-force-of-nature-the-dry-2-2024-poster.jpg b/app/src/debug/assets/library/assets/movie-force-of-nature-the-dry-2-2024-poster.jpg new file mode 100644 index 00000000..93ba0d71 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-force-of-nature-the-dry-2-2024-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-free-state-of-jones-2016-poster.jpg b/app/src/debug/assets/library/assets/movie-free-state-of-jones-2016-poster.jpg new file mode 100644 index 00000000..e69af7c0 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-free-state-of-jones-2016-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-from-up-on-poppy-hill-2011-poster.jpg b/app/src/debug/assets/library/assets/movie-from-up-on-poppy-hill-2011-poster.jpg new file mode 100644 index 00000000..264076e2 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-from-up-on-poppy-hill-2011-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-ghost-in-the-shell-1995-poster.jpg b/app/src/debug/assets/library/assets/movie-ghost-in-the-shell-1995-poster.jpg new file mode 100644 index 00000000..58d221ba Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-ghost-in-the-shell-1995-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-ghost-in-the-shell-2-innocence-2004-poster.jpg b/app/src/debug/assets/library/assets/movie-ghost-in-the-shell-2-innocence-2004-poster.jpg new file mode 100644 index 00000000..ae262147 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-ghost-in-the-shell-2-innocence-2004-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-gosford-park-2001-poster.jpg b/app/src/debug/assets/library/assets/movie-gosford-park-2001-poster.jpg new file mode 100644 index 00000000..6a6aa651 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-gosford-park-2001-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-grave-of-the-fireflies-1988-poster.jpg b/app/src/debug/assets/library/assets/movie-grave-of-the-fireflies-1988-poster.jpg new file mode 100644 index 00000000..1b71996a Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-grave-of-the-fireflies-1988-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-howl-s-moving-castle-2004-poster.jpg b/app/src/debug/assets/library/assets/movie-howl-s-moving-castle-2004-poster.jpg new file mode 100644 index 00000000..042a6c80 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-howl-s-moving-castle-2004-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-in-the-heights-2021-poster.jpg b/app/src/debug/assets/library/assets/movie-in-the-heights-2021-poster.jpg new file mode 100644 index 00000000..e05bfdb0 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-in-the-heights-2021-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-jennifer-s-body-2009-poster.jpg b/app/src/debug/assets/library/assets/movie-jennifer-s-body-2009-poster.jpg new file mode 100644 index 00000000..41cc1eb5 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-jennifer-s-body-2009-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-kiki-s-delivery-service-1989-poster.jpg b/app/src/debug/assets/library/assets/movie-kiki-s-delivery-service-1989-poster.jpg new file mode 100644 index 00000000..80a59b1e Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-kiki-s-delivery-service-1989-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-lemony-snicket-s-a-series-of-unfortunate-events-2004-poster.jpg b/app/src/debug/assets/library/assets/movie-lemony-snicket-s-a-series-of-unfortunate-events-2004-poster.jpg new file mode 100644 index 00000000..4c78fee9 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-lemony-snicket-s-a-series-of-unfortunate-events-2004-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-locke-2014-poster.jpg b/app/src/debug/assets/library/assets/movie-locke-2014-poster.jpg new file mode 100644 index 00000000..94ebe97d Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-locke-2014-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-look-who-s-back-2015-poster.jpg b/app/src/debug/assets/library/assets/movie-look-who-s-back-2015-poster.jpg new file mode 100644 index 00000000..423043cf Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-look-who-s-back-2015-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-memories-1995-poster.jpg b/app/src/debug/assets/library/assets/movie-memories-1995-poster.jpg new file mode 100644 index 00000000..f3725b42 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-memories-1995-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-mercy-2026-poster.jpg b/app/src/debug/assets/library/assets/movie-mercy-2026-poster.jpg new file mode 100644 index 00000000..cfc0d812 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-mercy-2026-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-night-is-short-walk-on-girl-2017-poster.jpg b/app/src/debug/assets/library/assets/movie-night-is-short-walk-on-girl-2017-poster.jpg new file mode 100644 index 00000000..c6fa6a26 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-night-is-short-walk-on-girl-2017-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-normal-2026-poster.jpg b/app/src/debug/assets/library/assets/movie-normal-2026-poster.jpg new file mode 100644 index 00000000..f4c89db7 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-normal-2026-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-outlaw-king-2018-poster.jpg b/app/src/debug/assets/library/assets/movie-outlaw-king-2018-poster.jpg new file mode 100644 index 00000000..d6760468 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-outlaw-king-2018-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-panic-room-2002-poster.jpg b/app/src/debug/assets/library/assets/movie-panic-room-2002-poster.jpg new file mode 100644 index 00000000..0b2a0d30 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-panic-room-2002-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-peaky-blinders-the-immortal-man-2026-poster.jpg b/app/src/debug/assets/library/assets/movie-peaky-blinders-the-immortal-man-2026-poster.jpg new file mode 100644 index 00000000..a4814472 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-peaky-blinders-the-immortal-man-2026-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-ponyo-2008-poster.jpg b/app/src/debug/assets/library/assets/movie-ponyo-2008-poster.jpg new file mode 100644 index 00000000..f548e831 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-ponyo-2008-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-porco-rosso-1992-poster.jpg b/app/src/debug/assets/library/assets/movie-porco-rosso-1992-poster.jpg new file mode 100644 index 00000000..4a6a2bd1 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-porco-rosso-1992-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-princess-mononoke-1997-poster.jpg b/app/src/debug/assets/library/assets/movie-princess-mononoke-1997-poster.jpg new file mode 100644 index 00000000..21dd9359 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-princess-mononoke-1997-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-prisoners-2013-poster.jpg b/app/src/debug/assets/library/assets/movie-prisoners-2013-poster.jpg new file mode 100644 index 00000000..411b149b Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-prisoners-2013-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-racing-stripes-2005-poster.jpg b/app/src/debug/assets/library/assets/movie-racing-stripes-2005-poster.jpg new file mode 100644 index 00000000..cc2ef2ce Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-racing-stripes-2005-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-reincarnated-2012-poster.jpg b/app/src/debug/assets/library/assets/movie-reincarnated-2012-poster.jpg new file mode 100644 index 00000000..e9ab449c Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-reincarnated-2012-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-requiem-for-a-dream-2000-poster.jpg b/app/src/debug/assets/library/assets/movie-requiem-for-a-dream-2000-poster.jpg new file mode 100644 index 00000000..6f89abc3 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-requiem-for-a-dream-2000-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-rogue-one-a-star-wars-story-2016-poster.jpg b/app/src/debug/assets/library/assets/movie-rogue-one-a-star-wars-story-2016-poster.jpg new file mode 100644 index 00000000..c79e70a1 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-rogue-one-a-star-wars-story-2016-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-secondhand-lions-2003-poster.jpg b/app/src/debug/assets/library/assets/movie-secondhand-lions-2003-poster.jpg new file mode 100644 index 00000000..33408fa0 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-secondhand-lions-2003-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-self-reliance-2024-poster.jpg b/app/src/debug/assets/library/assets/movie-self-reliance-2024-poster.jpg new file mode 100644 index 00000000..0f6017ed Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-self-reliance-2024-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-serpico-1973-poster.jpg b/app/src/debug/assets/library/assets/movie-serpico-1973-poster.jpg new file mode 100644 index 00000000..8ddd6e52 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-serpico-1973-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-shaft-2000-poster.jpg b/app/src/debug/assets/library/assets/movie-shaft-2000-poster.jpg new file mode 100644 index 00000000..6b2b79ce Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-shaft-2000-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-shipwrecked-nightmare-at-sea-2026-poster.jpg b/app/src/debug/assets/library/assets/movie-shipwrecked-nightmare-at-sea-2026-poster.jpg new file mode 100644 index 00000000..f200a28d Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-shipwrecked-nightmare-at-sea-2026-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-sinbad-legend-of-the-seven-seas-2003-poster.jpg b/app/src/debug/assets/library/assets/movie-sinbad-legend-of-the-seven-seas-2003-poster.jpg new file mode 100644 index 00000000..428bb38b Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-sinbad-legend-of-the-seven-seas-2003-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-sleeping-with-other-people-2015-poster.jpg b/app/src/debug/assets/library/assets/movie-sleeping-with-other-people-2015-poster.jpg new file mode 100644 index 00000000..a5ffff1f Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-sleeping-with-other-people-2015-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-snowpiercer-2013-poster.jpg b/app/src/debug/assets/library/assets/movie-snowpiercer-2013-poster.jpg new file mode 100644 index 00000000..be1873fd Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-snowpiercer-2013-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-spider-man-brand-new-day-2026-poster.jpg b/app/src/debug/assets/library/assets/movie-spider-man-brand-new-day-2026-poster.jpg new file mode 100644 index 00000000..51fa155f Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-spider-man-brand-new-day-2026-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-spider-man-far-from-home-2019-poster.jpg b/app/src/debug/assets/library/assets/movie-spider-man-far-from-home-2019-poster.jpg new file mode 100644 index 00000000..28521997 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-spider-man-far-from-home-2019-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-spider-man-homecoming-2017-poster.jpg b/app/src/debug/assets/library/assets/movie-spider-man-homecoming-2017-poster.jpg new file mode 100644 index 00000000..97fc9c05 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-spider-man-homecoming-2017-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-spider-man-no-way-home-2021-poster.jpg b/app/src/debug/assets/library/assets/movie-spider-man-no-way-home-2021-poster.jpg new file mode 100644 index 00000000..bc92a4cd Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-spider-man-no-way-home-2021-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-spirited-away-2001-poster.jpg b/app/src/debug/assets/library/assets/movie-spirited-away-2001-poster.jpg new file mode 100644 index 00000000..5a79da62 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-spirited-away-2001-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-steins-gate-the-movie-load-region-of-deja-vu-2013-poster.jpg b/app/src/debug/assets/library/assets/movie-steins-gate-the-movie-load-region-of-deja-vu-2013-poster.jpg new file mode 100644 index 00000000..e85ddb90 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-steins-gate-the-movie-load-region-of-deja-vu-2013-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-taxi-driver-1976-poster.jpg b/app/src/debug/assets/library/assets/movie-taxi-driver-1976-poster.jpg new file mode 100644 index 00000000..c410b981 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-taxi-driver-1976-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-the-alto-knights-2025-poster.jpg b/app/src/debug/assets/library/assets/movie-the-alto-knights-2025-poster.jpg new file mode 100644 index 00000000..bb009cbf Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-the-alto-knights-2025-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-the-amazing-spider-man-2-2014-poster.jpg b/app/src/debug/assets/library/assets/movie-the-amazing-spider-man-2-2014-poster.jpg new file mode 100644 index 00000000..4de2711f Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-the-amazing-spider-man-2-2014-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-the-amazing-spider-man-2012-poster.jpg b/app/src/debug/assets/library/assets/movie-the-amazing-spider-man-2012-poster.jpg new file mode 100644 index 00000000..c1aec876 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-the-amazing-spider-man-2012-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-the-animatrix-2003-poster.jpg b/app/src/debug/assets/library/assets/movie-the-animatrix-2003-poster.jpg new file mode 100644 index 00000000..65553d47 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-the-animatrix-2003-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-the-avengers-2012-poster.jpg b/app/src/debug/assets/library/assets/movie-the-avengers-2012-poster.jpg new file mode 100644 index 00000000..be87067c Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-the-avengers-2012-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-the-boy-and-the-heron-2023-poster.jpg b/app/src/debug/assets/library/assets/movie-the-boy-and-the-heron-2023-poster.jpg new file mode 100644 index 00000000..094df64e Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-the-boy-and-the-heron-2023-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-the-breakfast-club-1985-poster.jpg b/app/src/debug/assets/library/assets/movie-the-breakfast-club-1985-poster.jpg new file mode 100644 index 00000000..d1823120 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-the-breakfast-club-1985-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-the-dry-2021-poster.jpg b/app/src/debug/assets/library/assets/movie-the-dry-2021-poster.jpg new file mode 100644 index 00000000..a0379f2f Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-the-dry-2021-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-the-girl-who-leapt-through-time-2006-poster.jpg b/app/src/debug/assets/library/assets/movie-the-girl-who-leapt-through-time-2006-poster.jpg new file mode 100644 index 00000000..ded6cd2a Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-the-girl-who-leapt-through-time-2006-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-the-godfather-1972-poster.jpg b/app/src/debug/assets/library/assets/movie-the-godfather-1972-poster.jpg new file mode 100644 index 00000000..94111d9b Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-the-godfather-1972-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-the-godfather-part-ii-1974-poster.jpg b/app/src/debug/assets/library/assets/movie-the-godfather-part-ii-1974-poster.jpg new file mode 100644 index 00000000..1328c99e Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-the-godfather-part-ii-1974-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-the-godfather-part-iii-1990-poster.jpg b/app/src/debug/assets/library/assets/movie-the-godfather-part-iii-1990-poster.jpg new file mode 100644 index 00000000..abbe5e99 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-the-godfather-part-iii-1990-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-the-great-gatsby-2013-poster.jpg b/app/src/debug/assets/library/assets/movie-the-great-gatsby-2013-poster.jpg new file mode 100644 index 00000000..e949fb3e Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-the-great-gatsby-2013-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-the-hours-2002-poster.jpg b/app/src/debug/assets/library/assets/movie-the-hours-2002-poster.jpg new file mode 100644 index 00000000..f87e919f Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-the-hours-2002-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-the-killing-of-a-sacred-deer-2017-poster.jpg b/app/src/debug/assets/library/assets/movie-the-killing-of-a-sacred-deer-2017-poster.jpg new file mode 100644 index 00000000..83464d4c Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-the-killing-of-a-sacred-deer-2017-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-the-last-of-the-mohicans-1992-poster.jpg b/app/src/debug/assets/library/assets/movie-the-last-of-the-mohicans-1992-poster.jpg new file mode 100644 index 00000000..950e9ba1 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-the-last-of-the-mohicans-1992-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-the-last-samurai-2003-poster.jpg b/app/src/debug/assets/library/assets/movie-the-last-samurai-2003-poster.jpg new file mode 100644 index 00000000..0d58440c Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-the-last-samurai-2003-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-the-lighthouse-2019-poster.jpg b/app/src/debug/assets/library/assets/movie-the-lighthouse-2019-poster.jpg new file mode 100644 index 00000000..15f26533 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-the-lighthouse-2019-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-the-matrix-1999-poster.jpg b/app/src/debug/assets/library/assets/movie-the-matrix-1999-poster.jpg new file mode 100644 index 00000000..c292dce5 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-the-matrix-1999-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-the-matrix-reloaded-2003-poster.jpg b/app/src/debug/assets/library/assets/movie-the-matrix-reloaded-2003-poster.jpg new file mode 100644 index 00000000..ab11f50f Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-the-matrix-reloaded-2003-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-the-matrix-resurrections-2021-poster.jpg b/app/src/debug/assets/library/assets/movie-the-matrix-resurrections-2021-poster.jpg new file mode 100644 index 00000000..4477ef1e Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-the-matrix-resurrections-2021-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-the-matrix-revolutions-2003-poster.jpg b/app/src/debug/assets/library/assets/movie-the-matrix-revolutions-2003-poster.jpg new file mode 100644 index 00000000..7236cc4e Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-the-matrix-revolutions-2003-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-the-patriot-2000-poster.jpg b/app/src/debug/assets/library/assets/movie-the-patriot-2000-poster.jpg new file mode 100644 index 00000000..c8582133 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-the-patriot-2000-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-the-secret-life-of-pets-2-2019-poster.jpg b/app/src/debug/assets/library/assets/movie-the-secret-life-of-pets-2-2019-poster.jpg new file mode 100644 index 00000000..fe50c2f8 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-the-secret-life-of-pets-2-2019-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-the-substance-2024-poster.jpg b/app/src/debug/assets/library/assets/movie-the-substance-2024-poster.jpg new file mode 100644 index 00000000..72accfed Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-the-substance-2024-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-the-tale-of-the-princess-kaguya-2013-poster.jpg b/app/src/debug/assets/library/assets/movie-the-tale-of-the-princess-kaguya-2013-poster.jpg new file mode 100644 index 00000000..882621cb Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-the-tale-of-the-princess-kaguya-2013-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-the-uprising-2026-poster.jpg b/app/src/debug/assets/library/assets/movie-the-uprising-2026-poster.jpg new file mode 100644 index 00000000..21976395 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-the-uprising-2026-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-the-wild-robot-2024-poster.jpg b/app/src/debug/assets/library/assets/movie-the-wild-robot-2024-poster.jpg new file mode 100644 index 00000000..0894754d Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-the-wild-robot-2024-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-the-wind-rises-2013-poster.jpg b/app/src/debug/assets/library/assets/movie-the-wind-rises-2013-poster.jpg new file mode 100644 index 00000000..b7688c77 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-the-wind-rises-2013-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-the-witcher-nightmare-of-the-wolf-2021-poster.jpg b/app/src/debug/assets/library/assets/movie-the-witcher-nightmare-of-the-wolf-2021-poster.jpg new file mode 100644 index 00000000..6db33db1 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-the-witcher-nightmare-of-the-wolf-2021-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-the-witcher-sirens-of-the-deep-2025-poster.jpg b/app/src/debug/assets/library/assets/movie-the-witcher-sirens-of-the-deep-2025-poster.jpg new file mode 100644 index 00000000..8a54bc7f Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-the-witcher-sirens-of-the-deep-2025-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-thelma-louise-1991-poster.jpg b/app/src/debug/assets/library/assets/movie-thelma-louise-1991-poster.jpg new file mode 100644 index 00000000..5a4ff0ab Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-thelma-louise-1991-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-triangle-of-sadness-2022-poster.jpg b/app/src/debug/assets/library/assets/movie-triangle-of-sadness-2022-poster.jpg new file mode 100644 index 00000000..aee092c6 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-triangle-of-sadness-2022-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-tsotsi-2005-poster.jpg b/app/src/debug/assets/library/assets/movie-tsotsi-2005-poster.jpg new file mode 100644 index 00000000..362ddd82 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-tsotsi-2005-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-unknown-number-the-high-school-catfish-2025-poster.jpg b/app/src/debug/assets/library/assets/movie-unknown-number-the-high-school-catfish-2025-poster.jpg new file mode 100644 index 00000000..e32685f3 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-unknown-number-the-high-school-catfish-2025-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-vice-2018-poster.jpg b/app/src/debug/assets/library/assets/movie-vice-2018-poster.jpg new file mode 100644 index 00000000..76855126 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-vice-2018-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-vicky-cristina-barcelona-2008-poster.jpg b/app/src/debug/assets/library/assets/movie-vicky-cristina-barcelona-2008-poster.jpg new file mode 100644 index 00000000..1351cad1 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-vicky-cristina-barcelona-2008-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-warriors-of-the-wind-1984-poster.jpg b/app/src/debug/assets/library/assets/movie-warriors-of-the-wind-1984-poster.jpg new file mode 100644 index 00000000..918e424f Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-warriors-of-the-wind-1984-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-we-bury-the-dead-2026-poster.jpg b/app/src/debug/assets/library/assets/movie-we-bury-the-dead-2026-poster.jpg new file mode 100644 index 00000000..a0d65904 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-we-bury-the-dead-2026-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/movie-white-hot-the-rise-fall-of-abercrombie-fitch-2022-poster.jpg b/app/src/debug/assets/library/assets/movie-white-hot-the-rise-fall-of-abercrombie-fitch-2022-poster.jpg new file mode 100644 index 00000000..3a123e80 Binary files /dev/null and b/app/src/debug/assets/library/assets/movie-white-hot-the-rise-fall-of-abercrombie-fitch-2022-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-12-monkeys-2015-poster.jpg b/app/src/debug/assets/library/assets/tv-12-monkeys-2015-poster.jpg new file mode 100644 index 00000000..96e3596e Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-12-monkeys-2015-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-56-days-2026-poster.jpg b/app/src/debug/assets/library/assets/tv-56-days-2026-poster.jpg new file mode 100644 index 00000000..64ca587b Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-56-days-2026-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-90-day-fiance-before-the-90-days-2017-poster.jpg b/app/src/debug/assets/library/assets/tv-90-day-fiance-before-the-90-days-2017-poster.jpg new file mode 100644 index 00000000..3362da59 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-90-day-fiance-before-the-90-days-2017-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-90-day-fiance-the-other-way-2019-poster.jpg b/app/src/debug/assets/library/assets/tv-90-day-fiance-the-other-way-2019-poster.jpg new file mode 100644 index 00000000..b4d256eb Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-90-day-fiance-the-other-way-2019-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-a-knight-of-the-seven-kingdoms-2026-poster.jpg b/app/src/debug/assets/library/assets/tv-a-knight-of-the-seven-kingdoms-2026-poster.jpg new file mode 100644 index 00000000..79f1351c Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-a-knight-of-the-seven-kingdoms-2026-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-absolutely-fabulous-1992-poster.jpg b/app/src/debug/assets/library/assets/tv-absolutely-fabulous-1992-poster.jpg new file mode 100644 index 00000000..afd371a9 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-absolutely-fabulous-1992-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-accel-world-2012-poster.jpg b/app/src/debug/assets/library/assets/tv-accel-world-2012-poster.jpg new file mode 100644 index 00000000..207b1dd1 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-accel-world-2012-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-accused-2023-poster.jpg b/app/src/debug/assets/library/assets/tv-accused-2023-poster.jpg new file mode 100644 index 00000000..74af010a Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-accused-2023-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-adults-2025-poster.jpg b/app/src/debug/assets/library/assets/tv-adults-2025-poster.jpg new file mode 100644 index 00000000..53a7ba33 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-adults-2025-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-after-life-2019-poster.jpg b/app/src/debug/assets/library/assets/tv-after-life-2019-poster.jpg new file mode 100644 index 00000000..4fae4e33 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-after-life-2019-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-agatha-christie-s-marple-2004-poster.jpg b/app/src/debug/assets/library/assets/tv-agatha-christie-s-marple-2004-poster.jpg new file mode 100644 index 00000000..ea7dda99 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-agatha-christie-s-marple-2004-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-ahsoka-2023-poster.jpg b/app/src/debug/assets/library/assets/tv-ahsoka-2023-poster.jpg new file mode 100644 index 00000000..a29d6cb4 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-ahsoka-2023-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-all-american-homecoming-2022-poster.jpg b/app/src/debug/assets/library/assets/tv-all-american-homecoming-2022-poster.jpg new file mode 100644 index 00000000..09ccfc33 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-all-american-homecoming-2022-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-all-creatures-great-and-small-1978-poster.jpg b/app/src/debug/assets/library/assets/tv-all-creatures-great-and-small-1978-poster.jpg new file mode 100644 index 00000000..5b1666e6 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-all-creatures-great-and-small-1978-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-all-creatures-great-small-2020-poster.jpg b/app/src/debug/assets/library/assets/tv-all-creatures-great-small-2020-poster.jpg new file mode 100644 index 00000000..b506f990 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-all-creatures-great-small-2020-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-american-crime-story-2016-poster.jpg b/app/src/debug/assets/library/assets/tv-american-crime-story-2016-poster.jpg new file mode 100644 index 00000000..4086bf17 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-american-crime-story-2016-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-american-dad-2005-poster.jpg b/app/src/debug/assets/library/assets/tv-american-dad-2005-poster.jpg new file mode 100644 index 00000000..1f9e239a Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-american-dad-2005-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-american-gods-2017-poster.jpg b/app/src/debug/assets/library/assets/tv-american-gods-2017-poster.jpg new file mode 100644 index 00000000..c02c46da Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-american-gods-2017-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-american-housewife-2016-poster.jpg b/app/src/debug/assets/library/assets/tv-american-housewife-2016-poster.jpg new file mode 100644 index 00000000..5f92bf05 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-american-housewife-2016-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-american-primeval-2025-poster.jpg b/app/src/debug/assets/library/assets/tv-american-primeval-2025-poster.jpg new file mode 100644 index 00000000..7f10e6aa Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-american-primeval-2025-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-and-just-like-that-2021-poster.jpg b/app/src/debug/assets/library/assets/tv-and-just-like-that-2021-poster.jpg new file mode 100644 index 00000000..9904c74b Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-and-just-like-that-2021-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-andor-2022-poster.jpg b/app/src/debug/assets/library/assets/tv-andor-2022-poster.jpg new file mode 100644 index 00000000..df5dc498 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-andor-2022-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-andromeda-2000-poster.jpg b/app/src/debug/assets/library/assets/tv-andromeda-2000-poster.jpg new file mode 100644 index 00000000..67b766b0 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-andromeda-2000-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-anne-with-an-e-2017-poster.jpg b/app/src/debug/assets/library/assets/tv-anne-with-an-e-2017-poster.jpg new file mode 100644 index 00000000..55d443b4 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-anne-with-an-e-2017-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-aqua-teen-hunger-force-2000-poster.jpg b/app/src/debug/assets/library/assets/tv-aqua-teen-hunger-force-2000-poster.jpg new file mode 100644 index 00000000..e0c97321 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-aqua-teen-hunger-force-2000-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-arifureta-from-commonplace-to-world-s-strongest-2019-poster.jpg b/app/src/debug/assets/library/assets/tv-arifureta-from-commonplace-to-world-s-strongest-2019-poster.jpg new file mode 100644 index 00000000..6a8f9a24 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-arifureta-from-commonplace-to-world-s-strongest-2019-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-arrested-development-2003-poster.jpg b/app/src/debug/assets/library/assets/tv-arrested-development-2003-poster.jpg new file mode 100644 index 00000000..02b0dd43 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-arrested-development-2003-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-arrow-2012-poster.jpg b/app/src/debug/assets/library/assets/tv-arrow-2012-poster.jpg new file mode 100644 index 00000000..adee3bb7 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-arrow-2012-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-atlantis-2013-poster.jpg b/app/src/debug/assets/library/assets/tv-atlantis-2013-poster.jpg new file mode 100644 index 00000000..5cd5f098 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-atlantis-2013-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-avatar-seven-havens-2026-poster.jpg b/app/src/debug/assets/library/assets/tv-avatar-seven-havens-2026-poster.jpg new file mode 100644 index 00000000..61f459c6 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-avatar-seven-havens-2026-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-avatar-the-last-airbender-2005-poster.jpg b/app/src/debug/assets/library/assets/tv-avatar-the-last-airbender-2005-poster.jpg new file mode 100644 index 00000000..6f99263a Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-avatar-the-last-airbender-2005-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-avatar-the-last-airbender-2024-poster.jpg b/app/src/debug/assets/library/assets/tv-avatar-the-last-airbender-2024-poster.jpg new file mode 100644 index 00000000..9d46c2ff Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-avatar-the-last-airbender-2024-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-awkward-2011-poster.jpg b/app/src/debug/assets/library/assets/tv-awkward-2011-poster.jpg new file mode 100644 index 00000000..8da6e8e2 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-awkward-2011-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-b-b-vol-liefde-2021-poster.jpg b/app/src/debug/assets/library/assets/tv-b-b-vol-liefde-2021-poster.jpg new file mode 100644 index 00000000..a12ac33e Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-b-b-vol-liefde-2021-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-back-to-life-2019-poster.jpg b/app/src/debug/assets/library/assets/tv-back-to-life-2019-poster.jpg new file mode 100644 index 00000000..b00730a8 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-back-to-life-2019-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-ballers-2015-poster.jpg b/app/src/debug/assets/library/assets/tv-ballers-2015-poster.jpg new file mode 100644 index 00000000..f1c18f69 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-ballers-2015-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-baretta-1975-poster.jpg b/app/src/debug/assets/library/assets/tv-baretta-1975-poster.jpg new file mode 100644 index 00000000..ceef0c9d Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-baretta-1975-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-based-on-a-true-story-2023-poster.jpg b/app/src/debug/assets/library/assets/tv-based-on-a-true-story-2023-poster.jpg new file mode 100644 index 00000000..386d3d90 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-based-on-a-true-story-2023-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-batman-the-brave-and-the-bold-2008-poster.jpg b/app/src/debug/assets/library/assets/tv-batman-the-brave-and-the-bold-2008-poster.jpg new file mode 100644 index 00000000..a864f50c Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-batman-the-brave-and-the-bold-2008-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-batwoman-2019-poster.jpg b/app/src/debug/assets/library/assets/tv-batwoman-2019-poster.jpg new file mode 100644 index 00000000..7ca86592 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-batwoman-2019-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-beat-bobby-flay-2013-poster.jpg b/app/src/debug/assets/library/assets/tv-beat-bobby-flay-2013-poster.jpg new file mode 100644 index 00000000..fe11122d Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-beat-bobby-flay-2013-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-benson-1979-poster.jpg b/app/src/debug/assets/library/assets/tv-benson-1979-poster.jpg new file mode 100644 index 00000000..fe264c76 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-benson-1979-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-big-boys-2022-poster.jpg b/app/src/debug/assets/library/assets/tv-big-boys-2022-poster.jpg new file mode 100644 index 00000000..93e1e86a Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-big-boys-2022-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-big-city-greens-2018-poster.jpg b/app/src/debug/assets/library/assets/tv-big-city-greens-2018-poster.jpg new file mode 100644 index 00000000..ef024946 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-big-city-greens-2018-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-big-mouth-2017-poster.jpg b/app/src/debug/assets/library/assets/tv-big-mouth-2017-poster.jpg new file mode 100644 index 00000000..4f535fec Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-big-mouth-2017-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-black-ish-2014-poster.jpg b/app/src/debug/assets/library/assets/tv-black-ish-2014-poster.jpg new file mode 100644 index 00000000..97c885ad Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-black-ish-2014-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-black-lightning-2018-poster.jpg b/app/src/debug/assets/library/assets/tv-black-lightning-2018-poster.jpg new file mode 100644 index 00000000..733f5cbc Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-black-lightning-2018-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-black-rabbit-2025-poster.jpg b/app/src/debug/assets/library/assets/tv-black-rabbit-2025-poster.jpg new file mode 100644 index 00000000..3ff9aeed Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-black-rabbit-2025-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-bleach-2004-poster.jpg b/app/src/debug/assets/library/assets/tv-bleach-2004-poster.jpg new file mode 100644 index 00000000..b233e033 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-bleach-2004-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-blue-planet-ii-2017-poster.jpg b/app/src/debug/assets/library/assets/tv-blue-planet-ii-2017-poster.jpg new file mode 100644 index 00000000..5e193ab2 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-blue-planet-ii-2017-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-brassic-2019-poster.jpg b/app/src/debug/assets/library/assets/tv-brassic-2019-poster.jpg new file mode 100644 index 00000000..73b77df2 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-brassic-2019-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-breaking-bad-2008-poster.jpg b/app/src/debug/assets/library/assets/tv-breaking-bad-2008-poster.jpg new file mode 100644 index 00000000..c4f7217c Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-breaking-bad-2008-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-breeders-2020-poster.jpg b/app/src/debug/assets/library/assets/tv-breeders-2020-poster.jpg new file mode 100644 index 00000000..49c61208 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-breeders-2020-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-californication-2007-poster.jpg b/app/src/debug/assets/library/assets/tv-californication-2007-poster.jpg new file mode 100644 index 00000000..38428e76 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-californication-2007-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-call-the-midwife-2012-poster.jpg b/app/src/debug/assets/library/assets/tv-call-the-midwife-2012-poster.jpg new file mode 100644 index 00000000..466a1a7b Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-call-the-midwife-2012-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-chainsaw-man-2022-poster.jpg b/app/src/debug/assets/library/assets/tv-chainsaw-man-2022-poster.jpg new file mode 100644 index 00000000..a3779772 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-chainsaw-man-2022-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-chernobyl-2019-poster.jpg b/app/src/debug/assets/library/assets/tv-chernobyl-2019-poster.jpg new file mode 100644 index 00000000..7664f4b0 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-chernobyl-2019-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-community-2009-poster.jpg b/app/src/debug/assets/library/assets/tv-community-2009-poster.jpg new file mode 100644 index 00000000..e75072ae Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-community-2009-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-cyberpunk-edgerunners-2022-poster.jpg b/app/src/debug/assets/library/assets/tv-cyberpunk-edgerunners-2022-poster.jpg new file mode 100644 index 00000000..8d338532 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-cyberpunk-edgerunners-2022-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-dan-da-dan-2024-poster.jpg b/app/src/debug/assets/library/assets/tv-dan-da-dan-2024-poster.jpg new file mode 100644 index 00000000..f42cec16 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-dan-da-dan-2024-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-dead-end-job-2026-poster.jpg b/app/src/debug/assets/library/assets/tv-dead-end-job-2026-poster.jpg new file mode 100644 index 00000000..f5546d88 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-dead-end-job-2026-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-derry-girls-2018-poster.jpg b/app/src/debug/assets/library/assets/tv-derry-girls-2018-poster.jpg new file mode 100644 index 00000000..56a8cd79 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-derry-girls-2018-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-desperate-housewives-2004-poster.jpg b/app/src/debug/assets/library/assets/tv-desperate-housewives-2004-poster.jpg new file mode 100644 index 00000000..0c4c38bc Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-desperate-housewives-2004-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-dopesick-2021-poster.jpg b/app/src/debug/assets/library/assets/tv-dopesick-2021-poster.jpg new file mode 100644 index 00000000..ac0b5900 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-dopesick-2021-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-dr-stone-2019-poster.jpg b/app/src/debug/assets/library/assets/tv-dr-stone-2019-poster.jpg new file mode 100644 index 00000000..0783ed8c Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-dr-stone-2019-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-dune-prophecy-2024-poster.jpg b/app/src/debug/assets/library/assets/tv-dune-prophecy-2024-poster.jpg new file mode 100644 index 00000000..eef2a4f3 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-dune-prophecy-2024-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-east-of-eden-2026-poster.jpg b/app/src/debug/assets/library/assets/tv-east-of-eden-2026-poster.jpg new file mode 100644 index 00000000..6f06f2c9 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-east-of-eden-2026-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-etoile-2025-poster.jpg b/app/src/debug/assets/library/assets/tv-etoile-2025-poster.jpg new file mode 100644 index 00000000..f078bc89 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-etoile-2025-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-fallout-2024-poster.jpg b/app/src/debug/assets/library/assets/tv-fallout-2024-poster.jpg new file mode 100644 index 00000000..5e87a07d Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-fallout-2024-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-fawlty-towers-1975-poster.jpg b/app/src/debug/assets/library/assets/tv-fawlty-towers-1975-poster.jpg new file mode 100644 index 00000000..53b406da Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-fawlty-towers-1975-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-firefly-2002-poster.jpg b/app/src/debug/assets/library/assets/tv-firefly-2002-poster.jpg new file mode 100644 index 00000000..9ad599b3 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-firefly-2002-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-fleabag-2016-poster.jpg b/app/src/debug/assets/library/assets/tv-fleabag-2016-poster.jpg new file mode 100644 index 00000000..bd3ccea5 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-fleabag-2016-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-frieren-beyond-journey-s-end-2023-poster.jpg b/app/src/debug/assets/library/assets/tv-frieren-beyond-journey-s-end-2023-poster.jpg new file mode 100644 index 00000000..cb94104e Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-frieren-beyond-journey-s-end-2023-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-fullmetal-alchemist-brotherhood-2009-poster.jpg b/app/src/debug/assets/library/assets/tv-fullmetal-alchemist-brotherhood-2009-poster.jpg new file mode 100644 index 00000000..935e4944 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-fullmetal-alchemist-brotherhood-2009-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-gilmore-girls-2000-poster.jpg b/app/src/debug/assets/library/assets/tv-gilmore-girls-2000-poster.jpg new file mode 100644 index 00000000..23b668cb Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-gilmore-girls-2000-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-ginny-georgia-2021-poster.jpg b/app/src/debug/assets/library/assets/tv-ginny-georgia-2021-poster.jpg new file mode 100644 index 00000000..1fca7bf6 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-ginny-georgia-2021-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-gravity-falls-2012-poster.jpg b/app/src/debug/assets/library/assets/tv-gravity-falls-2012-poster.jpg new file mode 100644 index 00000000..41c051e0 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-gravity-falls-2012-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-hellcats-2010-poster.jpg b/app/src/debug/assets/library/assets/tv-hellcats-2010-poster.jpg new file mode 100644 index 00000000..2427108b Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-hellcats-2010-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-high-potential-2024-poster.jpg b/app/src/debug/assets/library/assets/tv-high-potential-2024-poster.jpg new file mode 100644 index 00000000..00a07ca7 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-high-potential-2024-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-how-to-change-your-mind-2022-poster.jpg b/app/src/debug/assets/library/assets/tv-how-to-change-your-mind-2022-poster.jpg new file mode 100644 index 00000000..e80c7999 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-how-to-change-your-mind-2022-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-how-to-get-to-heaven-from-belfast-2026-poster.jpg b/app/src/debug/assets/library/assets/tv-how-to-get-to-heaven-from-belfast-2026-poster.jpg new file mode 100644 index 00000000..eb5fc487 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-how-to-get-to-heaven-from-belfast-2026-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-interrogation-2020-poster.jpg b/app/src/debug/assets/library/assets/tv-interrogation-2020-poster.jpg new file mode 100644 index 00000000..f3a21b66 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-interrogation-2020-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-invincible-2021-poster.jpg b/app/src/debug/assets/library/assets/tv-invincible-2021-poster.jpg new file mode 100644 index 00000000..c278e37e Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-invincible-2021-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-it-s-always-sunny-in-philadelphia-2005-poster.jpg b/app/src/debug/assets/library/assets/tv-it-s-always-sunny-in-philadelphia-2005-poster.jpg new file mode 100644 index 00000000..652923ee Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-it-s-always-sunny-in-philadelphia-2005-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-jujutsu-kaisen-2020-poster.jpg b/app/src/debug/assets/library/assets/tv-jujutsu-kaisen-2020-poster.jpg new file mode 100644 index 00000000..45f5ff22 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-jujutsu-kaisen-2020-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-kaiju-no-8-2024-poster.jpg b/app/src/debug/assets/library/assets/tv-kaiju-no-8-2024-poster.jpg new file mode 100644 index 00000000..062496fa Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-kaiju-no-8-2024-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-landman-2024-poster.jpg b/app/src/debug/assets/library/assets/tv-landman-2024-poster.jpg new file mode 100644 index 00000000..3d348798 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-landman-2024-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-last-samurai-standing-2025-poster.jpg b/app/src/debug/assets/library/assets/tv-last-samurai-standing-2025-poster.jpg new file mode 100644 index 00000000..a9789909 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-last-samurai-standing-2025-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-lord-of-the-flies-2026-poster.jpg b/app/src/debug/assets/library/assets/tv-lord-of-the-flies-2026-poster.jpg new file mode 100644 index 00000000..b1229ed8 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-lord-of-the-flies-2026-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-love-death-robots-2019-poster.jpg b/app/src/debug/assets/library/assets/tv-love-death-robots-2019-poster.jpg new file mode 100644 index 00000000..08449aa9 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-love-death-robots-2019-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-love-is-blind-2020-poster.jpg b/app/src/debug/assets/library/assets/tv-love-is-blind-2020-poster.jpg new file mode 100644 index 00000000..62ccf357 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-love-is-blind-2020-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-maniac-2018-poster.jpg b/app/src/debug/assets/library/assets/tv-maniac-2018-poster.jpg new file mode 100644 index 00000000..a1985217 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-maniac-2018-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-maximum-pleasure-guaranteed-2026-poster.jpg b/app/src/debug/assets/library/assets/tv-maximum-pleasure-guaranteed-2026-poster.jpg new file mode 100644 index 00000000..abe1b2e2 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-maximum-pleasure-guaranteed-2026-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-minx-2022-poster.jpg b/app/src/debug/assets/library/assets/tv-minx-2022-poster.jpg new file mode 100644 index 00000000..a8797fe5 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-minx-2022-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-mussolini-son-of-the-century-2024-poster.jpg b/app/src/debug/assets/library/assets/tv-mussolini-son-of-the-century-2024-poster.jpg new file mode 100644 index 00000000..925d5c49 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-mussolini-son-of-the-century-2024-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-my-hero-academia-2016-poster.jpg b/app/src/debug/assets/library/assets/tv-my-hero-academia-2016-poster.jpg new file mode 100644 index 00000000..cf571b93 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-my-hero-academia-2016-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-neon-genesis-evangelion-1995-poster.jpg b/app/src/debug/assets/library/assets/tv-neon-genesis-evangelion-1995-poster.jpg new file mode 100644 index 00000000..f86cd698 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-neon-genesis-evangelion-1995-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-norsemen-2016-poster.jpg b/app/src/debug/assets/library/assets/tv-norsemen-2016-poster.jpg new file mode 100644 index 00000000..e7206b88 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-norsemen-2016-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-offspring-2010-poster.jpg b/app/src/debug/assets/library/assets/tv-offspring-2010-poster.jpg new file mode 100644 index 00000000..ae305043 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-offspring-2010-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-one-piece-2023-poster.jpg b/app/src/debug/assets/library/assets/tv-one-piece-2023-poster.jpg new file mode 100644 index 00000000..286e6260 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-one-piece-2023-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-only-murders-in-the-building-2021-poster.jpg b/app/src/debug/assets/library/assets/tv-only-murders-in-the-building-2021-poster.jpg new file mode 100644 index 00000000..a6b147a4 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-only-murders-in-the-building-2021-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-outlander-blood-of-my-blood-2025-poster.jpg b/app/src/debug/assets/library/assets/tv-outlander-blood-of-my-blood-2025-poster.jpg new file mode 100644 index 00000000..930943b0 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-outlander-blood-of-my-blood-2025-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-over-the-garden-wall-2014-poster.jpg b/app/src/debug/assets/library/assets/tv-over-the-garden-wall-2014-poster.jpg new file mode 100644 index 00000000..34b1ed84 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-over-the-garden-wall-2014-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-peaky-blinders-2013-poster.jpg b/app/src/debug/assets/library/assets/tv-peaky-blinders-2013-poster.jpg new file mode 100644 index 00000000..25ceea88 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-peaky-blinders-2013-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-pluribus-2025-poster.jpg b/app/src/debug/assets/library/assets/tv-pluribus-2025-poster.jpg new file mode 100644 index 00000000..1ea4711b Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-pluribus-2025-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-record-of-ragnarok-2021-poster.jpg b/app/src/debug/assets/library/assets/tv-record-of-ragnarok-2021-poster.jpg new file mode 100644 index 00000000..97d481d6 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-record-of-ragnarok-2021-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-rick-and-morty-2013-poster.jpg b/app/src/debug/assets/library/assets/tv-rick-and-morty-2013-poster.jpg new file mode 100644 index 00000000..b95c4890 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-rick-and-morty-2013-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-ripley-2024-poster.jpg b/app/src/debug/assets/library/assets/tv-ripley-2024-poster.jpg new file mode 100644 index 00000000..de0b32dd Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-ripley-2024-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-rivals-2024-poster.jpg b/app/src/debug/assets/library/assets/tv-rivals-2024-poster.jpg new file mode 100644 index 00000000..296ac67a Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-rivals-2024-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-rooster-2026-poster.jpg b/app/src/debug/assets/library/assets/tv-rooster-2026-poster.jpg new file mode 100644 index 00000000..b698f8a6 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-rooster-2026-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-sakamoto-days-2025-poster.jpg b/app/src/debug/assets/library/assets/tv-sakamoto-days-2025-poster.jpg new file mode 100644 index 00000000..ed9358b3 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-sakamoto-days-2025-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-say-nothing-2024-poster.jpg b/app/src/debug/assets/library/assets/tv-say-nothing-2024-poster.jpg new file mode 100644 index 00000000..cf50fc09 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-say-nothing-2024-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-secret-level-2024-poster.jpg b/app/src/debug/assets/library/assets/tv-secret-level-2024-poster.jpg new file mode 100644 index 00000000..1b6e67f6 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-secret-level-2024-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-sentenced-to-be-a-hero-2025-poster.jpg b/app/src/debug/assets/library/assets/tv-sentenced-to-be-a-hero-2025-poster.jpg new file mode 100644 index 00000000..2fb1c815 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-sentenced-to-be-a-hero-2025-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-severance-2022-poster.jpg b/app/src/debug/assets/library/assets/tv-severance-2022-poster.jpg new file mode 100644 index 00000000..5a29d6f9 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-severance-2022-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-sex-and-the-city-1998-poster.jpg b/app/src/debug/assets/library/assets/tv-sex-and-the-city-1998-poster.jpg new file mode 100644 index 00000000..e546cc6d Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-sex-and-the-city-1998-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-silo-2023-poster.jpg b/app/src/debug/assets/library/assets/tv-silo-2023-poster.jpg new file mode 100644 index 00000000..b493bc7b Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-silo-2023-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-six-feet-under-2001-poster.jpg b/app/src/debug/assets/library/assets/tv-six-feet-under-2001-poster.jpg new file mode 100644 index 00000000..559d6bd1 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-six-feet-under-2001-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-skymed-2022-poster.jpg b/app/src/debug/assets/library/assets/tv-skymed-2022-poster.jpg new file mode 100644 index 00000000..2540dad7 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-skymed-2022-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-so-you-think-you-can-dance-2008-poster.jpg b/app/src/debug/assets/library/assets/tv-so-you-think-you-can-dance-2008-poster.jpg new file mode 100644 index 00000000..a2e91496 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-so-you-think-you-can-dance-2008-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-south-park-1997-poster.jpg b/app/src/debug/assets/library/assets/tv-south-park-1997-poster.jpg new file mode 100644 index 00000000..d8568d54 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-south-park-1997-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-spy-x-family-2022-poster.jpg b/app/src/debug/assets/library/assets/tv-spy-x-family-2022-poster.jpg new file mode 100644 index 00000000..fc326930 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-spy-x-family-2022-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-the-100-2014-poster.jpg b/app/src/debug/assets/library/assets/tv-the-100-2014-poster.jpg new file mode 100644 index 00000000..4d254cb0 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-the-100-2014-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-the-abbott-and-costello-show-1952-poster.jpg b/app/src/debug/assets/library/assets/tv-the-abbott-and-costello-show-1952-poster.jpg new file mode 100644 index 00000000..7d6768ea Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-the-abbott-and-costello-show-1952-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-the-afterparty-2022-poster.jpg b/app/src/debug/assets/library/assets/tv-the-afterparty-2022-poster.jpg new file mode 100644 index 00000000..9beacde2 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-the-afterparty-2022-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-the-baby-sitters-club-2020-poster.jpg b/app/src/debug/assets/library/assets/tv-the-baby-sitters-club-2020-poster.jpg new file mode 100644 index 00000000..7e4e7be2 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-the-baby-sitters-club-2020-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-the-bear-2022-poster.jpg b/app/src/debug/assets/library/assets/tv-the-bear-2022-poster.jpg new file mode 100644 index 00000000..bbf0ab28 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-the-bear-2022-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-the-beast-in-me-2025-poster.jpg b/app/src/debug/assets/library/assets/tv-the-beast-in-me-2025-poster.jpg new file mode 100644 index 00000000..c78c5cf0 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-the-beast-in-me-2025-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-the-bold-type-2017-poster.jpg b/app/src/debug/assets/library/assets/tv-the-bold-type-2017-poster.jpg new file mode 100644 index 00000000..f663eb8b Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-the-bold-type-2017-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-the-boys-2019-poster.jpg b/app/src/debug/assets/library/assets/tv-the-boys-2019-poster.jpg new file mode 100644 index 00000000..f67ff16f Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-the-boys-2019-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-the-capture-2019-poster.jpg b/app/src/debug/assets/library/assets/tv-the-capture-2019-poster.jpg new file mode 100644 index 00000000..a4039011 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-the-capture-2019-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-the-diplomat-2023-poster.jpg b/app/src/debug/assets/library/assets/tv-the-diplomat-2023-poster.jpg new file mode 100644 index 00000000..2eb48b62 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-the-diplomat-2023-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-the-durrells-2016-poster.jpg b/app/src/debug/assets/library/assets/tv-the-durrells-2016-poster.jpg new file mode 100644 index 00000000..d29448bb Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-the-durrells-2016-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-the-final-problem-2026-poster.jpg b/app/src/debug/assets/library/assets/tv-the-final-problem-2026-poster.jpg new file mode 100644 index 00000000..f0332826 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-the-final-problem-2026-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-the-four-seasons-2025-poster.jpg b/app/src/debug/assets/library/assets/tv-the-four-seasons-2025-poster.jpg new file mode 100644 index 00000000..fd252088 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-the-four-seasons-2025-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-the-get-down-2016-poster.jpg b/app/src/debug/assets/library/assets/tv-the-get-down-2016-poster.jpg new file mode 100644 index 00000000..7bb38abd Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-the-get-down-2016-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-the-hunting-wives-2025-poster.jpg b/app/src/debug/assets/library/assets/tv-the-hunting-wives-2025-poster.jpg new file mode 100644 index 00000000..034273eb Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-the-hunting-wives-2025-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-the-last-of-us-2023-poster.jpg b/app/src/debug/assets/library/assets/tv-the-last-of-us-2023-poster.jpg new file mode 100644 index 00000000..7da462da Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-the-last-of-us-2023-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-the-legend-of-korra-2012-poster.jpg b/app/src/debug/assets/library/assets/tv-the-legend-of-korra-2012-poster.jpg new file mode 100644 index 00000000..a7086d5e Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-the-legend-of-korra-2012-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-the-lord-of-the-rings-the-rings-of-power-2022-poster.jpg b/app/src/debug/assets/library/assets/tv-the-lord-of-the-rings-the-rings-of-power-2022-poster.jpg new file mode 100644 index 00000000..dc387fcd Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-the-lord-of-the-rings-the-rings-of-power-2022-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-the-lost-flowers-of-alice-hart-2023-poster.jpg b/app/src/debug/assets/library/assets/tv-the-lost-flowers-of-alice-hart-2023-poster.jpg new file mode 100644 index 00000000..71407f36 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-the-lost-flowers-of-alice-hart-2023-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-the-night-manager-2016-poster.jpg b/app/src/debug/assets/library/assets/tv-the-night-manager-2016-poster.jpg new file mode 100644 index 00000000..7ab2dbf5 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-the-night-manager-2016-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-the-pitt-2025-poster.jpg b/app/src/debug/assets/library/assets/tv-the-pitt-2025-poster.jpg new file mode 100644 index 00000000..ad1ec8ff Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-the-pitt-2025-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-the-tatami-galaxy-2010-poster.jpg b/app/src/debug/assets/library/assets/tv-the-tatami-galaxy-2010-poster.jpg new file mode 100644 index 00000000..5324dc75 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-the-tatami-galaxy-2010-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-the-walk-in-2022-poster.jpg b/app/src/debug/assets/library/assets/tv-the-walk-in-2022-poster.jpg new file mode 100644 index 00000000..715d0c80 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-the-walk-in-2022-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-the-white-lotus-2021-poster.jpg b/app/src/debug/assets/library/assets/tv-the-white-lotus-2021-poster.jpg new file mode 100644 index 00000000..2f23d1fa Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-the-white-lotus-2021-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-the-witcher-2019-poster.jpg b/app/src/debug/assets/library/assets/tv-the-witcher-2019-poster.jpg new file mode 100644 index 00000000..f5eb8f59 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-the-witcher-2019-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-undercover-2019-poster.jpg b/app/src/debug/assets/library/assets/tv-undercover-2019-poster.jpg new file mode 100644 index 00000000..8611eab4 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-undercover-2019-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-upload-2020-poster.jpg b/app/src/debug/assets/library/assets/tv-upload-2020-poster.jpg new file mode 100644 index 00000000..547d3b7a Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-upload-2020-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-vinland-saga-2019-poster.jpg b/app/src/debug/assets/library/assets/tv-vinland-saga-2019-poster.jpg new file mode 100644 index 00000000..7d0ba17a Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-vinland-saga-2019-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-widow-s-bay-2026-poster.jpg b/app/src/debug/assets/library/assets/tv-widow-s-bay-2026-poster.jpg new file mode 100644 index 00000000..8c02a0d7 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-widow-s-bay-2026-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-yellowjackets-2021-poster.jpg b/app/src/debug/assets/library/assets/tv-yellowjackets-2021-poster.jpg new file mode 100644 index 00000000..c7e16a57 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-yellowjackets-2021-poster.jpg differ diff --git a/app/src/debug/assets/library/assets/tv-yu-yu-hakusho-1992-poster.jpg b/app/src/debug/assets/library/assets/tv-yu-yu-hakusho-1992-poster.jpg new file mode 100644 index 00000000..f5843766 Binary files /dev/null and b/app/src/debug/assets/library/assets/tv-yu-yu-hakusho-1992-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/episode-all-hands-on-deck-class-1-a-2021-s5e1-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/episode-all-hands-on-deck-class-1-a-2021-s5e1-backdrop.jpg new file mode 100644 index 00000000..f5b2f94c Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/episode-all-hands-on-deck-class-1-a-2021-s5e1-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/episode-all-hands-on-deck-class-1-a-2021-s5e1-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/episode-all-hands-on-deck-class-1-a-2021-s5e1-poster.jpg new file mode 100644 index 00000000..cf571b93 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/episode-all-hands-on-deck-class-1-a-2021-s5e1-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/episode-announcement-2022-s1e7-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/episode-announcement-2022-s1e7-backdrop.jpg new file mode 100644 index 00000000..a874a0c0 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/episode-announcement-2022-s1e7-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/episode-announcement-2022-s1e7-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/episode-announcement-2022-s1e7-poster.jpg new file mode 100644 index 00000000..df5dc498 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/episode-announcement-2022-s1e7-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/episode-episode-1-2025-s1e1-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/episode-episode-1-2025-s1e1-backdrop.jpg new file mode 100644 index 00000000..f2519b04 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/episode-episode-1-2025-s1e1-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/episode-episode-1-2025-s1e1-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/episode-episode-1-2025-s1e1-poster.jpg new file mode 100644 index 00000000..77febd79 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/episode-episode-1-2025-s1e1-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/episode-episode-2-2016-s1e2-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/episode-episode-2-2016-s1e2-backdrop.jpg new file mode 100644 index 00000000..3f8bdeec Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/episode-episode-2-2016-s1e2-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/episode-episode-2-2016-s1e2-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/episode-episode-2-2016-s1e2-poster.jpg new file mode 100644 index 00000000..d29448bb Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/episode-episode-2-2016-s1e2-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/episode-erickerhead-2026-s9e6-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/episode-erickerhead-2026-s9e6-backdrop.jpg new file mode 100644 index 00000000..1c4c0ffc Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/episode-erickerhead-2026-s9e6-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/episode-erickerhead-2026-s9e6-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/episode-erickerhead-2026-s9e6-poster.jpg new file mode 100644 index 00000000..b95c4890 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/episode-erickerhead-2026-s9e6-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/episode-girls-interrupted-2007-s1e7-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/episode-girls-interrupted-2007-s1e7-backdrop.jpg new file mode 100644 index 00000000..ffff979b Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/episode-girls-interrupted-2007-s1e7-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/episode-girls-interrupted-2007-s1e7-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/episode-girls-interrupted-2007-s1e7-poster.jpg new file mode 100644 index 00000000..38428e76 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/episode-girls-interrupted-2007-s1e7-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/episode-i-heart-ny-2002-s4e18-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/episode-i-heart-ny-2002-s4e18-backdrop.jpg new file mode 100644 index 00000000..57beacc1 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/episode-i-heart-ny-2002-s4e18-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/episode-i-heart-ny-2002-s4e18-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/episode-i-heart-ny-2002-s4e18-poster.jpg new file mode 100644 index 00000000..e546cc6d Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/episode-i-heart-ny-2002-s4e18-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/episode-new-day-2021-s1e2-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/episode-new-day-2021-s1e2-backdrop.jpg new file mode 100644 index 00000000..1f747323 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/episode-new-day-2021-s1e2-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/episode-new-day-2021-s1e2-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/episode-new-day-2021-s1e2-poster.jpg new file mode 100644 index 00000000..2f23d1fa Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/episode-new-day-2021-s1e2-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/episode-no-honeymoon-2020-s1e8-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/episode-no-honeymoon-2020-s1e8-backdrop.jpg new file mode 100644 index 00000000..9d95ba77 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/episode-no-honeymoon-2020-s1e8-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/episode-no-honeymoon-2020-s1e8-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/episode-no-honeymoon-2020-s1e8-poster.jpg new file mode 100644 index 00000000..49c61208 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/episode-no-honeymoon-2020-s1e8-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/episode-notapusy-2005-s3e4-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/episode-notapusy-2005-s3e4-backdrop.jpg new file mode 100644 index 00000000..ecb7e8cd Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/episode-notapusy-2005-s3e4-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/episode-notapusy-2005-s3e4-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/episode-notapusy-2005-s3e4-poster.jpg new file mode 100644 index 00000000..02b0dd43 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/episode-notapusy-2005-s3e4-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/episode-one-of-us-2024-s1e7-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/episode-one-of-us-2024-s1e7-backdrop.jpg new file mode 100644 index 00000000..66bb4d00 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/episode-one-of-us-2024-s1e7-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/episode-one-of-us-2024-s1e7-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/episode-one-of-us-2024-s1e7-poster.jpg new file mode 100644 index 00000000..00a07ca7 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/episode-one-of-us-2024-s1e7-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/episode-remembrance-day-2026-s2e1-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/episode-remembrance-day-2026-s2e1-backdrop.jpg new file mode 100644 index 00000000..23a242da Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/episode-remembrance-day-2026-s2e1-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/episode-remembrance-day-2026-s2e1-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/episode-remembrance-day-2026-s2e1-poster.jpg new file mode 100644 index 00000000..930943b0 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/episode-remembrance-day-2026-s2e1-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/episode-sex-and-the-country-2001-s4e9-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/episode-sex-and-the-country-2001-s4e9-backdrop.jpg new file mode 100644 index 00000000..57beacc1 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/episode-sex-and-the-country-2001-s4e9-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/episode-sex-and-the-country-2001-s4e9-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/episode-sex-and-the-country-2001-s4e9-poster.jpg new file mode 100644 index 00000000..e546cc6d Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/episode-sex-and-the-country-2001-s4e9-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/episode-south-american-biker-gangs-2026-s29e1-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/episode-south-american-biker-gangs-2026-s29e1-backdrop.jpg new file mode 100644 index 00000000..cd0aec39 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/episode-south-american-biker-gangs-2026-s29e1-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/episode-south-american-biker-gangs-2026-s29e1-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/episode-south-american-biker-gangs-2026-s29e1-poster.jpg new file mode 100644 index 00000000..d8568d54 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/episode-south-american-biker-gangs-2026-s29e1-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/episode-the-breakup-part-2-2001-s1e17-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/episode-the-breakup-part-2-2001-s1e17-backdrop.jpg new file mode 100644 index 00000000..b42ba953 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/episode-the-breakup-part-2-2001-s1e17-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/episode-the-breakup-part-2-2001-s1e17-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/episode-the-breakup-part-2-2001-s1e17-poster.jpg new file mode 100644 index 00000000..23b668cb Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/episode-the-breakup-part-2-2001-s1e17-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/episode-the-man-who-would-be-vogue-2018-s2e1-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/episode-the-man-who-would-be-vogue-2018-s2e1-backdrop.jpg new file mode 100644 index 00000000..84944d39 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/episode-the-man-who-would-be-vogue-2018-s2e1-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/episode-the-man-who-would-be-vogue-2018-s2e1-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/episode-the-man-who-would-be-vogue-2018-s2e1-poster.jpg new file mode 100644 index 00000000..4086bf17 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/episode-the-man-who-would-be-vogue-2018-s2e1-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/episode-the-uncomfortability-2010-s1e2-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/episode-the-uncomfortability-2010-s1e2-backdrop.jpg new file mode 100644 index 00000000..bc22e11a Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/episode-the-uncomfortability-2010-s1e2-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/episode-the-uncomfortability-2010-s1e2-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/episode-the-uncomfortability-2010-s1e2-poster.jpg new file mode 100644 index 00000000..ae305043 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/episode-the-uncomfortability-2010-s1e2-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/episode-three-monsters-1992-s1e6-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/episode-three-monsters-1992-s1e6-backdrop.jpg new file mode 100644 index 00000000..ba65ca2d Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/episode-three-monsters-1992-s1e6-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/episode-three-monsters-1992-s1e6-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/episode-three-monsters-1992-s1e6-poster.jpg new file mode 100644 index 00000000..f5843766 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/episode-three-monsters-1992-s1e6-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/episode-tomorrow-2024-s3e1-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/episode-tomorrow-2024-s3e1-backdrop.jpg new file mode 100644 index 00000000..9c9cca57 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/episode-tomorrow-2024-s3e1-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/episode-tomorrow-2024-s3e1-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/episode-tomorrow-2024-s3e1-poster.jpg new file mode 100644 index 00000000..bbf0ab28 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/episode-tomorrow-2024-s3e1-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/episode-what-more-do-i-need-2008-s5e7-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/episode-what-more-do-i-need-2008-s5e7-backdrop.jpg new file mode 100644 index 00000000..40ec3001 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/episode-what-more-do-i-need-2008-s5e7-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/episode-what-more-do-i-need-2008-s5e7-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/episode-what-more-do-i-need-2008-s5e7-poster.jpg new file mode 100644 index 00000000..13f0f7b3 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/episode-what-more-do-i-need-2008-s5e7-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-101-dalmatians-ii-patch-s-london-adventure-2003-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-101-dalmatians-ii-patch-s-london-adventure-2003-backdrop.jpg new file mode 100644 index 00000000..f0d6f752 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-101-dalmatians-ii-patch-s-london-adventure-2003-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-101-dalmatians-ii-patch-s-london-adventure-2003-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-101-dalmatians-ii-patch-s-london-adventure-2003-poster.jpg new file mode 100644 index 00000000..b9b72894 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-101-dalmatians-ii-patch-s-london-adventure-2003-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-12-years-a-slave-2013-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-12-years-a-slave-2013-backdrop.jpg new file mode 100644 index 00000000..d93357e5 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-12-years-a-slave-2013-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-12-years-a-slave-2013-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-12-years-a-slave-2013-poster.jpg new file mode 100644 index 00000000..ff1f55e6 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-12-years-a-slave-2013-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-a-bronx-tale-1993-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-a-bronx-tale-1993-backdrop.jpg new file mode 100644 index 00000000..15c11ff7 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-a-bronx-tale-1993-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-a-bronx-tale-1993-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-a-bronx-tale-1993-poster.jpg new file mode 100644 index 00000000..f7444271 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-a-bronx-tale-1993-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-a-silent-voice-the-movie-2016-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-a-silent-voice-the-movie-2016-backdrop.jpg new file mode 100644 index 00000000..b386b136 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-a-silent-voice-the-movie-2016-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-a-silent-voice-the-movie-2016-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-a-silent-voice-the-movie-2016-poster.jpg new file mode 100644 index 00000000..580b22f4 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-a-silent-voice-the-movie-2016-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-absolution-2024-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-absolution-2024-backdrop.jpg new file mode 100644 index 00000000..eb28037c Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-absolution-2024-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-absolution-2024-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-absolution-2024-poster.jpg new file mode 100644 index 00000000..3ce49112 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-absolution-2024-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-across-the-hall-2009-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-across-the-hall-2009-backdrop.jpg new file mode 100644 index 00000000..6c1ee8ac Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-across-the-hall-2009-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-across-the-hall-2009-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-across-the-hall-2009-poster.jpg new file mode 100644 index 00000000..52362b4e Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-across-the-hall-2009-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-addicted-2014-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-addicted-2014-backdrop.jpg new file mode 100644 index 00000000..5c016976 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-addicted-2014-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-addicted-2014-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-addicted-2014-poster.jpg new file mode 100644 index 00000000..e9a03c14 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-addicted-2014-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-adulterers-2016-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-adulterers-2016-backdrop.jpg new file mode 100644 index 00000000..331391ed Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-adulterers-2016-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-adulterers-2016-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-adulterers-2016-poster.jpg new file mode 100644 index 00000000..8b65745b Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-adulterers-2016-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-all-the-money-in-the-world-2017-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-all-the-money-in-the-world-2017-backdrop.jpg new file mode 100644 index 00000000..ac4b828a Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-all-the-money-in-the-world-2017-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-all-the-money-in-the-world-2017-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-all-the-money-in-the-world-2017-poster.jpg new file mode 100644 index 00000000..8beb2f7f Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-all-the-money-in-the-world-2017-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-alone-with-her-2006-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-alone-with-her-2006-backdrop.jpg new file mode 100644 index 00000000..ddf8f1dc Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-alone-with-her-2006-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-alone-with-her-2006-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-alone-with-her-2006-poster.jpg new file mode 100644 index 00000000..7ce6fa96 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-alone-with-her-2006-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-american-gangster-2007-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-american-gangster-2007-backdrop.jpg new file mode 100644 index 00000000..cb5c5de7 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-american-gangster-2007-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-american-gangster-2007-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-american-gangster-2007-poster.jpg new file mode 100644 index 00000000..0f41d299 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-american-gangster-2007-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-annie-hall-1977-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-annie-hall-1977-backdrop.jpg new file mode 100644 index 00000000..16d0b27d Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-annie-hall-1977-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-annie-hall-1977-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-annie-hall-1977-poster.jpg new file mode 100644 index 00000000..9023a691 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-annie-hall-1977-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-ant-man-and-the-wasp-quantumania-2023-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-ant-man-and-the-wasp-quantumania-2023-backdrop.jpg new file mode 100644 index 00000000..2a99846d Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-ant-man-and-the-wasp-quantumania-2023-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-ant-man-and-the-wasp-quantumania-2023-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-ant-man-and-the-wasp-quantumania-2023-poster.jpg new file mode 100644 index 00000000..030addf0 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-ant-man-and-the-wasp-quantumania-2023-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-apocalypse-now-1979-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-apocalypse-now-1979-backdrop.jpg new file mode 100644 index 00000000..93292da3 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-apocalypse-now-1979-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-apocalypse-now-1979-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-apocalypse-now-1979-poster.jpg new file mode 100644 index 00000000..09cd6aa8 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-apocalypse-now-1979-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-appleseed-alpha-2014-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-appleseed-alpha-2014-backdrop.jpg new file mode 100644 index 00000000..82579b86 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-appleseed-alpha-2014-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-appleseed-alpha-2014-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-appleseed-alpha-2014-poster.jpg new file mode 100644 index 00000000..62bd0afa Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-appleseed-alpha-2014-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-aquaman-and-the-lost-kingdom-2023-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-aquaman-and-the-lost-kingdom-2023-backdrop.jpg new file mode 100644 index 00000000..6693cb6d Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-aquaman-and-the-lost-kingdom-2023-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-aquaman-and-the-lost-kingdom-2023-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-aquaman-and-the-lost-kingdom-2023-poster.jpg new file mode 100644 index 00000000..4550bdaa Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-aquaman-and-the-lost-kingdom-2023-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-arctic-dogs-2019-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-arctic-dogs-2019-backdrop.jpg new file mode 100644 index 00000000..1794c99d Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-arctic-dogs-2019-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-arctic-dogs-2019-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-arctic-dogs-2019-poster.jpg new file mode 100644 index 00000000..07552443 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-arctic-dogs-2019-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-arrival-2016-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-arrival-2016-backdrop.jpg new file mode 100644 index 00000000..605724e7 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-arrival-2016-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-arrival-2016-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-arrival-2016-poster.jpg new file mode 100644 index 00000000..fe224a15 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-arrival-2016-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-avatar-aang-the-last-airbender-2026-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-avatar-aang-the-last-airbender-2026-backdrop.jpg new file mode 100644 index 00000000..d3b12fe0 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-avatar-aang-the-last-airbender-2026-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-avatar-aang-the-last-airbender-2026-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-avatar-aang-the-last-airbender-2026-poster.jpg new file mode 100644 index 00000000..f57f1052 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-avatar-aang-the-last-airbender-2026-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-avengers-age-of-ultron-2015-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-avengers-age-of-ultron-2015-backdrop.jpg new file mode 100644 index 00000000..f739d620 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-avengers-age-of-ultron-2015-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-avengers-age-of-ultron-2015-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-avengers-age-of-ultron-2015-poster.jpg new file mode 100644 index 00000000..300840ff Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-avengers-age-of-ultron-2015-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-avengers-confidential-black-widow-punisher-2014-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-avengers-confidential-black-widow-punisher-2014-backdrop.jpg new file mode 100644 index 00000000..8163931a Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-avengers-confidential-black-widow-punisher-2014-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-avengers-confidential-black-widow-punisher-2014-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-avengers-confidential-black-widow-punisher-2014-poster.jpg new file mode 100644 index 00000000..b096fff2 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-avengers-confidential-black-widow-punisher-2014-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-avengers-infinity-war-2018-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-avengers-infinity-war-2018-backdrop.jpg new file mode 100644 index 00000000..90dc4672 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-avengers-infinity-war-2018-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-avengers-infinity-war-2018-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-avengers-infinity-war-2018-poster.jpg new file mode 100644 index 00000000..57df9298 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-avengers-infinity-war-2018-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-awake-2007-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-awake-2007-backdrop.jpg new file mode 100644 index 00000000..6ddd7f59 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-awake-2007-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-awake-2007-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-awake-2007-poster.jpg new file mode 100644 index 00000000..32595897 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-awake-2007-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-batman-ninja-2018-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-batman-ninja-2018-backdrop.jpg new file mode 100644 index 00000000..9b538d9f Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-batman-ninja-2018-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-batman-ninja-2018-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-batman-ninja-2018-poster.jpg new file mode 100644 index 00000000..7f59127b Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-batman-ninja-2018-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-batman-the-dark-knight-returns-part-1-2012-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-batman-the-dark-knight-returns-part-1-2012-backdrop.jpg new file mode 100644 index 00000000..9d385801 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-batman-the-dark-knight-returns-part-1-2012-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-batman-the-dark-knight-returns-part-1-2012-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-batman-the-dark-knight-returns-part-1-2012-poster.jpg new file mode 100644 index 00000000..ce5623fe Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-batman-the-dark-knight-returns-part-1-2012-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-batman-v-superman-dawn-of-justice-2016-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-batman-v-superman-dawn-of-justice-2016-backdrop.jpg new file mode 100644 index 00000000..b4fa63b9 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-batman-v-superman-dawn-of-justice-2016-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-batman-v-superman-dawn-of-justice-2016-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-batman-v-superman-dawn-of-justice-2016-poster.jpg new file mode 100644 index 00000000..f8115170 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-batman-v-superman-dawn-of-justice-2016-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-black-adam-2022-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-black-adam-2022-backdrop.jpg new file mode 100644 index 00000000..3232fb22 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-black-adam-2022-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-black-adam-2022-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-black-adam-2022-poster.jpg new file mode 100644 index 00000000..dde008b5 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-black-adam-2022-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-black-bear-2020-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-black-bear-2020-backdrop.jpg new file mode 100644 index 00000000..4b0b262f Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-black-bear-2020-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-black-bear-2020-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-black-bear-2020-poster.jpg new file mode 100644 index 00000000..61c8860f Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-black-bear-2020-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-black-panther-2018-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-black-panther-2018-backdrop.jpg new file mode 100644 index 00000000..f0b8de8a Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-black-panther-2018-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-black-panther-2018-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-black-panther-2018-poster.jpg new file mode 100644 index 00000000..6fdaa3d2 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-black-panther-2018-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-black-panther-wakanda-forever-2022-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-black-panther-wakanda-forever-2022-backdrop.jpg new file mode 100644 index 00000000..ac7ad532 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-black-panther-wakanda-forever-2022-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-black-panther-wakanda-forever-2022-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-black-panther-wakanda-forever-2022-poster.jpg new file mode 100644 index 00000000..d0219a75 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-black-panther-wakanda-forever-2022-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-blame-2017-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-blame-2017-backdrop.jpg new file mode 100644 index 00000000..f39cf5ce Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-blame-2017-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-blame-2017-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-blame-2017-poster.jpg new file mode 100644 index 00000000..8d50255f Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-blame-2017-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-bleach-the-movie-fade-to-black-2008-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-bleach-the-movie-fade-to-black-2008-backdrop.jpg new file mode 100644 index 00000000..f426d0ce Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-bleach-the-movie-fade-to-black-2008-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-bleach-the-movie-fade-to-black-2008-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-bleach-the-movie-fade-to-black-2008-poster.jpg new file mode 100644 index 00000000..d3619fbd Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-bleach-the-movie-fade-to-black-2008-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-bohemian-rhapsody-2018-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-bohemian-rhapsody-2018-backdrop.jpg new file mode 100644 index 00000000..b6b5a7cd Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-bohemian-rhapsody-2018-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-bohemian-rhapsody-2018-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-bohemian-rhapsody-2018-poster.jpg new file mode 100644 index 00000000..20d2f9ee Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-bohemian-rhapsody-2018-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-braveheart-1995-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-braveheart-1995-backdrop.jpg new file mode 100644 index 00000000..c1c84c59 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-braveheart-1995-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-braveheart-1995-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-braveheart-1995-poster.jpg new file mode 100644 index 00000000..32fd8d4d Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-braveheart-1995-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-butterfly-on-a-wheel-2007-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-butterfly-on-a-wheel-2007-backdrop.jpg new file mode 100644 index 00000000..e49fe1d5 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-butterfly-on-a-wheel-2007-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-butterfly-on-a-wheel-2007-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-butterfly-on-a-wheel-2007-poster.jpg new file mode 100644 index 00000000..b54cc5c7 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-butterfly-on-a-wheel-2007-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-by-any-means-2026-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-by-any-means-2026-backdrop.jpg new file mode 100644 index 00000000..e536359f Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-by-any-means-2026-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-by-any-means-2026-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-by-any-means-2026-poster.jpg new file mode 100644 index 00000000..92fd601f Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-by-any-means-2026-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-captain-america-civil-war-2016-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-captain-america-civil-war-2016-backdrop.jpg new file mode 100644 index 00000000..5700c4e7 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-captain-america-civil-war-2016-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-captain-america-civil-war-2016-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-captain-america-civil-war-2016-poster.jpg new file mode 100644 index 00000000..426142ef Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-captain-america-civil-war-2016-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-captain-america-the-first-avenger-2011-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-captain-america-the-first-avenger-2011-backdrop.jpg new file mode 100644 index 00000000..411ceebe Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-captain-america-the-first-avenger-2011-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-captain-america-the-first-avenger-2011-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-captain-america-the-first-avenger-2011-poster.jpg new file mode 100644 index 00000000..bba96574 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-captain-america-the-first-avenger-2011-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-captain-america-the-winter-soldier-2014-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-captain-america-the-winter-soldier-2014-backdrop.jpg new file mode 100644 index 00000000..5661fcff Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-captain-america-the-winter-soldier-2014-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-captain-america-the-winter-soldier-2014-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-captain-america-the-winter-soldier-2014-poster.jpg new file mode 100644 index 00000000..c2dc5612 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-captain-america-the-winter-soldier-2014-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-careful-what-you-wish-for-2015-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-careful-what-you-wish-for-2015-backdrop.jpg new file mode 100644 index 00000000..988e20d5 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-careful-what-you-wish-for-2015-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-careful-what-you-wish-for-2015-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-careful-what-you-wish-for-2015-poster.jpg new file mode 100644 index 00000000..b58ce600 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-careful-what-you-wish-for-2015-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-castle-in-the-sky-1986-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-castle-in-the-sky-1986-backdrop.jpg new file mode 100644 index 00000000..f785c549 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-castle-in-the-sky-1986-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-castle-in-the-sky-1986-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-castle-in-the-sky-1986-poster.jpg new file mode 100644 index 00000000..a6a99fee Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-castle-in-the-sky-1986-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-chicago-2002-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-chicago-2002-backdrop.jpg new file mode 100644 index 00000000..6b3d02a3 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-chicago-2002-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-chicago-2002-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-chicago-2002-poster.jpg new file mode 100644 index 00000000..1def9414 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-chicago-2002-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-citizen-kane-1941-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-citizen-kane-1941-backdrop.jpg new file mode 100644 index 00000000..d41a10ef Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-citizen-kane-1941-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-citizen-kane-1941-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-citizen-kane-1941-poster.jpg new file mode 100644 index 00000000..f26414a7 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-citizen-kane-1941-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-coherence-2014-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-coherence-2014-backdrop.jpg new file mode 100644 index 00000000..37da64f9 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-coherence-2014-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-coherence-2014-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-coherence-2014-poster.jpg new file mode 100644 index 00000000..f3601b9b Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-coherence-2014-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-conclave-2024-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-conclave-2024-backdrop.jpg new file mode 100644 index 00000000..db0a7fcd Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-conclave-2024-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-conclave-2024-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-conclave-2024-poster.jpg new file mode 100644 index 00000000..c6aecefa Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-conclave-2024-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-crime-of-passion-1956-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-crime-of-passion-1956-backdrop.jpg new file mode 100644 index 00000000..6c70a452 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-crime-of-passion-1956-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-crime-of-passion-1956-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-crime-of-passion-1956-poster.jpg new file mode 100644 index 00000000..4acfa871 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-crime-of-passion-1956-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-deep-water-2022-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-deep-water-2022-backdrop.jpg new file mode 100644 index 00000000..bec98992 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-deep-water-2022-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-deep-water-2022-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-deep-water-2022-poster.jpg new file mode 100644 index 00000000..018d4f4b Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-deep-water-2022-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-derailed-2005-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-derailed-2005-backdrop.jpg new file mode 100644 index 00000000..e958449b Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-derailed-2005-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-derailed-2005-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-derailed-2005-poster.jpg new file mode 100644 index 00000000..d93f3124 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-derailed-2005-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-die-my-love-2025-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-die-my-love-2025-backdrop.jpg new file mode 100644 index 00000000..754e713f Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-die-my-love-2025-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-die-my-love-2025-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-die-my-love-2025-poster.jpg new file mode 100644 index 00000000..f6eca818 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-die-my-love-2025-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-dream-house-2011-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-dream-house-2011-backdrop.jpg new file mode 100644 index 00000000..29ecc103 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-dream-house-2011-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-dream-house-2011-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-dream-house-2011-poster.jpg new file mode 100644 index 00000000..d3444637 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-dream-house-2011-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-dream-lover-1994-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-dream-lover-1994-backdrop.jpg new file mode 100644 index 00000000..7f5a31ac Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-dream-lover-1994-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-dream-lover-1994-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-dream-lover-1994-poster.jpg new file mode 100644 index 00000000..3b563cf9 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-dream-lover-1994-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-drop-2025-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-drop-2025-backdrop.jpg new file mode 100644 index 00000000..ee642530 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-drop-2025-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-drop-2025-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-drop-2025-poster.jpg new file mode 100644 index 00000000..4cf7d66b Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-drop-2025-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-eastern-promises-2007-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-eastern-promises-2007-backdrop.jpg new file mode 100644 index 00000000..9096a0fa Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-eastern-promises-2007-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-eastern-promises-2007-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-eastern-promises-2007-poster.jpg new file mode 100644 index 00000000..01a26f3b Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-eastern-promises-2007-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-easy-a-2010-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-easy-a-2010-backdrop.jpg new file mode 100644 index 00000000..c27fa57b Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-easy-a-2010-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-easy-a-2010-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-easy-a-2010-poster.jpg new file mode 100644 index 00000000..45e13a32 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-easy-a-2010-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-el-camino-a-breaking-bad-movie-2019-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-el-camino-a-breaking-bad-movie-2019-backdrop.jpg new file mode 100644 index 00000000..8edc02a6 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-el-camino-a-breaking-bad-movie-2019-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-el-camino-a-breaking-bad-movie-2019-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-el-camino-a-breaking-bad-movie-2019-poster.jpg new file mode 100644 index 00000000..7a62df45 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-el-camino-a-breaking-bad-movie-2019-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-emancipation-2022-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-emancipation-2022-backdrop.jpg new file mode 100644 index 00000000..ac0777c7 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-emancipation-2022-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-emancipation-2022-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-emancipation-2022-poster.jpg new file mode 100644 index 00000000..c1bee971 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-emancipation-2022-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-faces-1968-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-faces-1968-backdrop.jpg new file mode 100644 index 00000000..60273dd9 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-faces-1968-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-faces-1968-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-faces-1968-poster.jpg new file mode 100644 index 00000000..43f996bd Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-faces-1968-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-fatale-2020-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-fatale-2020-backdrop.jpg new file mode 100644 index 00000000..b13c33c6 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-fatale-2020-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-fatale-2020-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-fatale-2020-poster.jpg new file mode 100644 index 00000000..dda9d622 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-fatale-2020-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-fighting-with-my-family-2019-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-fighting-with-my-family-2019-backdrop.jpg new file mode 100644 index 00000000..46835996 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-fighting-with-my-family-2019-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-fighting-with-my-family-2019-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-fighting-with-my-family-2019-poster.jpg new file mode 100644 index 00000000..169c466d Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-fighting-with-my-family-2019-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-force-of-nature-the-dry-2-2024-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-force-of-nature-the-dry-2-2024-backdrop.jpg new file mode 100644 index 00000000..3735ee63 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-force-of-nature-the-dry-2-2024-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-force-of-nature-the-dry-2-2024-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-force-of-nature-the-dry-2-2024-poster.jpg new file mode 100644 index 00000000..93ba0d71 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-force-of-nature-the-dry-2-2024-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-free-state-of-jones-2016-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-free-state-of-jones-2016-backdrop.jpg new file mode 100644 index 00000000..a7e5ddff Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-free-state-of-jones-2016-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-free-state-of-jones-2016-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-free-state-of-jones-2016-poster.jpg new file mode 100644 index 00000000..e69af7c0 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-free-state-of-jones-2016-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-from-up-on-poppy-hill-2011-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-from-up-on-poppy-hill-2011-backdrop.jpg new file mode 100644 index 00000000..32a28bd7 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-from-up-on-poppy-hill-2011-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-from-up-on-poppy-hill-2011-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-from-up-on-poppy-hill-2011-poster.jpg new file mode 100644 index 00000000..264076e2 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-from-up-on-poppy-hill-2011-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-ghost-in-the-shell-1995-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-ghost-in-the-shell-1995-backdrop.jpg new file mode 100644 index 00000000..716b8a87 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-ghost-in-the-shell-1995-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-ghost-in-the-shell-1995-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-ghost-in-the-shell-1995-poster.jpg new file mode 100644 index 00000000..58d221ba Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-ghost-in-the-shell-1995-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-ghost-in-the-shell-2-innocence-2004-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-ghost-in-the-shell-2-innocence-2004-backdrop.jpg new file mode 100644 index 00000000..4a9931ed Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-ghost-in-the-shell-2-innocence-2004-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-ghost-in-the-shell-2-innocence-2004-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-ghost-in-the-shell-2-innocence-2004-poster.jpg new file mode 100644 index 00000000..ae262147 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-ghost-in-the-shell-2-innocence-2004-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-gosford-park-2001-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-gosford-park-2001-backdrop.jpg new file mode 100644 index 00000000..42c4cea6 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-gosford-park-2001-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-gosford-park-2001-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-gosford-park-2001-poster.jpg new file mode 100644 index 00000000..6a6aa651 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-gosford-park-2001-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-grave-of-the-fireflies-1988-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-grave-of-the-fireflies-1988-backdrop.jpg new file mode 100644 index 00000000..0e1add06 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-grave-of-the-fireflies-1988-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-grave-of-the-fireflies-1988-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-grave-of-the-fireflies-1988-poster.jpg new file mode 100644 index 00000000..1b71996a Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-grave-of-the-fireflies-1988-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-howl-s-moving-castle-2004-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-howl-s-moving-castle-2004-backdrop.jpg new file mode 100644 index 00000000..0aeef2ba Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-howl-s-moving-castle-2004-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-howl-s-moving-castle-2004-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-howl-s-moving-castle-2004-poster.jpg new file mode 100644 index 00000000..042a6c80 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-howl-s-moving-castle-2004-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-in-the-heights-2021-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-in-the-heights-2021-backdrop.jpg new file mode 100644 index 00000000..7cd4ee24 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-in-the-heights-2021-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-in-the-heights-2021-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-in-the-heights-2021-poster.jpg new file mode 100644 index 00000000..e05bfdb0 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-in-the-heights-2021-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-jennifer-s-body-2009-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-jennifer-s-body-2009-backdrop.jpg new file mode 100644 index 00000000..032771a0 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-jennifer-s-body-2009-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-jennifer-s-body-2009-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-jennifer-s-body-2009-poster.jpg new file mode 100644 index 00000000..41cc1eb5 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-jennifer-s-body-2009-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-kiki-s-delivery-service-1989-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-kiki-s-delivery-service-1989-backdrop.jpg new file mode 100644 index 00000000..2a108f0c Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-kiki-s-delivery-service-1989-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-kiki-s-delivery-service-1989-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-kiki-s-delivery-service-1989-poster.jpg new file mode 100644 index 00000000..80a59b1e Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-kiki-s-delivery-service-1989-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-lemony-snicket-s-a-series-of-unfortunate-events-2004-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-lemony-snicket-s-a-series-of-unfortunate-events-2004-backdrop.jpg new file mode 100644 index 00000000..38203b77 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-lemony-snicket-s-a-series-of-unfortunate-events-2004-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-lemony-snicket-s-a-series-of-unfortunate-events-2004-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-lemony-snicket-s-a-series-of-unfortunate-events-2004-poster.jpg new file mode 100644 index 00000000..4c78fee9 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-lemony-snicket-s-a-series-of-unfortunate-events-2004-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-locke-2014-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-locke-2014-backdrop.jpg new file mode 100644 index 00000000..a24e64ab Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-locke-2014-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-locke-2014-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-locke-2014-poster.jpg new file mode 100644 index 00000000..94ebe97d Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-locke-2014-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-look-who-s-back-2015-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-look-who-s-back-2015-backdrop.jpg new file mode 100644 index 00000000..a064686f Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-look-who-s-back-2015-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-look-who-s-back-2015-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-look-who-s-back-2015-poster.jpg new file mode 100644 index 00000000..423043cf Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-look-who-s-back-2015-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-memories-1995-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-memories-1995-backdrop.jpg new file mode 100644 index 00000000..2fcaeaad Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-memories-1995-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-memories-1995-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-memories-1995-poster.jpg new file mode 100644 index 00000000..f3725b42 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-memories-1995-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-mercy-2026-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-mercy-2026-backdrop.jpg new file mode 100644 index 00000000..45591cc8 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-mercy-2026-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-mercy-2026-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-mercy-2026-poster.jpg new file mode 100644 index 00000000..cfc0d812 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-mercy-2026-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-night-is-short-walk-on-girl-2017-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-night-is-short-walk-on-girl-2017-backdrop.jpg new file mode 100644 index 00000000..da38be48 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-night-is-short-walk-on-girl-2017-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-night-is-short-walk-on-girl-2017-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-night-is-short-walk-on-girl-2017-poster.jpg new file mode 100644 index 00000000..c6fa6a26 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-night-is-short-walk-on-girl-2017-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-normal-2026-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-normal-2026-backdrop.jpg new file mode 100644 index 00000000..51711864 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-normal-2026-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-normal-2026-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-normal-2026-poster.jpg new file mode 100644 index 00000000..f4c89db7 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-normal-2026-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-outlaw-king-2018-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-outlaw-king-2018-backdrop.jpg new file mode 100644 index 00000000..54ac5a2a Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-outlaw-king-2018-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-outlaw-king-2018-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-outlaw-king-2018-poster.jpg new file mode 100644 index 00000000..d6760468 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-outlaw-king-2018-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-panic-room-2002-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-panic-room-2002-backdrop.jpg new file mode 100644 index 00000000..ec877751 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-panic-room-2002-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-panic-room-2002-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-panic-room-2002-poster.jpg new file mode 100644 index 00000000..0b2a0d30 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-panic-room-2002-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-peaky-blinders-the-immortal-man-2026-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-peaky-blinders-the-immortal-man-2026-backdrop.jpg new file mode 100644 index 00000000..e9d7155a Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-peaky-blinders-the-immortal-man-2026-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-peaky-blinders-the-immortal-man-2026-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-peaky-blinders-the-immortal-man-2026-poster.jpg new file mode 100644 index 00000000..a4814472 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-peaky-blinders-the-immortal-man-2026-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-ponyo-2008-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-ponyo-2008-backdrop.jpg new file mode 100644 index 00000000..8aa4ecbd Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-ponyo-2008-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-ponyo-2008-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-ponyo-2008-poster.jpg new file mode 100644 index 00000000..f548e831 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-ponyo-2008-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-porco-rosso-1992-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-porco-rosso-1992-backdrop.jpg new file mode 100644 index 00000000..63d8112e Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-porco-rosso-1992-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-porco-rosso-1992-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-porco-rosso-1992-poster.jpg new file mode 100644 index 00000000..4a6a2bd1 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-porco-rosso-1992-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-princess-mononoke-1997-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-princess-mononoke-1997-backdrop.jpg new file mode 100644 index 00000000..9486d2cf Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-princess-mononoke-1997-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-princess-mononoke-1997-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-princess-mononoke-1997-poster.jpg new file mode 100644 index 00000000..21dd9359 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-princess-mononoke-1997-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-prisoners-2013-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-prisoners-2013-backdrop.jpg new file mode 100644 index 00000000..724008c5 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-prisoners-2013-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-prisoners-2013-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-prisoners-2013-poster.jpg new file mode 100644 index 00000000..411b149b Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-prisoners-2013-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-racing-stripes-2005-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-racing-stripes-2005-backdrop.jpg new file mode 100644 index 00000000..1d332cec Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-racing-stripes-2005-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-racing-stripes-2005-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-racing-stripes-2005-poster.jpg new file mode 100644 index 00000000..cc2ef2ce Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-racing-stripes-2005-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-reincarnated-2012-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-reincarnated-2012-backdrop.jpg new file mode 100644 index 00000000..326e8ebc Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-reincarnated-2012-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-reincarnated-2012-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-reincarnated-2012-poster.jpg new file mode 100644 index 00000000..e9ab449c Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-reincarnated-2012-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-requiem-for-a-dream-2000-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-requiem-for-a-dream-2000-backdrop.jpg new file mode 100644 index 00000000..21842ef2 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-requiem-for-a-dream-2000-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-requiem-for-a-dream-2000-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-requiem-for-a-dream-2000-poster.jpg new file mode 100644 index 00000000..6f89abc3 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-requiem-for-a-dream-2000-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-rogue-one-a-star-wars-story-2016-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-rogue-one-a-star-wars-story-2016-backdrop.jpg new file mode 100644 index 00000000..ff0c14c0 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-rogue-one-a-star-wars-story-2016-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-rogue-one-a-star-wars-story-2016-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-rogue-one-a-star-wars-story-2016-poster.jpg new file mode 100644 index 00000000..c79e70a1 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-rogue-one-a-star-wars-story-2016-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-secondhand-lions-2003-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-secondhand-lions-2003-backdrop.jpg new file mode 100644 index 00000000..7ea43937 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-secondhand-lions-2003-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-secondhand-lions-2003-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-secondhand-lions-2003-poster.jpg new file mode 100644 index 00000000..33408fa0 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-secondhand-lions-2003-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-self-reliance-2024-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-self-reliance-2024-backdrop.jpg new file mode 100644 index 00000000..3cc0d123 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-self-reliance-2024-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-self-reliance-2024-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-self-reliance-2024-poster.jpg new file mode 100644 index 00000000..0f6017ed Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-self-reliance-2024-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-serpico-1973-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-serpico-1973-backdrop.jpg new file mode 100644 index 00000000..c9649485 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-serpico-1973-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-serpico-1973-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-serpico-1973-poster.jpg new file mode 100644 index 00000000..8ddd6e52 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-serpico-1973-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-shaft-2000-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-shaft-2000-backdrop.jpg new file mode 100644 index 00000000..13f14f93 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-shaft-2000-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-shaft-2000-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-shaft-2000-poster.jpg new file mode 100644 index 00000000..6b2b79ce Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-shaft-2000-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-shipwrecked-nightmare-at-sea-2026-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-shipwrecked-nightmare-at-sea-2026-backdrop.jpg new file mode 100644 index 00000000..6e98e242 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-shipwrecked-nightmare-at-sea-2026-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-shipwrecked-nightmare-at-sea-2026-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-shipwrecked-nightmare-at-sea-2026-poster.jpg new file mode 100644 index 00000000..f200a28d Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-shipwrecked-nightmare-at-sea-2026-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-sinbad-legend-of-the-seven-seas-2003-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-sinbad-legend-of-the-seven-seas-2003-backdrop.jpg new file mode 100644 index 00000000..d04685fe Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-sinbad-legend-of-the-seven-seas-2003-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-sinbad-legend-of-the-seven-seas-2003-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-sinbad-legend-of-the-seven-seas-2003-poster.jpg new file mode 100644 index 00000000..428bb38b Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-sinbad-legend-of-the-seven-seas-2003-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-sleeping-with-other-people-2015-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-sleeping-with-other-people-2015-backdrop.jpg new file mode 100644 index 00000000..df5bb046 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-sleeping-with-other-people-2015-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-sleeping-with-other-people-2015-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-sleeping-with-other-people-2015-poster.jpg new file mode 100644 index 00000000..a5ffff1f Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-sleeping-with-other-people-2015-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-snowpiercer-2013-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-snowpiercer-2013-backdrop.jpg new file mode 100644 index 00000000..c1281a9c Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-snowpiercer-2013-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-snowpiercer-2013-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-snowpiercer-2013-poster.jpg new file mode 100644 index 00000000..be1873fd Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-snowpiercer-2013-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-spider-man-brand-new-day-2026-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-spider-man-brand-new-day-2026-backdrop.jpg new file mode 100644 index 00000000..2fdaadb4 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-spider-man-brand-new-day-2026-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-spider-man-brand-new-day-2026-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-spider-man-brand-new-day-2026-poster.jpg new file mode 100644 index 00000000..51fa155f Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-spider-man-brand-new-day-2026-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-spider-man-far-from-home-2019-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-spider-man-far-from-home-2019-backdrop.jpg new file mode 100644 index 00000000..d09f655a Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-spider-man-far-from-home-2019-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-spider-man-far-from-home-2019-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-spider-man-far-from-home-2019-poster.jpg new file mode 100644 index 00000000..28521997 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-spider-man-far-from-home-2019-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-spider-man-homecoming-2017-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-spider-man-homecoming-2017-backdrop.jpg new file mode 100644 index 00000000..6088fadf Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-spider-man-homecoming-2017-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-spider-man-homecoming-2017-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-spider-man-homecoming-2017-poster.jpg new file mode 100644 index 00000000..97fc9c05 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-spider-man-homecoming-2017-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-spider-man-no-way-home-2021-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-spider-man-no-way-home-2021-backdrop.jpg new file mode 100644 index 00000000..a76afec9 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-spider-man-no-way-home-2021-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-spider-man-no-way-home-2021-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-spider-man-no-way-home-2021-poster.jpg new file mode 100644 index 00000000..bc92a4cd Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-spider-man-no-way-home-2021-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-spirited-away-2001-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-spirited-away-2001-backdrop.jpg new file mode 100644 index 00000000..af91c123 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-spirited-away-2001-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-spirited-away-2001-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-spirited-away-2001-poster.jpg new file mode 100644 index 00000000..5a79da62 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-spirited-away-2001-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-steins-gate-the-movie-load-region-of-deja-vu-2013-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-steins-gate-the-movie-load-region-of-deja-vu-2013-backdrop.jpg new file mode 100644 index 00000000..f6675060 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-steins-gate-the-movie-load-region-of-deja-vu-2013-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-steins-gate-the-movie-load-region-of-deja-vu-2013-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-steins-gate-the-movie-load-region-of-deja-vu-2013-poster.jpg new file mode 100644 index 00000000..e85ddb90 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-steins-gate-the-movie-load-region-of-deja-vu-2013-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-taxi-driver-1976-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-taxi-driver-1976-backdrop.jpg new file mode 100644 index 00000000..7946ea40 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-taxi-driver-1976-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-taxi-driver-1976-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-taxi-driver-1976-poster.jpg new file mode 100644 index 00000000..c410b981 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-taxi-driver-1976-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-alto-knights-2025-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-alto-knights-2025-backdrop.jpg new file mode 100644 index 00000000..ea619c14 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-alto-knights-2025-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-alto-knights-2025-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-alto-knights-2025-poster.jpg new file mode 100644 index 00000000..bb009cbf Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-alto-knights-2025-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-amazing-spider-man-2-2014-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-amazing-spider-man-2-2014-backdrop.jpg new file mode 100644 index 00000000..7c5878b7 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-amazing-spider-man-2-2014-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-amazing-spider-man-2-2014-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-amazing-spider-man-2-2014-poster.jpg new file mode 100644 index 00000000..4de2711f Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-amazing-spider-man-2-2014-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-amazing-spider-man-2012-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-amazing-spider-man-2012-backdrop.jpg new file mode 100644 index 00000000..75ae9b64 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-amazing-spider-man-2012-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-amazing-spider-man-2012-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-amazing-spider-man-2012-poster.jpg new file mode 100644 index 00000000..c1aec876 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-amazing-spider-man-2012-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-animatrix-2003-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-animatrix-2003-backdrop.jpg new file mode 100644 index 00000000..7d67ccb0 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-animatrix-2003-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-animatrix-2003-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-animatrix-2003-poster.jpg new file mode 100644 index 00000000..65553d47 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-animatrix-2003-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-avengers-2012-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-avengers-2012-backdrop.jpg new file mode 100644 index 00000000..83636f25 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-avengers-2012-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-avengers-2012-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-avengers-2012-poster.jpg new file mode 100644 index 00000000..be87067c Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-avengers-2012-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-boy-and-the-heron-2023-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-boy-and-the-heron-2023-backdrop.jpg new file mode 100644 index 00000000..a19dc77b Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-boy-and-the-heron-2023-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-boy-and-the-heron-2023-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-boy-and-the-heron-2023-poster.jpg new file mode 100644 index 00000000..094df64e Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-boy-and-the-heron-2023-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-breakfast-club-1985-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-breakfast-club-1985-backdrop.jpg new file mode 100644 index 00000000..9f979cd8 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-breakfast-club-1985-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-breakfast-club-1985-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-breakfast-club-1985-poster.jpg new file mode 100644 index 00000000..d1823120 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-breakfast-club-1985-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-dry-2021-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-dry-2021-backdrop.jpg new file mode 100644 index 00000000..2f016498 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-dry-2021-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-dry-2021-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-dry-2021-poster.jpg new file mode 100644 index 00000000..a0379f2f Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-dry-2021-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-girl-who-leapt-through-time-2006-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-girl-who-leapt-through-time-2006-backdrop.jpg new file mode 100644 index 00000000..6e920467 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-girl-who-leapt-through-time-2006-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-girl-who-leapt-through-time-2006-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-girl-who-leapt-through-time-2006-poster.jpg new file mode 100644 index 00000000..ded6cd2a Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-girl-who-leapt-through-time-2006-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-godfather-1972-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-godfather-1972-backdrop.jpg new file mode 100644 index 00000000..8fbb8f2a Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-godfather-1972-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-godfather-1972-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-godfather-1972-poster.jpg new file mode 100644 index 00000000..94111d9b Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-godfather-1972-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-godfather-part-ii-1974-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-godfather-part-ii-1974-backdrop.jpg new file mode 100644 index 00000000..6dbff534 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-godfather-part-ii-1974-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-godfather-part-ii-1974-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-godfather-part-ii-1974-poster.jpg new file mode 100644 index 00000000..1328c99e Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-godfather-part-ii-1974-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-godfather-part-iii-1990-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-godfather-part-iii-1990-backdrop.jpg new file mode 100644 index 00000000..d2080487 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-godfather-part-iii-1990-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-godfather-part-iii-1990-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-godfather-part-iii-1990-poster.jpg new file mode 100644 index 00000000..abbe5e99 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-godfather-part-iii-1990-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-great-gatsby-2013-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-great-gatsby-2013-backdrop.jpg new file mode 100644 index 00000000..7a4f8a32 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-great-gatsby-2013-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-great-gatsby-2013-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-great-gatsby-2013-poster.jpg new file mode 100644 index 00000000..e949fb3e Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-great-gatsby-2013-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-hours-2002-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-hours-2002-backdrop.jpg new file mode 100644 index 00000000..507a78c4 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-hours-2002-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-hours-2002-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-hours-2002-poster.jpg new file mode 100644 index 00000000..f87e919f Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-hours-2002-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-killing-of-a-sacred-deer-2017-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-killing-of-a-sacred-deer-2017-backdrop.jpg new file mode 100644 index 00000000..dd755ee8 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-killing-of-a-sacred-deer-2017-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-killing-of-a-sacred-deer-2017-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-killing-of-a-sacred-deer-2017-poster.jpg new file mode 100644 index 00000000..83464d4c Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-killing-of-a-sacred-deer-2017-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-last-of-the-mohicans-1992-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-last-of-the-mohicans-1992-backdrop.jpg new file mode 100644 index 00000000..3256d38d Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-last-of-the-mohicans-1992-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-last-of-the-mohicans-1992-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-last-of-the-mohicans-1992-poster.jpg new file mode 100644 index 00000000..950e9ba1 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-last-of-the-mohicans-1992-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-last-samurai-2003-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-last-samurai-2003-backdrop.jpg new file mode 100644 index 00000000..509af2d6 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-last-samurai-2003-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-last-samurai-2003-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-last-samurai-2003-poster.jpg new file mode 100644 index 00000000..0d58440c Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-last-samurai-2003-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-lighthouse-2019-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-lighthouse-2019-backdrop.jpg new file mode 100644 index 00000000..862c064a Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-lighthouse-2019-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-lighthouse-2019-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-lighthouse-2019-poster.jpg new file mode 100644 index 00000000..15f26533 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-lighthouse-2019-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-matrix-1999-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-matrix-1999-backdrop.jpg new file mode 100644 index 00000000..c3bf8f52 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-matrix-1999-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-matrix-1999-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-matrix-1999-poster.jpg new file mode 100644 index 00000000..c292dce5 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-matrix-1999-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-matrix-reloaded-2003-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-matrix-reloaded-2003-backdrop.jpg new file mode 100644 index 00000000..dcbf7b96 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-matrix-reloaded-2003-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-matrix-reloaded-2003-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-matrix-reloaded-2003-poster.jpg new file mode 100644 index 00000000..ab11f50f Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-matrix-reloaded-2003-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-matrix-resurrections-2021-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-matrix-resurrections-2021-backdrop.jpg new file mode 100644 index 00000000..99d85a40 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-matrix-resurrections-2021-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-matrix-resurrections-2021-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-matrix-resurrections-2021-poster.jpg new file mode 100644 index 00000000..4477ef1e Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-matrix-resurrections-2021-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-matrix-revolutions-2003-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-matrix-revolutions-2003-backdrop.jpg new file mode 100644 index 00000000..2cc02692 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-matrix-revolutions-2003-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-matrix-revolutions-2003-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-matrix-revolutions-2003-poster.jpg new file mode 100644 index 00000000..7236cc4e Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-matrix-revolutions-2003-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-patriot-2000-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-patriot-2000-backdrop.jpg new file mode 100644 index 00000000..ce7ce498 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-patriot-2000-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-patriot-2000-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-patriot-2000-poster.jpg new file mode 100644 index 00000000..c8582133 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-patriot-2000-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-secret-life-of-pets-2-2019-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-secret-life-of-pets-2-2019-backdrop.jpg new file mode 100644 index 00000000..698f4ad2 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-secret-life-of-pets-2-2019-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-secret-life-of-pets-2-2019-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-secret-life-of-pets-2-2019-poster.jpg new file mode 100644 index 00000000..fe50c2f8 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-secret-life-of-pets-2-2019-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-substance-2024-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-substance-2024-backdrop.jpg new file mode 100644 index 00000000..47a8b372 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-substance-2024-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-substance-2024-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-substance-2024-poster.jpg new file mode 100644 index 00000000..72accfed Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-substance-2024-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-tale-of-the-princess-kaguya-2013-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-tale-of-the-princess-kaguya-2013-backdrop.jpg new file mode 100644 index 00000000..b9157b91 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-tale-of-the-princess-kaguya-2013-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-tale-of-the-princess-kaguya-2013-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-tale-of-the-princess-kaguya-2013-poster.jpg new file mode 100644 index 00000000..882621cb Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-tale-of-the-princess-kaguya-2013-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-uprising-2026-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-uprising-2026-backdrop.jpg new file mode 100644 index 00000000..638eab3d Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-uprising-2026-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-uprising-2026-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-uprising-2026-poster.jpg new file mode 100644 index 00000000..21976395 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-uprising-2026-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-wild-robot-2024-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-wild-robot-2024-backdrop.jpg new file mode 100644 index 00000000..bb48460b Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-wild-robot-2024-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-wild-robot-2024-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-wild-robot-2024-poster.jpg new file mode 100644 index 00000000..0894754d Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-wild-robot-2024-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-wind-rises-2013-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-wind-rises-2013-backdrop.jpg new file mode 100644 index 00000000..2af40e28 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-wind-rises-2013-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-wind-rises-2013-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-wind-rises-2013-poster.jpg new file mode 100644 index 00000000..b7688c77 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-wind-rises-2013-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-witcher-nightmare-of-the-wolf-2021-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-witcher-nightmare-of-the-wolf-2021-backdrop.jpg new file mode 100644 index 00000000..cb5bfb28 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-witcher-nightmare-of-the-wolf-2021-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-witcher-nightmare-of-the-wolf-2021-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-witcher-nightmare-of-the-wolf-2021-poster.jpg new file mode 100644 index 00000000..6db33db1 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-witcher-nightmare-of-the-wolf-2021-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-witcher-sirens-of-the-deep-2025-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-witcher-sirens-of-the-deep-2025-backdrop.jpg new file mode 100644 index 00000000..aad8ea2c Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-witcher-sirens-of-the-deep-2025-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-the-witcher-sirens-of-the-deep-2025-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-the-witcher-sirens-of-the-deep-2025-poster.jpg new file mode 100644 index 00000000..8a54bc7f Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-the-witcher-sirens-of-the-deep-2025-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-thelma-louise-1991-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-thelma-louise-1991-backdrop.jpg new file mode 100644 index 00000000..a35327a9 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-thelma-louise-1991-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-thelma-louise-1991-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-thelma-louise-1991-poster.jpg new file mode 100644 index 00000000..5a4ff0ab Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-thelma-louise-1991-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-triangle-of-sadness-2022-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-triangle-of-sadness-2022-backdrop.jpg new file mode 100644 index 00000000..7c9b445d Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-triangle-of-sadness-2022-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-triangle-of-sadness-2022-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-triangle-of-sadness-2022-poster.jpg new file mode 100644 index 00000000..aee092c6 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-triangle-of-sadness-2022-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-tsotsi-2005-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-tsotsi-2005-backdrop.jpg new file mode 100644 index 00000000..e119de53 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-tsotsi-2005-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-tsotsi-2005-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-tsotsi-2005-poster.jpg new file mode 100644 index 00000000..362ddd82 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-tsotsi-2005-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-unknown-number-the-high-school-catfish-2025-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-unknown-number-the-high-school-catfish-2025-backdrop.jpg new file mode 100644 index 00000000..f456c01d Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-unknown-number-the-high-school-catfish-2025-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-unknown-number-the-high-school-catfish-2025-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-unknown-number-the-high-school-catfish-2025-poster.jpg new file mode 100644 index 00000000..e32685f3 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-unknown-number-the-high-school-catfish-2025-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-vice-2018-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-vice-2018-backdrop.jpg new file mode 100644 index 00000000..2918db3a Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-vice-2018-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-vice-2018-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-vice-2018-poster.jpg new file mode 100644 index 00000000..76855126 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-vice-2018-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-vicky-cristina-barcelona-2008-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-vicky-cristina-barcelona-2008-backdrop.jpg new file mode 100644 index 00000000..20eaa159 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-vicky-cristina-barcelona-2008-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-vicky-cristina-barcelona-2008-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-vicky-cristina-barcelona-2008-poster.jpg new file mode 100644 index 00000000..1351cad1 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-vicky-cristina-barcelona-2008-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-warriors-of-the-wind-1984-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-warriors-of-the-wind-1984-backdrop.jpg new file mode 100644 index 00000000..1fb22b96 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-warriors-of-the-wind-1984-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-warriors-of-the-wind-1984-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-warriors-of-the-wind-1984-poster.jpg new file mode 100644 index 00000000..918e424f Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-warriors-of-the-wind-1984-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-we-bury-the-dead-2026-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-we-bury-the-dead-2026-backdrop.jpg new file mode 100644 index 00000000..4a24720d Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-we-bury-the-dead-2026-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-we-bury-the-dead-2026-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-we-bury-the-dead-2026-poster.jpg new file mode 100644 index 00000000..a0d65904 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-we-bury-the-dead-2026-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-white-hot-the-rise-fall-of-abercrombie-fitch-2022-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-white-hot-the-rise-fall-of-abercrombie-fitch-2022-backdrop.jpg new file mode 100644 index 00000000..2f186030 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-white-hot-the-rise-fall-of-abercrombie-fitch-2022-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/movie-white-hot-the-rise-fall-of-abercrombie-fitch-2022-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/movie-white-hot-the-rise-fall-of-abercrombie-fitch-2022-poster.jpg new file mode 100644 index 00000000..3a123e80 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/movie-white-hot-the-rise-fall-of-abercrombie-fitch-2022-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-12-monkeys-2015-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-12-monkeys-2015-backdrop.jpg new file mode 100644 index 00000000..3d2825f5 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-12-monkeys-2015-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-12-monkeys-2015-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-12-monkeys-2015-poster.jpg new file mode 100644 index 00000000..96e3596e Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-12-monkeys-2015-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-56-days-2026-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-56-days-2026-backdrop.jpg new file mode 100644 index 00000000..dcda667a Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-56-days-2026-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-56-days-2026-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-56-days-2026-poster.jpg new file mode 100644 index 00000000..64ca587b Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-56-days-2026-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-90-day-fiance-before-the-90-days-2017-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-90-day-fiance-before-the-90-days-2017-backdrop.jpg new file mode 100644 index 00000000..24f66f2d Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-90-day-fiance-before-the-90-days-2017-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-90-day-fiance-before-the-90-days-2017-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-90-day-fiance-before-the-90-days-2017-poster.jpg new file mode 100644 index 00000000..3362da59 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-90-day-fiance-before-the-90-days-2017-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-90-day-fiance-the-other-way-2019-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-90-day-fiance-the-other-way-2019-backdrop.jpg new file mode 100644 index 00000000..b18891fd Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-90-day-fiance-the-other-way-2019-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-90-day-fiance-the-other-way-2019-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-90-day-fiance-the-other-way-2019-poster.jpg new file mode 100644 index 00000000..b4d256eb Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-90-day-fiance-the-other-way-2019-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-a-knight-of-the-seven-kingdoms-2026-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-a-knight-of-the-seven-kingdoms-2026-backdrop.jpg new file mode 100644 index 00000000..ce12fc71 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-a-knight-of-the-seven-kingdoms-2026-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-a-knight-of-the-seven-kingdoms-2026-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-a-knight-of-the-seven-kingdoms-2026-poster.jpg new file mode 100644 index 00000000..79f1351c Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-a-knight-of-the-seven-kingdoms-2026-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-absolutely-fabulous-1992-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-absolutely-fabulous-1992-backdrop.jpg new file mode 100644 index 00000000..2df9722d Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-absolutely-fabulous-1992-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-absolutely-fabulous-1992-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-absolutely-fabulous-1992-poster.jpg new file mode 100644 index 00000000..afd371a9 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-absolutely-fabulous-1992-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-accel-world-2012-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-accel-world-2012-backdrop.jpg new file mode 100644 index 00000000..1f5f6bdc Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-accel-world-2012-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-accel-world-2012-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-accel-world-2012-poster.jpg new file mode 100644 index 00000000..207b1dd1 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-accel-world-2012-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-accused-2023-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-accused-2023-backdrop.jpg new file mode 100644 index 00000000..d41c6397 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-accused-2023-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-accused-2023-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-accused-2023-poster.jpg new file mode 100644 index 00000000..74af010a Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-accused-2023-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-adults-2025-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-adults-2025-backdrop.jpg new file mode 100644 index 00000000..9cc0ffe2 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-adults-2025-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-adults-2025-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-adults-2025-poster.jpg new file mode 100644 index 00000000..53a7ba33 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-adults-2025-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-after-life-2019-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-after-life-2019-backdrop.jpg new file mode 100644 index 00000000..eaf9a4fa Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-after-life-2019-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-after-life-2019-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-after-life-2019-poster.jpg new file mode 100644 index 00000000..4fae4e33 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-after-life-2019-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-agatha-christie-s-marple-2004-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-agatha-christie-s-marple-2004-backdrop.jpg new file mode 100644 index 00000000..0c52f2e6 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-agatha-christie-s-marple-2004-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-agatha-christie-s-marple-2004-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-agatha-christie-s-marple-2004-poster.jpg new file mode 100644 index 00000000..ea7dda99 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-agatha-christie-s-marple-2004-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-ahsoka-2023-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-ahsoka-2023-backdrop.jpg new file mode 100644 index 00000000..7343fb32 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-ahsoka-2023-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-ahsoka-2023-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-ahsoka-2023-poster.jpg new file mode 100644 index 00000000..a29d6cb4 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-ahsoka-2023-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-all-american-homecoming-2022-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-all-american-homecoming-2022-backdrop.jpg new file mode 100644 index 00000000..09fbb9dc Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-all-american-homecoming-2022-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-all-american-homecoming-2022-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-all-american-homecoming-2022-poster.jpg new file mode 100644 index 00000000..09ccfc33 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-all-american-homecoming-2022-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-all-creatures-great-and-small-1978-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-all-creatures-great-and-small-1978-backdrop.jpg new file mode 100644 index 00000000..909ae1ba Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-all-creatures-great-and-small-1978-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-all-creatures-great-and-small-1978-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-all-creatures-great-and-small-1978-poster.jpg new file mode 100644 index 00000000..5b1666e6 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-all-creatures-great-and-small-1978-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-all-creatures-great-small-2020-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-all-creatures-great-small-2020-backdrop.jpg new file mode 100644 index 00000000..d2bcc88d Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-all-creatures-great-small-2020-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-all-creatures-great-small-2020-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-all-creatures-great-small-2020-poster.jpg new file mode 100644 index 00000000..b506f990 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-all-creatures-great-small-2020-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-american-crime-story-2016-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-american-crime-story-2016-backdrop.jpg new file mode 100644 index 00000000..84944d39 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-american-crime-story-2016-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-american-crime-story-2016-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-american-crime-story-2016-poster.jpg new file mode 100644 index 00000000..4086bf17 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-american-crime-story-2016-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-american-dad-2005-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-american-dad-2005-backdrop.jpg new file mode 100644 index 00000000..75a1948b Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-american-dad-2005-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-american-dad-2005-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-american-dad-2005-poster.jpg new file mode 100644 index 00000000..1f9e239a Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-american-dad-2005-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-american-gods-2017-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-american-gods-2017-backdrop.jpg new file mode 100644 index 00000000..4817c690 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-american-gods-2017-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-american-gods-2017-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-american-gods-2017-poster.jpg new file mode 100644 index 00000000..c02c46da Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-american-gods-2017-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-american-housewife-2016-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-american-housewife-2016-backdrop.jpg new file mode 100644 index 00000000..bf758ae0 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-american-housewife-2016-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-american-housewife-2016-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-american-housewife-2016-poster.jpg new file mode 100644 index 00000000..5f92bf05 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-american-housewife-2016-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-american-primeval-2025-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-american-primeval-2025-backdrop.jpg new file mode 100644 index 00000000..c3bfe5e1 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-american-primeval-2025-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-american-primeval-2025-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-american-primeval-2025-poster.jpg new file mode 100644 index 00000000..7f10e6aa Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-american-primeval-2025-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-and-just-like-that-2021-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-and-just-like-that-2021-backdrop.jpg new file mode 100644 index 00000000..59c981e5 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-and-just-like-that-2021-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-and-just-like-that-2021-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-and-just-like-that-2021-poster.jpg new file mode 100644 index 00000000..9904c74b Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-and-just-like-that-2021-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-andor-2022-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-andor-2022-backdrop.jpg new file mode 100644 index 00000000..a874a0c0 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-andor-2022-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-andor-2022-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-andor-2022-poster.jpg new file mode 100644 index 00000000..df5dc498 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-andor-2022-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-andromeda-2000-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-andromeda-2000-backdrop.jpg new file mode 100644 index 00000000..199249d7 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-andromeda-2000-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-andromeda-2000-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-andromeda-2000-poster.jpg new file mode 100644 index 00000000..67b766b0 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-andromeda-2000-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-anne-with-an-e-2017-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-anne-with-an-e-2017-backdrop.jpg new file mode 100644 index 00000000..15e325c9 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-anne-with-an-e-2017-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-anne-with-an-e-2017-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-anne-with-an-e-2017-poster.jpg new file mode 100644 index 00000000..55d443b4 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-anne-with-an-e-2017-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-aqua-teen-hunger-force-2000-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-aqua-teen-hunger-force-2000-backdrop.jpg new file mode 100644 index 00000000..d0e37959 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-aqua-teen-hunger-force-2000-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-aqua-teen-hunger-force-2000-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-aqua-teen-hunger-force-2000-poster.jpg new file mode 100644 index 00000000..e0c97321 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-aqua-teen-hunger-force-2000-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-arifureta-from-commonplace-to-world-s-strongest-2019-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-arifureta-from-commonplace-to-world-s-strongest-2019-backdrop.jpg new file mode 100644 index 00000000..9300e20f Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-arifureta-from-commonplace-to-world-s-strongest-2019-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-arifureta-from-commonplace-to-world-s-strongest-2019-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-arifureta-from-commonplace-to-world-s-strongest-2019-poster.jpg new file mode 100644 index 00000000..6a8f9a24 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-arifureta-from-commonplace-to-world-s-strongest-2019-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-arrested-development-2003-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-arrested-development-2003-backdrop.jpg new file mode 100644 index 00000000..ecb7e8cd Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-arrested-development-2003-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-arrested-development-2003-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-arrested-development-2003-poster.jpg new file mode 100644 index 00000000..02b0dd43 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-arrested-development-2003-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-arrow-2012-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-arrow-2012-backdrop.jpg new file mode 100644 index 00000000..b32f5aca Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-arrow-2012-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-arrow-2012-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-arrow-2012-poster.jpg new file mode 100644 index 00000000..adee3bb7 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-arrow-2012-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-atlantis-2013-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-atlantis-2013-backdrop.jpg new file mode 100644 index 00000000..39ecc0d6 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-atlantis-2013-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-atlantis-2013-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-atlantis-2013-poster.jpg new file mode 100644 index 00000000..5cd5f098 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-atlantis-2013-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-avatar-seven-havens-2026-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-avatar-seven-havens-2026-backdrop.jpg new file mode 100644 index 00000000..dacfd59e Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-avatar-seven-havens-2026-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-avatar-seven-havens-2026-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-avatar-seven-havens-2026-poster.jpg new file mode 100644 index 00000000..61f459c6 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-avatar-seven-havens-2026-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-avatar-the-last-airbender-2005-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-avatar-the-last-airbender-2005-backdrop.jpg new file mode 100644 index 00000000..f60120da Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-avatar-the-last-airbender-2005-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-avatar-the-last-airbender-2005-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-avatar-the-last-airbender-2005-poster.jpg new file mode 100644 index 00000000..6f99263a Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-avatar-the-last-airbender-2005-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-avatar-the-last-airbender-2024-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-avatar-the-last-airbender-2024-backdrop.jpg new file mode 100644 index 00000000..ad740218 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-avatar-the-last-airbender-2024-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-avatar-the-last-airbender-2024-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-avatar-the-last-airbender-2024-poster.jpg new file mode 100644 index 00000000..9d46c2ff Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-avatar-the-last-airbender-2024-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-awkward-2011-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-awkward-2011-backdrop.jpg new file mode 100644 index 00000000..1ca5e56c Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-awkward-2011-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-awkward-2011-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-awkward-2011-poster.jpg new file mode 100644 index 00000000..8da6e8e2 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-awkward-2011-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-b-b-vol-liefde-2021-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-b-b-vol-liefde-2021-backdrop.jpg new file mode 100644 index 00000000..57ece15e Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-b-b-vol-liefde-2021-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-b-b-vol-liefde-2021-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-b-b-vol-liefde-2021-poster.jpg new file mode 100644 index 00000000..a12ac33e Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-b-b-vol-liefde-2021-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-back-to-life-2019-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-back-to-life-2019-backdrop.jpg new file mode 100644 index 00000000..7ffef681 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-back-to-life-2019-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-back-to-life-2019-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-back-to-life-2019-poster.jpg new file mode 100644 index 00000000..b00730a8 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-back-to-life-2019-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-ballers-2015-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-ballers-2015-backdrop.jpg new file mode 100644 index 00000000..c4685e84 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-ballers-2015-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-ballers-2015-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-ballers-2015-poster.jpg new file mode 100644 index 00000000..f1c18f69 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-ballers-2015-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-baretta-1975-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-baretta-1975-backdrop.jpg new file mode 100644 index 00000000..4d61dfbe Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-baretta-1975-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-baretta-1975-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-baretta-1975-poster.jpg new file mode 100644 index 00000000..ceef0c9d Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-baretta-1975-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-based-on-a-true-story-2023-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-based-on-a-true-story-2023-backdrop.jpg new file mode 100644 index 00000000..b59c0e58 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-based-on-a-true-story-2023-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-based-on-a-true-story-2023-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-based-on-a-true-story-2023-poster.jpg new file mode 100644 index 00000000..386d3d90 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-based-on-a-true-story-2023-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-batman-the-brave-and-the-bold-2008-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-batman-the-brave-and-the-bold-2008-backdrop.jpg new file mode 100644 index 00000000..69e567cb Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-batman-the-brave-and-the-bold-2008-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-batman-the-brave-and-the-bold-2008-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-batman-the-brave-and-the-bold-2008-poster.jpg new file mode 100644 index 00000000..a864f50c Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-batman-the-brave-and-the-bold-2008-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-batwoman-2019-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-batwoman-2019-backdrop.jpg new file mode 100644 index 00000000..d04a1a20 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-batwoman-2019-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-batwoman-2019-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-batwoman-2019-poster.jpg new file mode 100644 index 00000000..7ca86592 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-batwoman-2019-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-beat-bobby-flay-2013-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-beat-bobby-flay-2013-backdrop.jpg new file mode 100644 index 00000000..e6c36ddd Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-beat-bobby-flay-2013-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-beat-bobby-flay-2013-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-beat-bobby-flay-2013-poster.jpg new file mode 100644 index 00000000..fe11122d Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-beat-bobby-flay-2013-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-benson-1979-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-benson-1979-backdrop.jpg new file mode 100644 index 00000000..32bd63a9 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-benson-1979-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-benson-1979-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-benson-1979-poster.jpg new file mode 100644 index 00000000..fe264c76 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-benson-1979-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-big-boys-2022-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-big-boys-2022-backdrop.jpg new file mode 100644 index 00000000..c7c91e2d Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-big-boys-2022-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-big-boys-2022-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-big-boys-2022-poster.jpg new file mode 100644 index 00000000..93e1e86a Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-big-boys-2022-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-big-city-greens-2018-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-big-city-greens-2018-backdrop.jpg new file mode 100644 index 00000000..381774e7 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-big-city-greens-2018-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-big-city-greens-2018-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-big-city-greens-2018-poster.jpg new file mode 100644 index 00000000..ef024946 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-big-city-greens-2018-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-big-mouth-2017-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-big-mouth-2017-backdrop.jpg new file mode 100644 index 00000000..760e0262 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-big-mouth-2017-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-big-mouth-2017-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-big-mouth-2017-poster.jpg new file mode 100644 index 00000000..4f535fec Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-big-mouth-2017-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-black-ish-2014-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-black-ish-2014-backdrop.jpg new file mode 100644 index 00000000..967fb621 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-black-ish-2014-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-black-ish-2014-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-black-ish-2014-poster.jpg new file mode 100644 index 00000000..97c885ad Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-black-ish-2014-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-black-lightning-2018-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-black-lightning-2018-backdrop.jpg new file mode 100644 index 00000000..3a0854c9 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-black-lightning-2018-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-black-lightning-2018-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-black-lightning-2018-poster.jpg new file mode 100644 index 00000000..733f5cbc Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-black-lightning-2018-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-black-rabbit-2025-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-black-rabbit-2025-backdrop.jpg new file mode 100644 index 00000000..48df9d46 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-black-rabbit-2025-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-black-rabbit-2025-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-black-rabbit-2025-poster.jpg new file mode 100644 index 00000000..3ff9aeed Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-black-rabbit-2025-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-bleach-2004-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-bleach-2004-backdrop.jpg new file mode 100644 index 00000000..ef8eaaa3 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-bleach-2004-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-bleach-2004-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-bleach-2004-poster.jpg new file mode 100644 index 00000000..b233e033 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-bleach-2004-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-blue-planet-ii-2017-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-blue-planet-ii-2017-backdrop.jpg new file mode 100644 index 00000000..8175e568 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-blue-planet-ii-2017-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-blue-planet-ii-2017-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-blue-planet-ii-2017-poster.jpg new file mode 100644 index 00000000..5e193ab2 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-blue-planet-ii-2017-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-brassic-2019-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-brassic-2019-backdrop.jpg new file mode 100644 index 00000000..86d3d806 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-brassic-2019-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-brassic-2019-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-brassic-2019-poster.jpg new file mode 100644 index 00000000..73b77df2 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-brassic-2019-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-breaking-bad-2008-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-breaking-bad-2008-backdrop.jpg new file mode 100644 index 00000000..e4ac4ae3 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-breaking-bad-2008-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-breaking-bad-2008-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-breaking-bad-2008-poster.jpg new file mode 100644 index 00000000..c4f7217c Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-breaking-bad-2008-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-breeders-2020-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-breeders-2020-backdrop.jpg new file mode 100644 index 00000000..9d95ba77 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-breeders-2020-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-breeders-2020-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-breeders-2020-poster.jpg new file mode 100644 index 00000000..49c61208 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-breeders-2020-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-californication-2007-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-californication-2007-backdrop.jpg new file mode 100644 index 00000000..ffff979b Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-californication-2007-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-californication-2007-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-californication-2007-poster.jpg new file mode 100644 index 00000000..38428e76 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-californication-2007-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-call-the-midwife-2012-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-call-the-midwife-2012-backdrop.jpg new file mode 100644 index 00000000..1ee28b8d Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-call-the-midwife-2012-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-call-the-midwife-2012-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-call-the-midwife-2012-poster.jpg new file mode 100644 index 00000000..466a1a7b Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-call-the-midwife-2012-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-chainsaw-man-2022-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-chainsaw-man-2022-backdrop.jpg new file mode 100644 index 00000000..f1fbee3e Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-chainsaw-man-2022-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-chainsaw-man-2022-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-chainsaw-man-2022-poster.jpg new file mode 100644 index 00000000..a3779772 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-chainsaw-man-2022-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-chernobyl-2019-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-chernobyl-2019-backdrop.jpg new file mode 100644 index 00000000..818a6665 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-chernobyl-2019-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-chernobyl-2019-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-chernobyl-2019-poster.jpg new file mode 100644 index 00000000..7664f4b0 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-chernobyl-2019-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-community-2009-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-community-2009-backdrop.jpg new file mode 100644 index 00000000..8deb8d5c Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-community-2009-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-community-2009-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-community-2009-poster.jpg new file mode 100644 index 00000000..e75072ae Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-community-2009-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-cyberpunk-edgerunners-2022-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-cyberpunk-edgerunners-2022-backdrop.jpg new file mode 100644 index 00000000..2920cf5a Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-cyberpunk-edgerunners-2022-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-cyberpunk-edgerunners-2022-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-cyberpunk-edgerunners-2022-poster.jpg new file mode 100644 index 00000000..8d338532 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-cyberpunk-edgerunners-2022-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-dan-da-dan-2024-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-dan-da-dan-2024-backdrop.jpg new file mode 100644 index 00000000..0cbc4b07 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-dan-da-dan-2024-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-dan-da-dan-2024-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-dan-da-dan-2024-poster.jpg new file mode 100644 index 00000000..f42cec16 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-dan-da-dan-2024-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-dead-end-job-2026-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-dead-end-job-2026-backdrop.jpg new file mode 100644 index 00000000..3525c2fc Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-dead-end-job-2026-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-dead-end-job-2026-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-dead-end-job-2026-poster.jpg new file mode 100644 index 00000000..f5546d88 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-dead-end-job-2026-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-derry-girls-2018-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-derry-girls-2018-backdrop.jpg new file mode 100644 index 00000000..76fae98c Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-derry-girls-2018-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-derry-girls-2018-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-derry-girls-2018-poster.jpg new file mode 100644 index 00000000..56a8cd79 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-derry-girls-2018-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-desperate-housewives-2004-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-desperate-housewives-2004-backdrop.jpg new file mode 100644 index 00000000..40ec3001 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-desperate-housewives-2004-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-desperate-housewives-2004-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-desperate-housewives-2004-poster.jpg new file mode 100644 index 00000000..0c4c38bc Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-desperate-housewives-2004-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-dopesick-2021-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-dopesick-2021-backdrop.jpg new file mode 100644 index 00000000..8d9f2727 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-dopesick-2021-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-dopesick-2021-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-dopesick-2021-poster.jpg new file mode 100644 index 00000000..ac0b5900 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-dopesick-2021-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-dr-stone-2019-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-dr-stone-2019-backdrop.jpg new file mode 100644 index 00000000..5ac396b6 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-dr-stone-2019-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-dr-stone-2019-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-dr-stone-2019-poster.jpg new file mode 100644 index 00000000..0783ed8c Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-dr-stone-2019-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-dune-prophecy-2024-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-dune-prophecy-2024-backdrop.jpg new file mode 100644 index 00000000..5b940b9f Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-dune-prophecy-2024-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-dune-prophecy-2024-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-dune-prophecy-2024-poster.jpg new file mode 100644 index 00000000..eef2a4f3 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-dune-prophecy-2024-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-east-of-eden-2026-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-east-of-eden-2026-backdrop.jpg new file mode 100644 index 00000000..89dfafbf Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-east-of-eden-2026-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-east-of-eden-2026-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-east-of-eden-2026-poster.jpg new file mode 100644 index 00000000..6f06f2c9 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-east-of-eden-2026-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-etoile-2025-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-etoile-2025-backdrop.jpg new file mode 100644 index 00000000..a8e9576c Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-etoile-2025-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-etoile-2025-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-etoile-2025-poster.jpg new file mode 100644 index 00000000..f078bc89 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-etoile-2025-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-fallout-2024-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-fallout-2024-backdrop.jpg new file mode 100644 index 00000000..c9d6a190 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-fallout-2024-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-fallout-2024-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-fallout-2024-poster.jpg new file mode 100644 index 00000000..5e87a07d Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-fallout-2024-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-fawlty-towers-1975-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-fawlty-towers-1975-backdrop.jpg new file mode 100644 index 00000000..2c9c258f Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-fawlty-towers-1975-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-fawlty-towers-1975-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-fawlty-towers-1975-poster.jpg new file mode 100644 index 00000000..53b406da Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-fawlty-towers-1975-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-firefly-2002-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-firefly-2002-backdrop.jpg new file mode 100644 index 00000000..fa3b7604 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-firefly-2002-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-firefly-2002-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-firefly-2002-poster.jpg new file mode 100644 index 00000000..9ad599b3 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-firefly-2002-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-fleabag-2016-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-fleabag-2016-backdrop.jpg new file mode 100644 index 00000000..e5a83462 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-fleabag-2016-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-fleabag-2016-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-fleabag-2016-poster.jpg new file mode 100644 index 00000000..bd3ccea5 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-fleabag-2016-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-frieren-beyond-journey-s-end-2023-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-frieren-beyond-journey-s-end-2023-backdrop.jpg new file mode 100644 index 00000000..a42a2c94 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-frieren-beyond-journey-s-end-2023-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-frieren-beyond-journey-s-end-2023-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-frieren-beyond-journey-s-end-2023-poster.jpg new file mode 100644 index 00000000..cb94104e Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-frieren-beyond-journey-s-end-2023-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-fullmetal-alchemist-brotherhood-2009-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-fullmetal-alchemist-brotherhood-2009-backdrop.jpg new file mode 100644 index 00000000..91ce4909 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-fullmetal-alchemist-brotherhood-2009-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-fullmetal-alchemist-brotherhood-2009-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-fullmetal-alchemist-brotherhood-2009-poster.jpg new file mode 100644 index 00000000..935e4944 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-fullmetal-alchemist-brotherhood-2009-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-gilmore-girls-2000-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-gilmore-girls-2000-backdrop.jpg new file mode 100644 index 00000000..b42ba953 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-gilmore-girls-2000-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-gilmore-girls-2000-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-gilmore-girls-2000-poster.jpg new file mode 100644 index 00000000..23b668cb Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-gilmore-girls-2000-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-ginny-georgia-2021-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-ginny-georgia-2021-backdrop.jpg new file mode 100644 index 00000000..1271d577 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-ginny-georgia-2021-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-ginny-georgia-2021-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-ginny-georgia-2021-poster.jpg new file mode 100644 index 00000000..1fca7bf6 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-ginny-georgia-2021-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-gravity-falls-2012-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-gravity-falls-2012-backdrop.jpg new file mode 100644 index 00000000..b9ef40fa Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-gravity-falls-2012-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-gravity-falls-2012-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-gravity-falls-2012-poster.jpg new file mode 100644 index 00000000..41c051e0 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-gravity-falls-2012-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-hellcats-2010-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-hellcats-2010-backdrop.jpg new file mode 100644 index 00000000..38e856b0 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-hellcats-2010-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-hellcats-2010-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-hellcats-2010-poster.jpg new file mode 100644 index 00000000..2427108b Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-hellcats-2010-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-high-potential-2024-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-high-potential-2024-backdrop.jpg new file mode 100644 index 00000000..66bb4d00 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-high-potential-2024-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-high-potential-2024-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-high-potential-2024-poster.jpg new file mode 100644 index 00000000..00a07ca7 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-high-potential-2024-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-how-to-change-your-mind-2022-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-how-to-change-your-mind-2022-backdrop.jpg new file mode 100644 index 00000000..9e4171e3 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-how-to-change-your-mind-2022-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-how-to-change-your-mind-2022-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-how-to-change-your-mind-2022-poster.jpg new file mode 100644 index 00000000..e80c7999 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-how-to-change-your-mind-2022-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-how-to-get-to-heaven-from-belfast-2026-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-how-to-get-to-heaven-from-belfast-2026-backdrop.jpg new file mode 100644 index 00000000..a605895b Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-how-to-get-to-heaven-from-belfast-2026-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-how-to-get-to-heaven-from-belfast-2026-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-how-to-get-to-heaven-from-belfast-2026-poster.jpg new file mode 100644 index 00000000..eb5fc487 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-how-to-get-to-heaven-from-belfast-2026-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-interrogation-2020-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-interrogation-2020-backdrop.jpg new file mode 100644 index 00000000..c347e016 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-interrogation-2020-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-interrogation-2020-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-interrogation-2020-poster.jpg new file mode 100644 index 00000000..f3a21b66 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-interrogation-2020-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-invincible-2021-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-invincible-2021-backdrop.jpg new file mode 100644 index 00000000..e8120387 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-invincible-2021-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-invincible-2021-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-invincible-2021-poster.jpg new file mode 100644 index 00000000..c278e37e Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-invincible-2021-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-it-s-always-sunny-in-philadelphia-2005-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-it-s-always-sunny-in-philadelphia-2005-backdrop.jpg new file mode 100644 index 00000000..cbdc6525 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-it-s-always-sunny-in-philadelphia-2005-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-it-s-always-sunny-in-philadelphia-2005-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-it-s-always-sunny-in-philadelphia-2005-poster.jpg new file mode 100644 index 00000000..652923ee Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-it-s-always-sunny-in-philadelphia-2005-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-jujutsu-kaisen-2020-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-jujutsu-kaisen-2020-backdrop.jpg new file mode 100644 index 00000000..79e7d6bd Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-jujutsu-kaisen-2020-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-jujutsu-kaisen-2020-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-jujutsu-kaisen-2020-poster.jpg new file mode 100644 index 00000000..45f5ff22 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-jujutsu-kaisen-2020-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-kaiju-no-8-2024-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-kaiju-no-8-2024-backdrop.jpg new file mode 100644 index 00000000..480b2a8e Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-kaiju-no-8-2024-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-kaiju-no-8-2024-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-kaiju-no-8-2024-poster.jpg new file mode 100644 index 00000000..062496fa Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-kaiju-no-8-2024-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-landman-2024-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-landman-2024-backdrop.jpg new file mode 100644 index 00000000..009fbfc2 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-landman-2024-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-landman-2024-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-landman-2024-poster.jpg new file mode 100644 index 00000000..3d348798 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-landman-2024-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-last-samurai-standing-2025-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-last-samurai-standing-2025-backdrop.jpg new file mode 100644 index 00000000..c85a210b Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-last-samurai-standing-2025-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-last-samurai-standing-2025-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-last-samurai-standing-2025-poster.jpg new file mode 100644 index 00000000..a9789909 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-last-samurai-standing-2025-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-lord-of-the-flies-2026-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-lord-of-the-flies-2026-backdrop.jpg new file mode 100644 index 00000000..1249a8f3 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-lord-of-the-flies-2026-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-lord-of-the-flies-2026-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-lord-of-the-flies-2026-poster.jpg new file mode 100644 index 00000000..b1229ed8 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-lord-of-the-flies-2026-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-love-death-robots-2019-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-love-death-robots-2019-backdrop.jpg new file mode 100644 index 00000000..3694bfc4 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-love-death-robots-2019-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-love-death-robots-2019-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-love-death-robots-2019-poster.jpg new file mode 100644 index 00000000..08449aa9 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-love-death-robots-2019-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-love-is-blind-2020-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-love-is-blind-2020-backdrop.jpg new file mode 100644 index 00000000..5cea5b52 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-love-is-blind-2020-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-love-is-blind-2020-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-love-is-blind-2020-poster.jpg new file mode 100644 index 00000000..62ccf357 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-love-is-blind-2020-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-maniac-2018-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-maniac-2018-backdrop.jpg new file mode 100644 index 00000000..9d46de1d Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-maniac-2018-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-maniac-2018-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-maniac-2018-poster.jpg new file mode 100644 index 00000000..a1985217 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-maniac-2018-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-maximum-pleasure-guaranteed-2026-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-maximum-pleasure-guaranteed-2026-backdrop.jpg new file mode 100644 index 00000000..20748a70 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-maximum-pleasure-guaranteed-2026-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-maximum-pleasure-guaranteed-2026-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-maximum-pleasure-guaranteed-2026-poster.jpg new file mode 100644 index 00000000..abe1b2e2 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-maximum-pleasure-guaranteed-2026-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-minx-2022-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-minx-2022-backdrop.jpg new file mode 100644 index 00000000..bd459fde Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-minx-2022-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-minx-2022-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-minx-2022-poster.jpg new file mode 100644 index 00000000..a8797fe5 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-minx-2022-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-mussolini-son-of-the-century-2024-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-mussolini-son-of-the-century-2024-backdrop.jpg new file mode 100644 index 00000000..21674163 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-mussolini-son-of-the-century-2024-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-mussolini-son-of-the-century-2024-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-mussolini-son-of-the-century-2024-poster.jpg new file mode 100644 index 00000000..925d5c49 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-mussolini-son-of-the-century-2024-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-my-hero-academia-2016-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-my-hero-academia-2016-backdrop.jpg new file mode 100644 index 00000000..f5b2f94c Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-my-hero-academia-2016-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-my-hero-academia-2016-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-my-hero-academia-2016-poster.jpg new file mode 100644 index 00000000..cf571b93 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-my-hero-academia-2016-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-neon-genesis-evangelion-1995-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-neon-genesis-evangelion-1995-backdrop.jpg new file mode 100644 index 00000000..d80e17c1 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-neon-genesis-evangelion-1995-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-neon-genesis-evangelion-1995-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-neon-genesis-evangelion-1995-poster.jpg new file mode 100644 index 00000000..f86cd698 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-neon-genesis-evangelion-1995-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-norsemen-2016-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-norsemen-2016-backdrop.jpg new file mode 100644 index 00000000..58805e67 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-norsemen-2016-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-norsemen-2016-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-norsemen-2016-poster.jpg new file mode 100644 index 00000000..e7206b88 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-norsemen-2016-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-offspring-2010-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-offspring-2010-backdrop.jpg new file mode 100644 index 00000000..bc22e11a Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-offspring-2010-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-offspring-2010-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-offspring-2010-poster.jpg new file mode 100644 index 00000000..ae305043 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-offspring-2010-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-one-piece-2023-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-one-piece-2023-backdrop.jpg new file mode 100644 index 00000000..3fa4a282 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-one-piece-2023-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-one-piece-2023-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-one-piece-2023-poster.jpg new file mode 100644 index 00000000..286e6260 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-one-piece-2023-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-only-murders-in-the-building-2021-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-only-murders-in-the-building-2021-backdrop.jpg new file mode 100644 index 00000000..0b768d54 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-only-murders-in-the-building-2021-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-only-murders-in-the-building-2021-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-only-murders-in-the-building-2021-poster.jpg new file mode 100644 index 00000000..a6b147a4 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-only-murders-in-the-building-2021-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-outlander-blood-of-my-blood-2025-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-outlander-blood-of-my-blood-2025-backdrop.jpg new file mode 100644 index 00000000..23a242da Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-outlander-blood-of-my-blood-2025-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-outlander-blood-of-my-blood-2025-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-outlander-blood-of-my-blood-2025-poster.jpg new file mode 100644 index 00000000..930943b0 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-outlander-blood-of-my-blood-2025-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-over-the-garden-wall-2014-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-over-the-garden-wall-2014-backdrop.jpg new file mode 100644 index 00000000..43ac4428 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-over-the-garden-wall-2014-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-over-the-garden-wall-2014-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-over-the-garden-wall-2014-poster.jpg new file mode 100644 index 00000000..34b1ed84 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-over-the-garden-wall-2014-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-peaky-blinders-2013-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-peaky-blinders-2013-backdrop.jpg new file mode 100644 index 00000000..da587ec3 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-peaky-blinders-2013-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-peaky-blinders-2013-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-peaky-blinders-2013-poster.jpg new file mode 100644 index 00000000..25ceea88 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-peaky-blinders-2013-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-pluribus-2025-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-pluribus-2025-backdrop.jpg new file mode 100644 index 00000000..e64c0268 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-pluribus-2025-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-pluribus-2025-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-pluribus-2025-poster.jpg new file mode 100644 index 00000000..1ea4711b Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-pluribus-2025-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-record-of-ragnarok-2021-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-record-of-ragnarok-2021-backdrop.jpg new file mode 100644 index 00000000..d68a4060 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-record-of-ragnarok-2021-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-record-of-ragnarok-2021-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-record-of-ragnarok-2021-poster.jpg new file mode 100644 index 00000000..97d481d6 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-record-of-ragnarok-2021-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-rick-and-morty-2013-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-rick-and-morty-2013-backdrop.jpg new file mode 100644 index 00000000..1c4c0ffc Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-rick-and-morty-2013-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-rick-and-morty-2013-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-rick-and-morty-2013-poster.jpg new file mode 100644 index 00000000..b95c4890 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-rick-and-morty-2013-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-ripley-2024-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-ripley-2024-backdrop.jpg new file mode 100644 index 00000000..2e7399c1 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-ripley-2024-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-ripley-2024-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-ripley-2024-poster.jpg new file mode 100644 index 00000000..de0b32dd Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-ripley-2024-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-rivals-2024-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-rivals-2024-backdrop.jpg new file mode 100644 index 00000000..fe7025e4 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-rivals-2024-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-rivals-2024-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-rivals-2024-poster.jpg new file mode 100644 index 00000000..296ac67a Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-rivals-2024-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-rooster-2026-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-rooster-2026-backdrop.jpg new file mode 100644 index 00000000..f0f7a19e Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-rooster-2026-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-rooster-2026-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-rooster-2026-poster.jpg new file mode 100644 index 00000000..b698f8a6 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-rooster-2026-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-sakamoto-days-2025-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-sakamoto-days-2025-backdrop.jpg new file mode 100644 index 00000000..3186e89a Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-sakamoto-days-2025-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-sakamoto-days-2025-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-sakamoto-days-2025-poster.jpg new file mode 100644 index 00000000..ed9358b3 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-sakamoto-days-2025-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-say-nothing-2024-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-say-nothing-2024-backdrop.jpg new file mode 100644 index 00000000..445862dc Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-say-nothing-2024-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-say-nothing-2024-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-say-nothing-2024-poster.jpg new file mode 100644 index 00000000..cf50fc09 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-say-nothing-2024-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-secret-level-2024-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-secret-level-2024-backdrop.jpg new file mode 100644 index 00000000..54d2a13e Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-secret-level-2024-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-secret-level-2024-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-secret-level-2024-poster.jpg new file mode 100644 index 00000000..1b6e67f6 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-secret-level-2024-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-sentenced-to-be-a-hero-2025-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-sentenced-to-be-a-hero-2025-backdrop.jpg new file mode 100644 index 00000000..8d081a15 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-sentenced-to-be-a-hero-2025-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-sentenced-to-be-a-hero-2025-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-sentenced-to-be-a-hero-2025-poster.jpg new file mode 100644 index 00000000..2fb1c815 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-sentenced-to-be-a-hero-2025-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-severance-2022-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-severance-2022-backdrop.jpg new file mode 100644 index 00000000..a24c03bd Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-severance-2022-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-severance-2022-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-severance-2022-poster.jpg new file mode 100644 index 00000000..5a29d6f9 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-severance-2022-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-sex-and-the-city-1998-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-sex-and-the-city-1998-backdrop.jpg new file mode 100644 index 00000000..57beacc1 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-sex-and-the-city-1998-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-sex-and-the-city-1998-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-sex-and-the-city-1998-poster.jpg new file mode 100644 index 00000000..e546cc6d Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-sex-and-the-city-1998-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-silo-2023-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-silo-2023-backdrop.jpg new file mode 100644 index 00000000..bcc1c4b7 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-silo-2023-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-silo-2023-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-silo-2023-poster.jpg new file mode 100644 index 00000000..b493bc7b Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-silo-2023-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-six-feet-under-2001-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-six-feet-under-2001-backdrop.jpg new file mode 100644 index 00000000..4d2c02ad Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-six-feet-under-2001-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-six-feet-under-2001-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-six-feet-under-2001-poster.jpg new file mode 100644 index 00000000..559d6bd1 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-six-feet-under-2001-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-skymed-2022-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-skymed-2022-backdrop.jpg new file mode 100644 index 00000000..c7ec326b Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-skymed-2022-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-skymed-2022-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-skymed-2022-poster.jpg new file mode 100644 index 00000000..2540dad7 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-skymed-2022-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-so-you-think-you-can-dance-2008-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-so-you-think-you-can-dance-2008-backdrop.jpg new file mode 100644 index 00000000..feb777b2 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-so-you-think-you-can-dance-2008-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-so-you-think-you-can-dance-2008-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-so-you-think-you-can-dance-2008-poster.jpg new file mode 100644 index 00000000..a2e91496 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-so-you-think-you-can-dance-2008-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-south-park-1997-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-south-park-1997-backdrop.jpg new file mode 100644 index 00000000..cd0aec39 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-south-park-1997-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-south-park-1997-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-south-park-1997-poster.jpg new file mode 100644 index 00000000..d8568d54 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-south-park-1997-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-spy-x-family-2022-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-spy-x-family-2022-backdrop.jpg new file mode 100644 index 00000000..8764e6eb Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-spy-x-family-2022-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-spy-x-family-2022-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-spy-x-family-2022-poster.jpg new file mode 100644 index 00000000..fc326930 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-spy-x-family-2022-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-the-100-2014-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-the-100-2014-backdrop.jpg new file mode 100644 index 00000000..8d41cb22 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-the-100-2014-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-the-100-2014-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-the-100-2014-poster.jpg new file mode 100644 index 00000000..4d254cb0 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-the-100-2014-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-the-abbott-and-costello-show-1952-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-the-abbott-and-costello-show-1952-backdrop.jpg new file mode 100644 index 00000000..53e1d593 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-the-abbott-and-costello-show-1952-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-the-abbott-and-costello-show-1952-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-the-abbott-and-costello-show-1952-poster.jpg new file mode 100644 index 00000000..7d6768ea Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-the-abbott-and-costello-show-1952-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-the-afterparty-2022-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-the-afterparty-2022-backdrop.jpg new file mode 100644 index 00000000..72ca19db Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-the-afterparty-2022-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-the-afterparty-2022-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-the-afterparty-2022-poster.jpg new file mode 100644 index 00000000..9beacde2 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-the-afterparty-2022-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-the-baby-sitters-club-2020-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-the-baby-sitters-club-2020-backdrop.jpg new file mode 100644 index 00000000..d72d7c7e Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-the-baby-sitters-club-2020-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-the-baby-sitters-club-2020-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-the-baby-sitters-club-2020-poster.jpg new file mode 100644 index 00000000..7e4e7be2 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-the-baby-sitters-club-2020-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-the-bear-2022-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-the-bear-2022-backdrop.jpg new file mode 100644 index 00000000..9c9cca57 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-the-bear-2022-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-the-bear-2022-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-the-bear-2022-poster.jpg new file mode 100644 index 00000000..bbf0ab28 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-the-bear-2022-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-the-beast-in-me-2025-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-the-beast-in-me-2025-backdrop.jpg new file mode 100644 index 00000000..e7727a79 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-the-beast-in-me-2025-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-the-beast-in-me-2025-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-the-beast-in-me-2025-poster.jpg new file mode 100644 index 00000000..c78c5cf0 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-the-beast-in-me-2025-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-the-bold-type-2017-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-the-bold-type-2017-backdrop.jpg new file mode 100644 index 00000000..dd84deab Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-the-bold-type-2017-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-the-bold-type-2017-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-the-bold-type-2017-poster.jpg new file mode 100644 index 00000000..f663eb8b Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-the-bold-type-2017-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-the-boys-2019-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-the-boys-2019-backdrop.jpg new file mode 100644 index 00000000..a834d9fb Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-the-boys-2019-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-the-boys-2019-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-the-boys-2019-poster.jpg new file mode 100644 index 00000000..f67ff16f Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-the-boys-2019-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-the-capture-2019-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-the-capture-2019-backdrop.jpg new file mode 100644 index 00000000..42256fc1 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-the-capture-2019-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-the-capture-2019-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-the-capture-2019-poster.jpg new file mode 100644 index 00000000..a4039011 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-the-capture-2019-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-the-diplomat-2023-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-the-diplomat-2023-backdrop.jpg new file mode 100644 index 00000000..b25ab5f3 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-the-diplomat-2023-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-the-diplomat-2023-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-the-diplomat-2023-poster.jpg new file mode 100644 index 00000000..2eb48b62 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-the-diplomat-2023-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-the-durrells-2016-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-the-durrells-2016-backdrop.jpg new file mode 100644 index 00000000..3f8bdeec Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-the-durrells-2016-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-the-durrells-2016-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-the-durrells-2016-poster.jpg new file mode 100644 index 00000000..d29448bb Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-the-durrells-2016-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-the-final-problem-2026-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-the-final-problem-2026-backdrop.jpg new file mode 100644 index 00000000..61a310d8 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-the-final-problem-2026-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-the-final-problem-2026-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-the-final-problem-2026-poster.jpg new file mode 100644 index 00000000..f0332826 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-the-final-problem-2026-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-the-four-seasons-2025-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-the-four-seasons-2025-backdrop.jpg new file mode 100644 index 00000000..a358664c Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-the-four-seasons-2025-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-the-four-seasons-2025-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-the-four-seasons-2025-poster.jpg new file mode 100644 index 00000000..fd252088 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-the-four-seasons-2025-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-the-get-down-2016-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-the-get-down-2016-backdrop.jpg new file mode 100644 index 00000000..1de4a3ca Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-the-get-down-2016-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-the-get-down-2016-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-the-get-down-2016-poster.jpg new file mode 100644 index 00000000..7bb38abd Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-the-get-down-2016-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-the-hunting-wives-2025-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-the-hunting-wives-2025-backdrop.jpg new file mode 100644 index 00000000..d1758fef Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-the-hunting-wives-2025-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-the-hunting-wives-2025-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-the-hunting-wives-2025-poster.jpg new file mode 100644 index 00000000..034273eb Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-the-hunting-wives-2025-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-the-last-of-us-2023-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-the-last-of-us-2023-backdrop.jpg new file mode 100644 index 00000000..fa28e38d Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-the-last-of-us-2023-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-the-last-of-us-2023-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-the-last-of-us-2023-poster.jpg new file mode 100644 index 00000000..7da462da Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-the-last-of-us-2023-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-the-legend-of-korra-2012-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-the-legend-of-korra-2012-backdrop.jpg new file mode 100644 index 00000000..ab6086bd Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-the-legend-of-korra-2012-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-the-legend-of-korra-2012-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-the-legend-of-korra-2012-poster.jpg new file mode 100644 index 00000000..a7086d5e Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-the-legend-of-korra-2012-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-the-lord-of-the-rings-the-rings-of-power-2022-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-the-lord-of-the-rings-the-rings-of-power-2022-backdrop.jpg new file mode 100644 index 00000000..0b88fd4b Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-the-lord-of-the-rings-the-rings-of-power-2022-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-the-lord-of-the-rings-the-rings-of-power-2022-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-the-lord-of-the-rings-the-rings-of-power-2022-poster.jpg new file mode 100644 index 00000000..dc387fcd Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-the-lord-of-the-rings-the-rings-of-power-2022-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-the-lost-flowers-of-alice-hart-2023-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-the-lost-flowers-of-alice-hart-2023-backdrop.jpg new file mode 100644 index 00000000..c5d17d97 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-the-lost-flowers-of-alice-hart-2023-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-the-lost-flowers-of-alice-hart-2023-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-the-lost-flowers-of-alice-hart-2023-poster.jpg new file mode 100644 index 00000000..71407f36 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-the-lost-flowers-of-alice-hart-2023-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-the-night-manager-2016-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-the-night-manager-2016-backdrop.jpg new file mode 100644 index 00000000..327aa449 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-the-night-manager-2016-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-the-night-manager-2016-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-the-night-manager-2016-poster.jpg new file mode 100644 index 00000000..7ab2dbf5 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-the-night-manager-2016-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-the-pitt-2025-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-the-pitt-2025-backdrop.jpg new file mode 100644 index 00000000..b593444a Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-the-pitt-2025-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-the-pitt-2025-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-the-pitt-2025-poster.jpg new file mode 100644 index 00000000..ad1ec8ff Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-the-pitt-2025-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-the-tatami-galaxy-2010-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-the-tatami-galaxy-2010-backdrop.jpg new file mode 100644 index 00000000..a267b4cb Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-the-tatami-galaxy-2010-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-the-tatami-galaxy-2010-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-the-tatami-galaxy-2010-poster.jpg new file mode 100644 index 00000000..5324dc75 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-the-tatami-galaxy-2010-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-the-walk-in-2022-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-the-walk-in-2022-backdrop.jpg new file mode 100644 index 00000000..e37f8d5c Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-the-walk-in-2022-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-the-walk-in-2022-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-the-walk-in-2022-poster.jpg new file mode 100644 index 00000000..715d0c80 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-the-walk-in-2022-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-the-white-lotus-2021-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-the-white-lotus-2021-backdrop.jpg new file mode 100644 index 00000000..1f747323 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-the-white-lotus-2021-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-the-white-lotus-2021-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-the-white-lotus-2021-poster.jpg new file mode 100644 index 00000000..2f23d1fa Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-the-white-lotus-2021-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-the-witcher-2019-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-the-witcher-2019-backdrop.jpg new file mode 100644 index 00000000..acca834e Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-the-witcher-2019-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-the-witcher-2019-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-the-witcher-2019-poster.jpg new file mode 100644 index 00000000..f5eb8f59 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-the-witcher-2019-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-undercover-2019-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-undercover-2019-backdrop.jpg new file mode 100644 index 00000000..ad972c17 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-undercover-2019-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-undercover-2019-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-undercover-2019-poster.jpg new file mode 100644 index 00000000..8611eab4 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-undercover-2019-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-upload-2020-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-upload-2020-backdrop.jpg new file mode 100644 index 00000000..f350a49c Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-upload-2020-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-upload-2020-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-upload-2020-poster.jpg new file mode 100644 index 00000000..547d3b7a Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-upload-2020-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-vinland-saga-2019-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-vinland-saga-2019-backdrop.jpg new file mode 100644 index 00000000..9ae58ec4 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-vinland-saga-2019-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-vinland-saga-2019-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-vinland-saga-2019-poster.jpg new file mode 100644 index 00000000..7d0ba17a Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-vinland-saga-2019-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-widow-s-bay-2026-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-widow-s-bay-2026-backdrop.jpg new file mode 100644 index 00000000..03b1c335 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-widow-s-bay-2026-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-widow-s-bay-2026-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-widow-s-bay-2026-poster.jpg new file mode 100644 index 00000000..8c02a0d7 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-widow-s-bay-2026-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-yellowjackets-2021-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-yellowjackets-2021-backdrop.jpg new file mode 100644 index 00000000..960c2d23 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-yellowjackets-2021-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-yellowjackets-2021-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-yellowjackets-2021-poster.jpg new file mode 100644 index 00000000..c7e16a57 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-yellowjackets-2021-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-yu-yu-hakusho-1992-backdrop.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-yu-yu-hakusho-1992-backdrop.jpg new file mode 100644 index 00000000..ba65ca2d Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-yu-yu-hakusho-1992-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/assets/tv-yu-yu-hakusho-1992-poster.jpg b/app/src/debug/assets/wolfskin-discover/assets/tv-yu-yu-hakusho-1992-poster.jpg new file mode 100644 index 00000000..f5843766 Binary files /dev/null and b/app/src/debug/assets/wolfskin-discover/assets/tv-yu-yu-hakusho-1992-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-discover/fixture.json b/app/src/debug/assets/wolfskin-discover/fixture.json new file mode 100644 index 00000000..450f0ece --- /dev/null +++ b/app/src/debug/assets/wolfskin-discover/fixture.json @@ -0,0 +1 @@ +{"schemaVersion": 1, "generatedAt": "2026-11-04T20:42:12.030108+00:00", "profiles": [{"key": "justin", "name": "Justin", "initial": "J", "color": "#62c4ff", "destinations": {"Home": {"kind": "home"}, "Movies": {"kind": "library", "collection": "movies"}, "Shows": {"kind": "library", "collection": "shows"}, "Anime": {"kind": "library", "collection": "anime"}, "Discover": {"kind": "discover", "collection": "discover"}}, "movies": [{"id": "movie-the-girl-who-leapt-through-time-2006", "title": "The Girl Who Leapt Through Time", "year": 2006, "type": "movie", "runtimeSeconds": 5886, "seasonCount": null, "communityRating": 7.772, "criticRating": 87, "genres": ["Fantasy", "Animation", "Drama"], "overview": "When 17-year-old Makoto Konno gains the ability to 'leap' backwards through time, she immediately sets about improving her grades and preventing personal mishaps. However, she soon realises that changing the past\u2026", "poster": "assets/movie-the-girl-who-leapt-through-time-2006-poster.jpg", "backdrop": "assets/movie-the-girl-who-leapt-through-time-2006-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T17:39:11.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 14069, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 87, "rtCriticsLabel": "Fresh", "rtAudience": 90, "rtAudienceLabel": "Upright", "imdb": 7.6, "imdbVotes": 76917, "tmdb": 7.775, "tmdbVotes": 2345}}, {"id": "movie-locke-2014", "title": "Locke", "year": 2014, "type": "movie", "runtimeSeconds": 5090, "seasonCount": null, "communityRating": 6.891, "criticRating": 91, "genres": ["Drama", "Thriller"], "overview": "Ivan Locke has worked hard to craft a good life for himself. Tonight, that life will collapse around him. On the eve of the biggest challenge of his career, Ivan receives a phone call that sets in motion a series of\u2026", "poster": "assets/movie-locke-2014-poster.jpg", "backdrop": "assets/movie-locke-2014-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T17:38:48.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 210479, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 90, "rtCriticsLabel": "Certified Fresh", "rtAudience": 72, "rtAudienceLabel": "Upright", "imdb": 7.1, "imdbVotes": 171265, "tmdb": 6.889, "tmdbVotes": 3088}}, {"id": "movie-look-who-s-back-2015", "title": "Look Who's Back", "year": 2015, "type": "movie", "runtimeSeconds": 6936, "seasonCount": null, "communityRating": 6.793, "criticRating": null, "genres": ["Comedy"], "overview": "When Adolf Hitler reawakens at the site of his former bunker in present-day Berlin, he is mistaken for a comedian and quickly becomes a media phenomenon.", "poster": "assets/movie-look-who-s-back-2015-poster.jpg", "backdrop": "assets/movie-look-who-s-back-2015-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:27:48.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 318917, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": 81, "rtAudienceLabel": "Upright", "imdb": 7, "imdbVotes": 54672, "tmdb": 6.796, "tmdbVotes": 1990}}, {"id": "movie-memories-1995", "title": "Memories", "year": 1995, "type": "movie", "runtimeSeconds": 6805, "seasonCount": null, "communityRating": 7.465, "criticRating": null, "genres": ["Fantasy", "Animation", "Science Fiction"], "overview": "Three back-to-back anime films by three different directors make up this sci-fi trilogy three years in the making.", "poster": "assets/movie-memories-1995-poster.jpg", "backdrop": "assets/movie-memories-1995-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-30T21:36:03.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 42994, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": 82, "rtAudienceLabel": "Upright", "imdb": 7.5, "imdbVotes": 26638, "tmdb": 7.459, "tmdbVotes": 622}}, {"id": "movie-reincarnated-2012", "title": "Reincarnated", "year": 2012, "type": "movie", "runtimeSeconds": 5759, "seasonCount": null, "communityRating": 6.145, "criticRating": 28, "genres": ["Music", "Documentary"], "overview": "Evolution as an artist is often times what separates legends from the more mundane. After being heavily influenced by his experience in Jamaica \u2013 and his subsequent name change from Snoop Dogg to Snoop Lion \u2013 the LBC\u2026", "poster": "assets/movie-reincarnated-2012-poster.jpg", "backdrop": "assets/movie-reincarnated-2012-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:27:26.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 123431, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 28, "rtCriticsLabel": "Rotten", "rtAudience": 41, "rtAudienceLabel": "Spilled", "imdb": 6.2, "imdbVotes": 2563, "tmdb": 6.1, "tmdbVotes": 69}}, {"id": "movie-shipwrecked-nightmare-at-sea-2026", "title": "Shipwrecked: Nightmare at Sea", "year": 2026, "type": "movie", "runtimeSeconds": 5385, "seasonCount": null, "communityRating": 7.181, "criticRating": null, "genres": ["Documentary"], "overview": "Never-before-seen footage and survivor accounts trace the 2012 shipwreck of a luxury cruise and the disaster that ensued, in this immersive documentary.", "poster": "assets/movie-shipwrecked-nightmare-at-sea-2026-poster.jpg", "backdrop": "assets/movie-shipwrecked-nightmare-at-sea-2026-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-20T20:11:43.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 1715492, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": 6.5, "imdbVotes": 5080, "tmdb": 7.172, "tmdbVotes": 87}}, {"id": "movie-steins-gate-the-movie-load-region-of-deja-vu-2013", "title": "Steins;Gate: The Movie - Load Region of D\u00e9j\u00e0 Vu", "year": 2013, "type": "movie", "runtimeSeconds": 5403, "seasonCount": null, "communityRating": 7.8, "criticRating": null, "genres": ["Animation", "Mystery", "Sci-Fi"], "overview": "After the events of the anime, Rintarou begins to feel the repercussions of extensive time travel, and eventually completely fades from reality. Kurisu, being the only companion to remember him, now must find a way\u2026", "poster": "assets/movie-steins-gate-the-movie-load-region-of-deja-vu-2013-poster.jpg", "backdrop": "assets/movie-steins-gate-the-movie-load-region-of-deja-vu-2013-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-22T14:55:54.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}], "shows": [{"id": "tv-andor-2022", "title": "Andor", "year": 2022, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 8.293, "criticRating": null, "genres": ["Sci-Fi & Fantasy", "Action & Adventure", "Drama"], "overview": "In an era filled with danger, deception and intrigue, Cassian Andor will discover the difference he can make in the struggle against the tyrannical Galactic Empire. He embarks on a path that is destined to turn him\u2026", "poster": "assets/tv-andor-2022-poster.jpg", "backdrop": "assets/tv-andor-2022-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0432996Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 83867, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 96, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.321, "tmdbVotes": 2312}}, {"id": "tv-the-boys-2019", "title": "The Boys", "year": 2019, "type": "tv", "runtimeSeconds": null, "seasonCount": 5, "communityRating": 8.443, "criticRating": null, "genres": ["Sci-Fi & Fantasy", "Action & Adventure"], "overview": "A group of vigilantes known informally as \u201cThe Boys\u201d set out to take down corrupt superheroes with no more than blue-collar grit and a willingness to fight dirty.", "poster": "assets/tv-the-boys-2019-poster.jpg", "backdrop": "assets/tv-the-boys-2019-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0410131Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 76479, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 92, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.4, "tmdbVotes": 13628}}, {"id": "tv-californication-2007", "title": "Californication", "year": 2007, "type": "tv", "runtimeSeconds": 1680, "seasonCount": 7, "communityRating": 7.632, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "A self-loathing, alcoholic writer attempts to repair his damaged relationships with his daughter and her mother while combating sex addiction, a budding drug problem, and the seeming inability to avoid making bad\u2026", "poster": "assets/tv-californication-2007-poster.jpg", "backdrop": "assets/tv-californication-2007-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0428037Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 1215, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 57, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.62, "tmdbVotes": 1406}}, {"id": "tv-firefly-2002", "title": "Firefly", "year": 2002, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 8.347, "criticRating": null, "genres": ["Drama", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "In the year 2517, the universe is a vast frontier where lawlessness reigns and adventure awaits! Join Captain Malcolm Reynolds and his ragtag crew aboard the spaceship Serenity as they navigate the fringes of\u2026", "poster": "assets/tv-firefly-2002-poster.jpg", "backdrop": "assets/tv-firefly-2002-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-20T11:40:08.4202369Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 1437, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 77, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.351, "tmdbVotes": 2550}}, {"id": "tv-fleabag-2016", "title": "Fleabag", "year": 2016, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 8.278, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "A portrait into the mind of a dry-witted, sexual, angry, porn-watching, grief-riddled woman, trying to make sense of the world. As she hurls herself headlong at modern living, Fleabag is thrown roughly up against the\u2026", "poster": "assets/tv-fleabag-2016-poster.jpg", "backdrop": "assets/tv-fleabag-2016-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T17:42:25.4848214Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 67070, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.3, "tmdbVotes": 1993}}, {"id": "tv-gravity-falls-2012", "title": "Gravity Falls", "year": 2012, "type": "tv", "runtimeSeconds": 1320, "seasonCount": 2, "communityRating": 8.619, "criticRating": null, "genres": ["Action & Adventure", "Animation", "Comedy"], "overview": "Twin brother and sister Dipper and Mabel Pines are in for an unexpected adventure when they spend the summer helping their great uncle Stan run a tourist trap in the mysterious town of Gravity Falls, Oregon.", "poster": "assets/tv-gravity-falls-2012-poster.jpg", "backdrop": "assets/tv-gravity-falls-2012-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0435827Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 40075, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.624, "tmdbVotes": 3647}}, {"id": "tv-invincible-2021", "title": "INVINCIBLE", "year": 2021, "type": "tv", "runtimeSeconds": null, "seasonCount": 4, "communityRating": 8.638, "criticRating": null, "genres": ["Animation", "Drama", "Sci-Fi & Fantasy"], "overview": "Mark Grayson is a normal teenager except for the fact that his father is the most powerful superhero on the planet. Shortly after his seventeenth birthday, Mark begins to develop powers of his own and enters into his\u2026", "poster": "assets/tv-invincible-2021-poster.jpg", "backdrop": "assets/tv-invincible-2021-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.040159Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 95557, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 99, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.6, "tmdbVotes": 6155}}, {"id": "tv-the-legend-of-korra-2012", "title": "The Legend of Korra", "year": 2012, "type": "tv", "runtimeSeconds": 1380, "seasonCount": 4, "communityRating": 8.2, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "Avatar Korra, a headstrong, rebellious, feisty young woman who continually challenges and breaks with tradition, is on her quest to become a fully realized Avatar. In this story, the Avatar struggles to find balance\u2026", "poster": "assets/tv-the-legend-of-korra-2012-poster.jpg", "backdrop": "assets/tv-the-legend-of-korra-2012-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-20T00:19:23.2494945Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 33880, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 88, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.221, "tmdbVotes": 2482}}, {"id": "tv-love-death-robots-2019", "title": "Love, Death & Robots", "year": 2019, "type": "tv", "runtimeSeconds": null, "seasonCount": 4, "communityRating": 8.205, "criticRating": null, "genres": ["Animation", "Sci-Fi & Fantasy"], "overview": "Terrifying creatures, wicked surprises and dark comedy converge in this NSFW anthology of animated stories presented by Tim Miller and David Fincher.", "poster": "assets/tv-love-death-robots-2019-poster.jpg", "backdrop": "assets/tv-love-death-robots-2019-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-20T11:31:20.8818757Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 86831, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 89, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.203, "tmdbVotes": 4238}}, {"id": "tv-norsemen-2016", "title": "Norsemen", "year": 2016, "type": "tv", "runtimeSeconds": 1800, "seasonCount": 3, "communityRating": 7.177, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "Norsemen is an epic and humorous drama series set in the Viking Age. The residents of an 8th-century Viking village experience political rivalry, social change and innovations that upend their culture and way of life.", "poster": "assets/tv-norsemen-2016-poster.jpg", "backdrop": "assets/tv-norsemen-2016-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.034182Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 68126, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.2, "tmdbVotes": 233}}, {"id": "tv-rick-and-morty-2013", "title": "Rick and Morty", "year": 2013, "type": "tv", "runtimeSeconds": null, "seasonCount": 9, "communityRating": 8.679, "criticRating": null, "genres": ["Animation", "Comedy", "Sci-Fi & Fantasy"], "overview": "Follows a sociopathic genius scientist who drags his inherently timid grandson on adventures across the universe.", "poster": "assets/tv-rick-and-morty-2013-poster.jpg", "backdrop": "assets/tv-rick-and-morty-2013-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0419581Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 60625, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 91, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.7, "tmdbVotes": 11548}}, {"id": "tv-secret-level-2024", "title": "Secret Level", "year": 2024, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.411, "criticRating": null, "genres": ["Animation", "Sci-Fi & Fantasy", "Action & Adventure"], "overview": "Adult animated series of original short stories which are set within the worlds of beloved video games. Each episode serves as a gateway to a new adventure, unlocking exciting worlds from beloved gaming classics and\u2026", "poster": "assets/tv-secret-level-2024-poster.jpg", "backdrop": "assets/tv-secret-level-2024-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0336417Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 261579, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 65, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.392, "tmdbVotes": 612}}, {"id": "tv-silo-2023", "title": "Silo", "year": 2023, "type": "tv", "runtimeSeconds": null, "seasonCount": 3, "communityRating": 8.178, "criticRating": null, "genres": ["Sci-Fi & Fantasy", "Drama"], "overview": "In a ruined and toxic future, thousands live in a giant silo deep underground. After its sheriff breaks a cardinal rule and residents die mysteriously, engineer Juliette starts to uncover shocking secrets and the\u2026", "poster": "assets/tv-silo-2023-poster.jpg", "backdrop": "assets/tv-silo-2023-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0346526Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 125988, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 92, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.232, "tmdbVotes": 2881}}, {"id": "tv-south-park-1997", "title": "South Park", "year": 1997, "type": "tv", "runtimeSeconds": null, "seasonCount": 29, "communityRating": 8.336, "criticRating": null, "genres": ["Animation", "Comedy"], "overview": "Follow the misadventures of four irreverent grade-schoolers in the quiet, dysfunctional town of South Park, Colorado.", "poster": "assets/tv-south-park-1997-poster.jpg", "backdrop": "assets/tv-south-park-1997-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0456124Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 2190, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 80, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.332, "tmdbVotes": 5250}}], "anime": [{"id": "tv-bleach-2004", "title": "Bleach", "year": 2004, "type": "tv", "runtimeSeconds": 1440, "seasonCount": 17, "communityRating": 8.363, "criticRating": null, "genres": ["Action & Adventure", "Animation", "Sci-Fi & Fantasy"], "overview": "For as long as he can remember, Ichigo Kurosaki has been able to see ghosts. But when he meets Rukia, a Soul Reaper who battles evil spirits known as Hollows, he finds his life is changed forever. Now, with a\u2026", "poster": "assets/tv-bleach-2004-poster.jpg", "backdrop": "assets/tv-bleach-2004-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0359827Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 30984, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.4, "tmdbVotes": 2331}}, {"id": "tv-chainsaw-man-2022", "title": "Chainsaw Man", "year": 2022, "type": "tv", "runtimeSeconds": 1440, "seasonCount": 1, "communityRating": 8.515, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "Denji has a simple dream\u2014to live a happy and peaceful life, spending time with a girl he likes. This is a far cry from reality, however, as Denji is forced by the yakuza into killing devils in order to pay off his\u2026", "poster": "assets/tv-chainsaw-man-2022-poster.jpg", "backdrop": "assets/tv-chainsaw-man-2022-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-20T22:28:13.2095501Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 114410, "artwork": {"posterKind": "center_crop", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 97, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.508, "tmdbVotes": 2364}}, {"id": "tv-cyberpunk-edgerunners-2022", "title": "Cyberpunk: Edgerunners", "year": 2022, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 8.466, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "In a dystopia riddled with corruption and cybernetic implants, a talented but reckless street kid strives to become a mercenary outlaw \u2014 an edgerunner.", "poster": "assets/tv-cyberpunk-edgerunners-2022-poster.jpg", "backdrop": "assets/tv-cyberpunk-edgerunners-2022-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-20T22:28:13.2093107Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 105248, "artwork": {"posterKind": "center_crop", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 89, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.507, "tmdbVotes": 2132}}, {"id": "tv-dan-da-dan-2024", "title": "Dan Da Dan", "year": 2024, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 8.538, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Comedy"], "overview": "In a bet to prove whether ghosts or aliens exist, two high schoolers face terrifying paranormal threats, gain superpowers and maybe even fall in love?!", "poster": "assets/tv-dan-da-dan-2024-poster.jpg", "backdrop": "assets/tv-dan-da-dan-2024-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-22T10:31:16.2652252Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 240411, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.517, "tmdbVotes": 986}}, {"id": "tv-dr-stone-2019", "title": "Dr. STONE", "year": 2019, "type": "tv", "runtimeSeconds": 1440, "seasonCount": 4, "communityRating": 8.541, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Comedy"], "overview": "One fateful day, all of humanity was petrified by a blinding flash of light. After several millennia, high schooler Taiju awakens and finds himself lost in a world of statues. However, he\u2019s not alone! His\u2026", "poster": "assets/tv-dr-stone-2019-poster.jpg", "backdrop": "assets/tv-dr-stone-2019-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-20T22:28:13.2091579Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 86031, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.53, "tmdbVotes": 1814}}, {"id": "tv-frieren-beyond-journey-s-end-2023", "title": "Frieren: Beyond Journey's End", "year": 2023, "type": "tv", "runtimeSeconds": 1500, "seasonCount": 2, "communityRating": 8.803, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Drama"], "overview": "After the party of heroes defeated the Demon King, they restored peace to the land and returned to lives of solitude. Generations pass, and the elven mage Frieren comes face to face with humanity\u2019s mortality. She\u2026", "poster": "assets/tv-frieren-beyond-journey-s-end-2023-poster.jpg", "backdrop": "assets/tv-frieren-beyond-journey-s-end-2023-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-20T22:28:13.2094435Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 209867, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.826, "tmdbVotes": 1016}}, {"id": "tv-fullmetal-alchemist-brotherhood-2009", "title": "Fullmetal Alchemist: Brotherhood", "year": 2009, "type": "tv", "runtimeSeconds": 1500, "seasonCount": 1, "communityRating": 8.7, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "Disregard for alchemy\u2019s laws ripped half of Edward Elric\u2019s limbs from his body and left his brother Alphonse\u2019s soul clinging to a suit of armor. To restore what was lost, the brothers seek the Philosopher\u2019s Stone.\u2026", "poster": "assets/tv-fullmetal-alchemist-brotherhood-2009-poster.jpg", "backdrop": "assets/tv-fullmetal-alchemist-brotherhood-2009-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-20T10:27:12.3573939Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 31911, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.7, "tmdbVotes": 2633}}, {"id": "tv-jujutsu-kaisen-2020", "title": "JUJUTSU KAISEN", "year": 2020, "type": "tv", "runtimeSeconds": 1440, "seasonCount": 3, "communityRating": 8.583, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "Yuji Itadori is a boy with tremendous physical strength, though he lives a completely ordinary high school life. One day, to save a classmate who has been attacked by curses, he eats the finger of Ryomen Sukuna,\u2026", "poster": "assets/tv-jujutsu-kaisen-2020-poster.jpg", "backdrop": "assets/tv-jujutsu-kaisen-2020-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-20T22:28:13.207573Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 95479, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.574, "tmdbVotes": 4735}}, {"id": "tv-kaiju-no-8-2024", "title": "Kaiju No. 8", "year": 2024, "type": "tv", "runtimeSeconds": 1440, "seasonCount": 2, "communityRating": 8.436, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "In a world plagued by creatures known as Kaiju, Kafka Hibino aspired to enlist in The Defense Force. He makes a promise to enlist with his childhood friend, Mina Ashiro. Soon, life takes them in separate ways. While\u2026", "poster": "assets/tv-kaiju-no-8-2024-poster.jpg", "backdrop": "assets/tv-kaiju-no-8-2024-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-22T10:31:16.2646566Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 207468, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.4, "tmdbVotes": 836}}, {"id": "tv-my-hero-academia-2016", "title": "My Hero Academia", "year": 2016, "type": "tv", "runtimeSeconds": 1440, "seasonCount": 8, "communityRating": 8.607, "criticRating": null, "genres": ["Action & Adventure", "Animation", "Sci-Fi & Fantasy"], "overview": "After he saves a bully from a Villain, a normal student is granted a superpower that allows him to attend a high school training academy for Heroes.", "poster": "assets/tv-my-hero-academia-2016-poster.jpg", "backdrop": "assets/tv-my-hero-academia-2016-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-20T22:28:13.2089315Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 65930, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.6, "tmdbVotes": 5426}}, {"id": "tv-neon-genesis-evangelion-1995", "title": "Neon Genesis Evangelion", "year": 1995, "type": "tv", "runtimeSeconds": 1500, "seasonCount": 1, "communityRating": 8.568, "criticRating": null, "genres": ["Sci-Fi & Fantasy", "Animation", "Drama"], "overview": "At the turn of the century, the Angels returned to Earth, seeking to wipe out humanity in an apocalyptic fury. Devastated, mankind's last remnants moved underground to wait for the day when the Angels would come back\u2026", "poster": "assets/tv-neon-genesis-evangelion-1995-poster.jpg", "backdrop": "assets/tv-neon-genesis-evangelion-1995-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0340629Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 890, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.56, "tmdbVotes": 2205}}, {"id": "tv-record-of-ragnarok-2021", "title": "Record of Ragnarok", "year": 2021, "type": "tv", "runtimeSeconds": null, "seasonCount": 3, "communityRating": 8.402, "criticRating": null, "genres": ["Action & Adventure", "Animation", "Sci-Fi & Fantasy"], "overview": "Before eradicating humankind from the world, the gods give them one last chance to prove themselves worthy of survival. Let the Ragnarok battles begin.", "poster": "assets/tv-record-of-ragnarok-2021-poster.jpg", "backdrop": "assets/tv-record-of-ragnarok-2021-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-20T22:28:13.2085766Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 114868, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.403, "tmdbVotes": 1929}}, {"id": "tv-sakamoto-days-2025", "title": "SAKAMOTO DAYS", "year": 2025, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 8.071, "criticRating": null, "genres": ["Animation", "Comedy", "Action & Adventure"], "overview": "Once the greatest hitman of all, Taro Sakamoto retired in the name of love. But when his past catches up, he must fight to protect his beloved family.", "poster": "assets/tv-sakamoto-days-2025-poster.jpg", "backdrop": "assets/tv-sakamoto-days-2025-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-22T10:31:16.266066Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 207332, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.057, "tmdbVotes": 375}}, {"id": "tv-sentenced-to-be-a-hero-2025", "title": "Sentenced to Be a Hero", "year": 2025, "type": "tv", "runtimeSeconds": 1440, "seasonCount": 1, "communityRating": 8.338, "criticRating": null, "genres": ["Animation", "Sci-Fi & Fantasy", "Action & Adventure"], "overview": "In a world where heroism is a punishment, Xylo Forbartz, a condemned goddess killer, battles endless hordes of monstrous abominations as part of Penal Hero Unit 9004. Death is no escape, only a cycle of resurrection\u2026", "poster": "assets/tv-sentenced-to-be-a-hero-2025-poster.jpg", "backdrop": "assets/tv-sentenced-to-be-a-hero-2025-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-22T10:31:16.2666791Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 249907, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.244, "tmdbVotes": 129}}, {"id": "tv-spy-x-family-2022", "title": "SPY x FAMILY", "year": 2022, "type": "tv", "runtimeSeconds": 1440, "seasonCount": 3, "communityRating": 8.506, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Comedy"], "overview": "A spy, an assassin and a telepath come together to pose as a family, each for their own reasons, while hiding their true identities from each other.", "poster": "assets/tv-spy-x-family-2022-poster.jpg", "backdrop": "assets/tv-spy-x-family-2022-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-22T10:31:16.2670364Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 120089, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.5, "tmdbVotes": 2382}}, {"id": "tv-the-tatami-galaxy-2010", "title": "The Tatami Galaxy", "year": 2010, "type": "tv", "runtimeSeconds": 1500, "seasonCount": 2, "communityRating": 8.271, "criticRating": null, "genres": ["Animation", "Comedy", "Drama"], "overview": "When a college dropout stops for a late night bite at a mysterious ramen stand, he crosses paths with a self-proclaimed deity of matrimony. This bizarre meeting sends the young man hurtling through a horrifying\u2026", "poster": "assets/tv-the-tatami-galaxy-2010-poster.jpg", "backdrop": "assets/tv-the-tatami-galaxy-2010-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-18T05:52:51.0023256Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 36243, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.3, "tmdbVotes": 152}}, {"id": "tv-vinland-saga-2019", "title": "Vinland Saga", "year": 2019, "type": "tv", "runtimeSeconds": 1500, "seasonCount": 2, "communityRating": 8.527, "criticRating": null, "genres": ["Animation", "War & Politics", "Action & Adventure"], "overview": "For a thousand years, the Vikings have made quite a name and reputation for themselves as the strongest families with a thirst for violence. Thorfinn, the son of one of the Vikings' greatest warriors, spends his\u2026", "poster": "assets/tv-vinland-saga-2019-poster.jpg", "backdrop": "assets/tv-vinland-saga-2019-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-20T22:28:13.207389Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 88803, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.509, "tmdbVotes": 1064}}, {"id": "tv-yu-yu-hakusho-1992", "title": "Yu Yu Hakusho", "year": 1992, "type": "tv", "runtimeSeconds": 1440, "seasonCount": 4, "communityRating": 8.5, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "After dying to save a boy, delinquent tough guy Yusuke Urameshi is granted another chance at life by redeeming himself as a \"Spirit Detective.\"", "poster": "assets/tv-yu-yu-hakusho-1992-poster.jpg", "backdrop": "assets/tv-yu-yu-hakusho-1992-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-19T21:46:01.5733049Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 30669, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.475, "tmdbVotes": 519}}], "resume": [], "nextUp": [{"id": "episode-three-monsters-1992-s1e6", "title": "Three Monsters", "year": 1992, "type": "episode", "runtimeSeconds": 1421, "seasonCount": null, "communityRating": 7.4, "criticRating": null, "genres": ["Animation", "Action", "Adventure"], "overview": "Yusuke receives his first real case as Spirit Detective. Three demon thieves have muscled their way into King Yama's sacred vault, stealing the three Artifacts of Darkness. Yusuke must recover the artifacts and bring\u2026", "poster": "assets/episode-three-monsters-1992-s1e6-poster.jpg", "backdrop": "assets/episode-three-monsters-1992-s1e6-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-19T21:59:21.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "Yu Yu Hakusho", "seasonNumber": 1, "episodeNumber": 6, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}, {"id": "episode-all-hands-on-deck-class-1-a-2021-s5e1", "title": "All Hands on Deck! Class 1-A", "year": 2021, "type": "episode", "runtimeSeconds": 1433, "seasonCount": null, "communityRating": 6.938, "criticRating": null, "genres": ["Animation", "Action", "Adventure"], "overview": "There's an emergency drill at U.A. High School, and Class 1-A is requested to report for duty!", "poster": "assets/episode-all-hands-on-deck-class-1-a-2021-s5e1-poster.jpg", "backdrop": "assets/episode-all-hands-on-deck-class-1-a-2021-s5e1-backdrop.jpg", "played": false, "playCount": 2, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-22T04:04:50.0000000Z", "lastPlayedAt": "2026-10-19T17:47:09.3028025Z", "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "My Hero Academia", "seasonNumber": 5, "episodeNumber": 1, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}, {"id": "episode-erickerhead-2026-s9e6", "title": "Erickerhead", "year": 2026, "type": "episode", "runtimeSeconds": 1357, "seasonCount": null, "communityRating": 8.196, "criticRating": null, "genres": [], "overview": "Rick's stomach is mad, broh. But it's all-you-can-eat-and-drink here, broh!", "poster": "assets/episode-erickerhead-2026-s9e6-poster.jpg", "backdrop": "assets/episode-erickerhead-2026-s9e6-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-28T10:23:23.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "Rick and Morty", "seasonNumber": 9, "episodeNumber": 6, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}, {"id": "episode-girls-interrupted-2007-s1e7", "title": "Girls, Interrupted", "year": 2007, "type": "episode", "runtimeSeconds": 1642, "seasonCount": null, "communityRating": 7.4, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "Hank is disturbed by Becca's negative reaction towards the concept of happy endings, even more so when he finds out that it is partially his fault.\nMarcy comes up with the idea of a threesome with Charlie and Dani,\u2026", "poster": "assets/episode-girls-interrupted-2007-s1e7-poster.jpg", "backdrop": "assets/episode-girls-interrupted-2007-s1e7-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-05T02:46:18.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "Californication", "seasonNumber": 1, "episodeNumber": 7, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}, {"id": "episode-announcement-2022-s1e7", "title": "Announcement", "year": 2022, "type": "episode", "runtimeSeconds": 3012, "seasonCount": null, "communityRating": 7.8, "criticRating": null, "genres": ["Action", "Adventure", "Drama"], "overview": "The repercussions of the Aldhani heist reach all the way to Coruscant, while Cassian returns home.", "poster": "assets/episode-announcement-2022-s1e7-poster.jpg", "backdrop": "assets/episode-announcement-2022-s1e7-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T12:56:24.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "Andor", "seasonNumber": 1, "episodeNumber": 7, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}, {"id": "episode-south-american-biker-gangs-2026-s29e1", "title": "South American Biker Gangs", "year": 2026, "type": "episode", "runtimeSeconds": 1335, "seasonCount": null, "communityRating": 6.4, "criticRating": null, "genres": ["Animation", "Comedy"], "overview": "When e-bikes arrive in South America, the boys take over the streets and the parents of South America can hardly recognize South America.", "poster": "assets/episode-south-american-biker-gangs-2026-s29e1-poster.jpg", "backdrop": "assets/episode-south-american-biker-gangs-2026-s29e1-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-01T06:40:46.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "South Park", "seasonNumber": 29, "episodeNumber": 1, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}], "recentlyAdded": [{"id": "movie-steins-gate-the-movie-load-region-of-deja-vu-2013", "title": "Steins;Gate: The Movie - Load Region of D\u00e9j\u00e0 Vu", "year": 2013, "type": "movie", "runtimeSeconds": 5403, "seasonCount": null, "communityRating": 7.8, "criticRating": null, "genres": ["Animation", "Mystery", "Sci-Fi"], "overview": "After the events of the anime, Rintarou begins to feel the repercussions of extensive time travel, and eventually completely fades from reality. Kurisu, being the only companion to remember him, now must find a way\u2026", "poster": "assets/movie-steins-gate-the-movie-load-region-of-deja-vu-2013-poster.jpg", "backdrop": "assets/movie-steins-gate-the-movie-load-region-of-deja-vu-2013-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-22T14:55:54.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}, {"id": "tv-yu-yu-hakusho-1992", "title": "Yu Yu Hakusho", "year": 1992, "type": "tv", "runtimeSeconds": 1440, "seasonCount": 4, "communityRating": 8.5, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "After dying to save a boy, delinquent tough guy Yusuke Urameshi is granted another chance at life by redeeming himself as a \"Spirit Detective.\"", "poster": "assets/tv-yu-yu-hakusho-1992-poster.jpg", "backdrop": "assets/tv-yu-yu-hakusho-1992-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-19T21:46:01.5733049Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 30669, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.475, "tmdbVotes": 519}}, {"id": "movie-memories-1995", "title": "Memories", "year": 1995, "type": "movie", "runtimeSeconds": 6805, "seasonCount": null, "communityRating": 7.465, "criticRating": null, "genres": ["Fantasy", "Animation", "Science Fiction"], "overview": "Three back-to-back anime films by three different directors make up this sci-fi trilogy three years in the making.", "poster": "assets/movie-memories-1995-poster.jpg", "backdrop": "assets/movie-memories-1995-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-30T21:36:03.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 42994, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": 82, "rtAudienceLabel": "Upright", "imdb": 7.5, "imdbVotes": 26638, "tmdb": 7.459, "tmdbVotes": 622}}, {"id": "tv-firefly-2002", "title": "Firefly", "year": 2002, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 8.347, "criticRating": null, "genres": ["Drama", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "In the year 2517, the universe is a vast frontier where lawlessness reigns and adventure awaits! Join Captain Malcolm Reynolds and his ragtag crew aboard the spaceship Serenity as they navigate the fringes of\u2026", "poster": "assets/tv-firefly-2002-poster.jpg", "backdrop": "assets/tv-firefly-2002-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-20T11:40:08.4202369Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 1437, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 77, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.351, "tmdbVotes": 2550}}, {"id": "tv-love-death-robots-2019", "title": "Love, Death & Robots", "year": 2019, "type": "tv", "runtimeSeconds": null, "seasonCount": 4, "communityRating": 8.205, "criticRating": null, "genres": ["Animation", "Sci-Fi & Fantasy"], "overview": "Terrifying creatures, wicked surprises and dark comedy converge in this NSFW anthology of animated stories presented by Tim Miller and David Fincher.", "poster": "assets/tv-love-death-robots-2019-poster.jpg", "backdrop": "assets/tv-love-death-robots-2019-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-20T11:31:20.8818757Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 86831, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 89, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.203, "tmdbVotes": 4238}}, {"id": "tv-the-legend-of-korra-2012", "title": "The Legend of Korra", "year": 2012, "type": "tv", "runtimeSeconds": 1380, "seasonCount": 4, "communityRating": 8.2, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "Avatar Korra, a headstrong, rebellious, feisty young woman who continually challenges and breaks with tradition, is on her quest to become a fully realized Avatar. In this story, the Avatar struggles to find balance\u2026", "poster": "assets/tv-the-legend-of-korra-2012-poster.jpg", "backdrop": "assets/tv-the-legend-of-korra-2012-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-20T00:19:23.2494945Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 33880, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 88, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.221, "tmdbVotes": 2482}}, {"id": "tv-spy-x-family-2022", "title": "SPY x FAMILY", "year": 2022, "type": "tv", "runtimeSeconds": 1440, "seasonCount": 3, "communityRating": 8.506, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Comedy"], "overview": "A spy, an assassin and a telepath come together to pose as a family, each for their own reasons, while hiding their true identities from each other.", "poster": "assets/tv-spy-x-family-2022-poster.jpg", "backdrop": "assets/tv-spy-x-family-2022-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-22T10:31:16.2670364Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 120089, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.5, "tmdbVotes": 2382}}, {"id": "tv-sentenced-to-be-a-hero-2025", "title": "Sentenced to Be a Hero", "year": 2025, "type": "tv", "runtimeSeconds": 1440, "seasonCount": 1, "communityRating": 8.338, "criticRating": null, "genres": ["Animation", "Sci-Fi & Fantasy", "Action & Adventure"], "overview": "In a world where heroism is a punishment, Xylo Forbartz, a condemned goddess killer, battles endless hordes of monstrous abominations as part of Penal Hero Unit 9004. Death is no escape, only a cycle of resurrection\u2026", "poster": "assets/tv-sentenced-to-be-a-hero-2025-poster.jpg", "backdrop": "assets/tv-sentenced-to-be-a-hero-2025-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-22T10:31:16.2666791Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 249907, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.244, "tmdbVotes": 129}}, {"id": "tv-sakamoto-days-2025", "title": "SAKAMOTO DAYS", "year": 2025, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 8.071, "criticRating": null, "genres": ["Animation", "Comedy", "Action & Adventure"], "overview": "Once the greatest hitman of all, Taro Sakamoto retired in the name of love. But when his past catches up, he must fight to protect his beloved family.", "poster": "assets/tv-sakamoto-days-2025-poster.jpg", "backdrop": "assets/tv-sakamoto-days-2025-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-22T10:31:16.266066Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 207332, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.057, "tmdbVotes": 375}}, {"id": "tv-dan-da-dan-2024", "title": "Dan Da Dan", "year": 2024, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 8.538, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Comedy"], "overview": "In a bet to prove whether ghosts or aliens exist, two high schoolers face terrifying paranormal threats, gain superpowers and maybe even fall in love?!", "poster": "assets/tv-dan-da-dan-2024-poster.jpg", "backdrop": "assets/tv-dan-da-dan-2024-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-22T10:31:16.2652252Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 240411, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.517, "tmdbVotes": 986}}, {"id": "tv-kaiju-no-8-2024", "title": "Kaiju No. 8", "year": 2024, "type": "tv", "runtimeSeconds": 1440, "seasonCount": 2, "communityRating": 8.436, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "In a world plagued by creatures known as Kaiju, Kafka Hibino aspired to enlist in The Defense Force. He makes a promise to enlist with his childhood friend, Mina Ashiro. Soon, life takes them in separate ways. While\u2026", "poster": "assets/tv-kaiju-no-8-2024-poster.jpg", "backdrop": "assets/tv-kaiju-no-8-2024-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-22T10:31:16.2646566Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 207468, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.4, "tmdbVotes": 836}}, {"id": "tv-chainsaw-man-2022", "title": "Chainsaw Man", "year": 2022, "type": "tv", "runtimeSeconds": 1440, "seasonCount": 1, "communityRating": 8.515, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "Denji has a simple dream\u2014to live a happy and peaceful life, spending time with a girl he likes. This is a far cry from reality, however, as Denji is forced by the yakuza into killing devils in order to pay off his\u2026", "poster": "assets/tv-chainsaw-man-2022-poster.jpg", "backdrop": "assets/tv-chainsaw-man-2022-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-20T22:28:13.2095501Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 114410, "artwork": {"posterKind": "center_crop", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 97, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.508, "tmdbVotes": 2364}}], "discover": [{"id": "movie-the-amazing-spider-man-2012", "title": "The Amazing Spider-Man", "year": 2012, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action", "Adventure", "Science Fiction"], "overview": "A teenage Peter Parker grapples with both high school and amazing super-human crises as his alter-ego Spider-Man.", "poster": "assets/movie-the-amazing-spider-man-2012-poster.jpg", "backdrop": "assets/movie-the-amazing-spider-man-2012-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 1930, "ratings": {"rtCritics": 71, "rtCriticsLabel": "Certified Fresh", "rtAudience": 77, "rtAudienceLabel": "Upright", "imdb": 7, "imdbVotes": 791938, "tmdb": 6.768, "tmdbVotes": 19312}}, {"id": "movie-the-amazing-spider-man-2-2014", "title": "The Amazing Spider-Man 2", "year": 2014, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action", "Adventure", "Science Fiction"], "overview": "For Peter Parker, life is busy. Between taking out the bad guys as Spider-Man and spending time with the person he loves, Gwen Stacy, high school graduation cannot come quickly enough. Peter has not forgotten about\u2026", "poster": "assets/movie-the-amazing-spider-man-2-2014-poster.jpg", "backdrop": "assets/movie-the-amazing-spider-man-2-2014-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 102382, "ratings": {"rtCritics": 51, "rtCriticsLabel": "Rotten", "rtAudience": 64, "rtAudienceLabel": "Upright", "imdb": 6.6, "imdbVotes": 611981, "tmdb": 6.567, "tmdbVotes": 14919}}, {"id": "movie-the-animatrix-2003", "title": "The Animatrix", "year": 2003, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Animation", "Science Fiction"], "overview": "Straight from the creators of the groundbreaking Matrix trilogy, this collection of short animated films from the world's leading anime directors fuses computer graphics and Japanese anime to provide the background\u2026", "poster": "assets/movie-the-animatrix-2003-poster.jpg", "backdrop": "assets/movie-the-animatrix-2003-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 55931, "ratings": {"rtCritics": 86, "rtCriticsLabel": "Fresh", "rtAudience": 78, "rtAudienceLabel": "Upright", "imdb": 7.3, "imdbVotes": 91929, "tmdb": 7.221, "tmdbVotes": 1872}}, {"id": "movie-ant-man-and-the-wasp-quantumania-2023", "title": "Ant-Man and the Wasp: Quantumania", "year": 2023, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action", "Adventure", "Science Fiction"], "overview": "Super-Hero partners Scott Lang and Hope van Dyne, along with with Hope's parents Janet van Dyne and Hank Pym, and Scott's daughter Cassie Lang, find themselves exploring the Quantum Realm, interacting with strange\u2026", "poster": "assets/movie-ant-man-and-the-wasp-quantumania-2023-poster.jpg", "backdrop": "assets/movie-ant-man-and-the-wasp-quantumania-2023-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 640146, "ratings": {"rtCritics": 46, "rtCriticsLabel": "Rotten", "rtAudience": 81, "rtAudienceLabel": "Upright", "imdb": 6, "imdbVotes": 281738, "tmdb": 6.197, "tmdbVotes": 6236}}, {"id": "movie-appleseed-alpha-2014", "title": "Appleseed Alpha", "year": 2014, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Animation", "Science Fiction", "Action"], "overview": "The Third World War (2099\u20132126) devastated part of the Earth. Former nations are reforming while new powers emerge, and groups of humans struggle to survive in ruined cities. The story follows Deunan Knute and her\u2026", "poster": "assets/movie-appleseed-alpha-2014-poster.jpg", "backdrop": "assets/movie-appleseed-alpha-2014-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "center_crop", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 269650, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": 59, "rtAudienceLabel": "Spilled", "imdb": 6.5, "imdbVotes": 9689, "tmdb": 6.808, "tmdbVotes": 436}}, {"id": "movie-aquaman-and-the-lost-kingdom-2023", "title": "Aquaman and the Lost Kingdom", "year": 2023, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action", "Adventure", "Fantasy"], "overview": "Black Manta seeks revenge on Aquaman for his father's death. Wielding the Black Trident's power, he becomes a formidable foe. To defend Atlantis, Arthur (Aquaman) forges an alliance with his imprisoned brother. They\u2026", "poster": "assets/movie-aquaman-and-the-lost-kingdom-2023-poster.jpg", "backdrop": "assets/movie-aquaman-and-the-lost-kingdom-2023-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 572802, "ratings": {"rtCritics": 33, "rtCriticsLabel": "Rotten", "rtAudience": 79, "rtAudienceLabel": "Upright", "imdb": 5.6, "imdbVotes": 122422, "tmdb": 6.48, "tmdbVotes": 3748}}, {"id": "movie-the-avengers-2012", "title": "The Avengers", "year": 2012, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Science Fiction", "Action", "Adventure"], "overview": "When an unexpected enemy emerges and threatens global safety and security, Nick Fury, director of the international peacekeeping agency known as S.H.I.E.L.D., finds himself in need of a team to pull the world back\u2026", "poster": "assets/movie-the-avengers-2012-poster.jpg", "backdrop": "assets/movie-the-avengers-2012-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 24428, "ratings": {"rtCritics": 91, "rtCriticsLabel": "Certified Fresh", "rtAudience": 91, "rtAudienceLabel": "Upright", "imdb": 8, "imdbVotes": 1590693, "tmdb": 8.084, "tmdbVotes": 40262}}, {"id": "movie-avengers-confidential-black-widow-punisher-2014", "title": "Avengers Confidential: Black Widow & Punisher", "year": 2014, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Animation", "Science Fiction", "Action"], "overview": "When the Punisher takes out a black-market weapons dealer, he stumbles upon a far-reaching terrorist plot devised by a group known as Leviathan.", "poster": "assets/movie-avengers-confidential-black-widow-punisher-2014-poster.jpg", "backdrop": "assets/movie-avengers-confidential-black-widow-punisher-2014-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 257346, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": 55, "rtAudienceLabel": "Spilled", "imdb": 5.7, "imdbVotes": 5166, "tmdb": 6.368, "tmdbVotes": 303}}, {"id": "movie-avengers-age-of-ultron-2015", "title": "Avengers: Age of Ultron", "year": 2015, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action", "Adventure", "Science Fiction"], "overview": "When Tony Stark tries to jumpstart a dormant peacekeeping program, things go awry and Earth\u2019s Mightiest Heroes are put to the ultimate test as the fate of the planet hangs in the balance. As the villainous Ultron\u2026", "poster": "assets/movie-avengers-age-of-ultron-2015-poster.jpg", "backdrop": "assets/movie-avengers-age-of-ultron-2015-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 99861, "ratings": {"rtCritics": 75, "rtCriticsLabel": "Certified Fresh", "rtAudience": 82, "rtAudienceLabel": "Upright", "imdb": 7.3, "imdbVotes": 1025876, "tmdb": 7.278, "tmdbVotes": 25289}}, {"id": "movie-avengers-infinity-war-2018", "title": "Avengers: Infinity War", "year": 2018, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Adventure", "Action", "Science Fiction"], "overview": "As the Avengers and their allies have continued to protect the world from threats too large for any one hero to handle, a new danger has emerged from the cosmic shadows: Thanos. A despot of intergalactic infamy, his\u2026", "poster": "assets/movie-avengers-infinity-war-2018-poster.jpg", "backdrop": "assets/movie-avengers-infinity-war-2018-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 299536, "ratings": {"rtCritics": 85, "rtCriticsLabel": "Certified Fresh", "rtAudience": 92, "rtAudienceLabel": "Upright", "imdb": 8.4, "imdbVotes": 1421954, "tmdb": 8.246, "tmdbVotes": 33331}}, {"id": "movie-batman-ninja-2018", "title": "Batman Ninja", "year": 2018, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Animation", "Action", "Science Fiction"], "overview": "Batman, along with many of his allies and adversaries, finds himself transported to feudal Japan by Gorilla Grodd's time displacement machine.", "poster": "assets/movie-batman-ninja-2018-poster.jpg", "backdrop": "assets/movie-batman-ninja-2018-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 485942, "ratings": {"rtCritics": 84, "rtCriticsLabel": "Fresh", "rtAudience": 60, "rtAudienceLabel": "Upright", "imdb": 5.6, "imdbVotes": 24579, "tmdb": 5.9, "tmdbVotes": 1106}}, {"id": "movie-batman-v-superman-dawn-of-justice-2016", "title": "Batman v Superman: Dawn of Justice", "year": 2016, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action", "Adventure", "Fantasy"], "overview": "Fearing the actions of a god-like Super Hero left unchecked, Gotham City\u2019s own formidable, forceful vigilante takes on Metropolis\u2019s most revered, modern-day savior, while the world wrestles with what sort of hero it\u2026", "poster": "assets/movie-batman-v-superman-dawn-of-justice-2016-poster.jpg", "backdrop": "assets/movie-batman-v-superman-dawn-of-justice-2016-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 209112, "ratings": {"rtCritics": 28, "rtCriticsLabel": "Rotten", "rtAudience": 63, "rtAudienceLabel": "Upright", "imdb": 6.4, "imdbVotes": 801382, "tmdb": 6.014, "tmdbVotes": 19527}}, {"id": "movie-batman-the-dark-knight-returns-part-1-2012", "title": "Batman: The Dark Knight Returns, Part 1", "year": 2012, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Science Fiction", "Action", "Animation"], "overview": "Batman has not been seen for ten years. A new breed of criminal ravages Gotham City, forcing 55-year-old Bruce Wayne back into the cape and cowl. But, does he still have what it takes to fight crime in a new era?", "poster": "assets/movie-batman-the-dark-knight-returns-part-1-2012-poster.jpg", "backdrop": "assets/movie-batman-the-dark-knight-returns-part-1-2012-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 123025, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": 93, "rtAudienceLabel": "Upright", "imdb": 7.9, "imdbVotes": 68943, "tmdb": 7.742, "tmdbVotes": 1766}}, {"id": "movie-black-adam-2022", "title": "Black Adam", "year": 2022, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action", "Adventure", "Science Fiction"], "overview": "Nearly 5,000 years after he was bestowed with the almighty powers of the Egyptian gods\u2014and imprisoned just as quickly\u2014Black Adam is freed from his earthly tomb, ready to unleash his unique form of justice on the\u2026", "poster": "assets/movie-black-adam-2022-poster.jpg", "backdrop": "assets/movie-black-adam-2022-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 436270, "ratings": {"rtCritics": 39, "rtCriticsLabel": "Rotten", "rtAudience": 87, "rtAudienceLabel": "Upright", "imdb": 6.1, "imdbVotes": 309624, "tmdb": 6.747, "tmdbVotes": 7370}}, {"id": "movie-black-panther-2018", "title": "Black Panther", "year": 2018, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action", "Adventure", "Science Fiction"], "overview": "King T'Challa returns home to the reclusive, technologically advanced African nation of Wakanda to serve as his country's new leader. However, T'Challa soon finds that he is challenged for the throne by factions\u2026", "poster": "assets/movie-black-panther-2018-poster.jpg", "backdrop": "assets/movie-black-panther-2018-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 284054, "ratings": {"rtCritics": 96, "rtCriticsLabel": "Certified Fresh", "rtAudience": null, "rtAudienceLabel": "Spilled", "imdb": 7.3, "imdbVotes": 931120, "tmdb": 7.36, "tmdbVotes": 24190}}, {"id": "movie-black-panther-wakanda-forever-2022", "title": "Black Panther: Wakanda Forever", "year": 2022, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action", "Adventure", "Science Fiction"], "overview": "Queen Ramonda, Shuri, M\u2019Baku, Okoye and the Dora Milaje fight to protect their nation from intervening world powers in the wake of King T\u2019Challa\u2019s death. As the Wakandans strive to embrace their next chapter, the\u2026", "poster": "assets/movie-black-panther-wakanda-forever-2022-poster.jpg", "backdrop": "assets/movie-black-panther-wakanda-forever-2022-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 505642, "ratings": {"rtCritics": 84, "rtCriticsLabel": "Certified Fresh", "rtAudience": 93, "rtAudienceLabel": "Upright", "imdb": 6.6, "imdbVotes": 405088, "tmdb": 6.984, "tmdbVotes": 7920}}, {"id": "movie-blame-2017", "title": "BLAME!", "year": 2017, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action", "Drama", "Science Fiction"], "overview": "In the distant technological future, civilization has reached its ultimate Net-based form. An \"infection\" in the past caused the automated systems to spiral out of order, resulting in a multi-leveled city structure\u2026", "poster": "assets/movie-blame-2017-poster.jpg", "backdrop": "assets/movie-blame-2017-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 409421, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": 61, "rtAudienceLabel": "Upright", "imdb": 6.6, "imdbVotes": 10258, "tmdb": 6.523, "tmdbVotes": 370}}, {"id": "movie-bleach-the-movie-fade-to-black-2008", "title": "Bleach the Movie: Fade to Black", "year": 2008, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action", "Animation", "Fantasy"], "overview": "A strange disturbance in the World of the Living sends Ichigo and Kon to the Soul Society, where the Seireitei has been devastated by an explosion of reishi and Rukia is missing. Stranger still, none of the Soul\u2026", "poster": "assets/movie-bleach-the-movie-fade-to-black-2008-poster.jpg", "backdrop": "assets/movie-bleach-the-movie-fade-to-black-2008-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 17165, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": 67, "rtAudienceLabel": "Upright", "imdb": 7.1, "imdbVotes": 3693, "tmdb": 7.1, "tmdbVotes": 206}}, {"id": "tv-90-day-fiance-before-the-90-days-2017", "title": "90 Day Fianc\u00e9: Before the 90 Days", "year": 2017, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Reality"], "overview": "Follow couples who have an existing relationship online, but haven't met in person. We'll experience their journey as they travel to the other's foreign country for the first time in an attempt to establish an\u2026", "poster": "assets/tv-90-day-fiance-before-the-90-days-2017-poster.jpg", "backdrop": "assets/tv-90-day-fiance-before-the-90-days-2017-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 73319, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.5, "tmdbVotes": 45}}, {"id": "tv-90-day-fiance-the-other-way-2019", "title": "90 Day Fianc\u00e9: The Other Way", "year": 2019, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Reality"], "overview": "Americans move to a foreign country all in the name of love. Will uprooting their lives in the United States pay off, or will they be packing up and moving back to America brokenhearted?", "poster": "assets/tv-90-day-fiance-the-other-way-2019-poster.jpg", "backdrop": "assets/tv-90-day-fiance-the-other-way-2019-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 90046, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.8, "tmdbVotes": 34}}, {"id": "tv-the-100-2014", "title": "The 100", "year": 2014, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Sci-Fi & Fantasy", "Action & Adventure", "Drama"], "overview": "100 years in the future, when the Earth has been abandoned due to radioactivity, the last surviving humans live on an ark orbiting the planet \u2014 but the ark won't last forever. So the repressive regime picks 100\u2026", "poster": "assets/tv-the-100-2014-poster.jpg", "backdrop": "assets/tv-the-100-2014-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 48866, "ratings": {"rtCritics": 93, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.878, "tmdbVotes": 8855}}, {"id": "tv-the-abbott-and-costello-show-1952", "title": "The Abbott and Costello Show", "year": 1952, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Comedy"], "overview": "Bud and Lou are unemployed actors living in Mr. Fields\u2019 boarding house. Lou\u2019s girlfriend Hillary lives across the hall. Many situations arise leading to slapstick and puns.", "poster": "assets/tv-the-abbott-and-costello-show-1952-poster.jpg", "backdrop": "assets/tv-the-abbott-and-costello-show-1952-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 11821, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.2, "tmdbVotes": 22}}, {"id": "tv-accel-world-2012", "title": "Accel World", "year": 2012, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Drama"], "overview": "A short, overweight student uses the Neuro Link, an evolution of the Nerve Gear, to escape himself from the reality. But his skills in the virtual world brings him to the attention of Kuroyukihime, a popular student\u2026", "poster": "assets/tv-accel-world-2012-poster.jpg", "backdrop": "assets/tv-accel-world-2012-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "center_crop", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 43167, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.429, "tmdbVotes": 163}}, {"id": "tv-ahsoka-2023", "title": "Ahsoka", "year": 2023, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Sci-Fi & Fantasy", "Action & Adventure", "Drama"], "overview": "Former Jedi Knight Ahsoka Tano investigates an emerging threat to a vulnerable galaxy.", "poster": "assets/tv-ahsoka-2023-poster.jpg", "backdrop": "assets/tv-ahsoka-2023-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 114461, "ratings": {"rtCritics": 85, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.4, "tmdbVotes": 1351}}, {"id": "tv-american-dad-2005", "title": "American Dad!", "year": 2005, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Animation", "Comedy"], "overview": "The series focuses on an eccentric motley crew that is the Smith family and their three housemates: Father, husband, and breadwinner Stan Smith; his better half housewife, Francine Smith; their college-aged daughter,\u2026", "poster": "assets/tv-american-dad-2005-poster.jpg", "backdrop": "assets/tv-american-dad-2005-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 1433, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.022, "tmdbVotes": 2481}}, {"id": "tv-american-gods-2017", "title": "American Gods", "year": 2017, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Mystery", "Sci-Fi & Fantasy"], "overview": "An ex-con becomes the traveling partner of a conman who turns out to be one of the older gods trying to recruit troops to battle the upstart deities. Based on Neil Gaiman's fantasy novel.", "poster": "assets/tv-american-gods-2017-poster.jpg", "backdrop": "assets/tv-american-gods-2017-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 46639, "ratings": {"rtCritics": 75, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.1, "tmdbVotes": 1852}}, {"id": "tv-andromeda-2000", "title": "Andromeda", "year": 2000, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action & Adventure", "Drama", "Sci-Fi & Fantasy"], "overview": "Captain Dylan Hunt and his crew quest to restore a government that once presided over an extended peace and prosperity.", "poster": "assets/tv-andromeda-2000-poster.jpg", "backdrop": "assets/tv-andromeda-2000-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 2985, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.068, "tmdbVotes": 315}}, {"id": "tv-aqua-teen-hunger-force-2000", "title": "Aqua Teen Hunger Force", "year": 2000, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Animation", "Comedy"], "overview": "The surreal adventures of three anthropomorphic fast food items: Master Shake, Frylock and Meatwad, and their human nextdoor neighbor, Carl Brutananadilewski.", "poster": "assets/tv-aqua-teen-hunger-force-2000-poster.jpg", "backdrop": "assets/tv-aqua-teen-hunger-force-2000-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 251, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.5, "tmdbVotes": 272}}, {"id": "tv-arifureta-from-commonplace-to-world-s-strongest-2019", "title": "Arifureta: From Commonplace to World's Strongest", "year": 2019, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "Hajime Nagumo and his high school class are suddenly summoned to a fantastical land as heroes. But while most of his classmates have powerful stats and abilities, Hajime does not. Underappreciated and unprepared, he\u2026", "poster": "assets/tv-arifureta-from-commonplace-to-world-s-strongest-2019-poster.jpg", "backdrop": "assets/tv-arifureta-from-commonplace-to-world-s-strongest-2019-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 86034, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.382, "tmdbVotes": 662}}, {"id": "tv-arrow-2012", "title": "Arrow", "year": 2012, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Crime", "Drama", "Action & Adventure"], "overview": "Spoiled billionaire playboy Oliver Queen is missing and presumed dead when his yacht is lost at sea. He returns five years later a changed man, determined to clean up the city as a hooded vigilante armed with a bow.", "poster": "assets/tv-arrow-2012-poster.jpg", "backdrop": "assets/tv-arrow-2012-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 1412, "ratings": {"rtCritics": 86, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.834, "tmdbVotes": 6537}}, {"id": "tv-avatar-the-last-airbender-2024", "title": "Avatar: The Last Airbender", "year": 2024, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action & Adventure", "Sci-Fi & Fantasy", "Drama"], "overview": "A young boy known as the Avatar must master the four elemental powers to save a world at war \u2014 and fight a ruthless enemy bent on stopping him.", "poster": "assets/tv-avatar-the-last-airbender-2024-poster.jpg", "backdrop": "assets/tv-avatar-the-last-airbender-2024-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 82452, "ratings": {"rtCritics": 66, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.8, "tmdbVotes": 1406}}, {"id": "tv-avatar-seven-havens-2026", "title": "Avatar: Seven Havens", "year": 2026, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "In a world shattered by a devastating cataclysm, a young Earthbender discovers she's the new Avatar after Korra. But in this dangerous era, that title marks her as humanity's destroyer, not its savior. Hunted by both\u2026", "poster": "assets/tv-avatar-seven-havens-2026-poster.jpg", "backdrop": "assets/tv-avatar-seven-havens-2026-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 284833, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.9, "tmdbVotes": 183}}, {"id": "tv-batman-the-brave-and-the-bold-2008", "title": "Batman: The Brave and the Bold", "year": 2008, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "The Caped Crusader is teamed up with Blue Beetle, Green Arrow, Aquaman and countless others in his quest to uphold justice.", "poster": "assets/tv-batman-the-brave-and-the-bold-2008-poster.jpg", "backdrop": "assets/tv-batman-the-brave-and-the-bold-2008-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 15804, "ratings": {"rtCritics": 96, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.6, "tmdbVotes": 295}}, {"id": "tv-batwoman-2019", "title": "Batwoman", "year": 2019, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Sci-Fi & Fantasy", "Action & Adventure"], "overview": "Kate Kane, armed with a passion for social justice and a flair for speaking her mind, soars onto the streets of Gotham as Batwoman, an out lesbian and highly trained street fighter primed to snuff out the failing\u2026", "poster": "assets/tv-batwoman-2019-poster.jpg", "backdrop": "assets/tv-batwoman-2019-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 89247, "ratings": {"rtCritics": 83, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.8, "tmdbVotes": 1619}}, {"id": "tv-big-mouth-2017", "title": "Big Mouth", "year": 2017, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Comedy", "Animation"], "overview": "Teenage friends find their lives upended by the wonders and horrors of puberty in this edgy comedy from real-life pals Nick Kroll and Andrew Goldberg.", "poster": "assets/tv-big-mouth-2017-poster.jpg", "backdrop": "assets/tv-big-mouth-2017-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 74204, "ratings": {"rtCritics": 95, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.591, "tmdbVotes": 1274}}, {"id": "tv-black-lightning-2018", "title": "Black Lightning", "year": 2018, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action & Adventure", "Sci-Fi & Fantasy", "Drama"], "overview": "Jefferson Pierce is a man wrestling with a secret. As the father of two daughters and principal of a charter high school that also serves as a safe haven for young people in a New Orleans neighborhood overrun by gang\u2026", "poster": "assets/tv-black-lightning-2018-poster.jpg", "backdrop": "assets/tv-black-lightning-2018-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 71663, "ratings": {"rtCritics": 92, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.907, "tmdbVotes": 991}}], "discoverySource": {"state": "materialized_snapshot", "rankKnown": false, "selection": "First 18 alphabetically indexed movie stubs and first 18 series stubs, not ranked feed order", "observedAt": "2026-11-04T20:42:12.030108+00:00"}}, {"key": "mindel", "name": "Mindel", "initial": "M", "color": "#ff9d72", "destinations": {"Home": {"kind": "home"}, "Movies": {"kind": "library", "collection": "movies"}, "Shows": {"kind": "library", "collection": "shows"}, "Discover": {"kind": "discover", "collection": "discover"}}, "movies": [{"id": "movie-chicago-2002", "title": "Chicago", "year": 2002, "type": "movie", "runtimeSeconds": 6808, "seasonCount": null, "communityRating": 7.131, "criticRating": 87, "genres": ["Comedy", "Crime", "Drama"], "overview": "Murderesses Velma Kelly and Roxie Hart find themselves on death row together and fight for the fame that will keep them from the gallows in 1920s Chicago.", "poster": "assets/movie-chicago-2002-poster.jpg", "backdrop": "assets/movie-chicago-2002-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:24:53.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 1574, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 87, "rtCriticsLabel": "Certified Fresh", "rtAudience": 83, "rtAudienceLabel": "Upright", "imdb": 7.2, "imdbVotes": 259272, "tmdb": 7.135, "tmdbVotes": 3025}}, {"id": "movie-coherence-2014", "title": "Coherence", "year": 2014, "type": "movie", "runtimeSeconds": 5286, "seasonCount": null, "communityRating": 7.21, "criticRating": 89, "genres": ["Thriller", "Science Fiction"], "overview": "Four couples gather for dinner the night a mysterious and powerful comet passes overhead.", "poster": "assets/movie-coherence-2014-poster.jpg", "backdrop": "assets/movie-coherence-2014-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2017-08-12T23:49:00.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 220289, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 89, "rtCriticsLabel": "Certified Fresh", "rtAudience": 81, "rtAudienceLabel": "Upright", "imdb": 7.1, "imdbVotes": 180354, "tmdb": 7.208, "tmdbVotes": 3702}}, {"id": "movie-the-killing-of-a-sacred-deer-2017", "title": "The Killing of a Sacred Deer", "year": 2017, "type": "movie", "runtimeSeconds": 7262, "seasonCount": null, "communityRating": 7.003, "criticRating": 79, "genres": ["Drama", "Thriller", "Mystery"], "overview": "Dr. Steven Murphy is a renowned cardiovascular surgeon who presides over a spotless household with his wife and two children. Lurking at the margins of his idyllic suburban existence is Martin, a fatherless teen who\u2026", "poster": "assets/movie-the-killing-of-a-sacred-deer-2017-poster.jpg", "backdrop": "assets/movie-the-killing-of-a-sacred-deer-2017-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-22T21:49:26.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 399057, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 79, "rtCriticsLabel": "Certified Fresh", "rtAudience": 63, "rtAudienceLabel": "Upright", "imdb": 7, "imdbVotes": 219488, "tmdb": 7.001, "tmdbVotes": 4640}}, {"id": "movie-night-is-short-walk-on-girl-2017", "title": "Night Is Short, Walk On Girl", "year": 2017, "type": "movie", "runtimeSeconds": 5548, "seasonCount": null, "communityRating": 7.421, "criticRating": 90, "genres": ["Comedy", "Romance", "Animation"], "overview": "As a group of university students go out for a night on the town, a sophomore known only as \"The Girl with Black Hair\" experiences a series of surreal encounters with the local nightlife \u2013 all the while unaware of\u2026", "poster": "assets/movie-night-is-short-walk-on-girl-2017-poster.jpg", "backdrop": "assets/movie-night-is-short-walk-on-girl-2017-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T17:39:14.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 430214, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 90, "rtCriticsLabel": "Fresh", "rtAudience": 84, "rtAudienceLabel": "Upright", "imdb": 7.5, "imdbVotes": 7640, "tmdb": 7.4, "tmdbVotes": 267}}, {"id": "movie-thelma-louise-1991", "title": "Thelma & Louise", "year": 1991, "type": "movie", "runtimeSeconds": 7786, "seasonCount": null, "communityRating": 7.596, "criticRating": 87, "genres": ["Drama", "Crime", "Adventure"], "overview": "Taking a break from their dreary lives, close friends Thelma and Louise embark on a short weekend trip that ends in unforeseen incriminating circumstances. As fugitives, both women rediscover the strength of their\u2026", "poster": "assets/movie-thelma-louise-1991-poster.jpg", "backdrop": "assets/movie-thelma-louise-1991-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:24:40.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 1541, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 87, "rtCriticsLabel": "Certified Fresh", "rtAudience": 82, "rtAudienceLabel": "Upright", "imdb": 7.6, "imdbVotes": 197947, "tmdb": 7.594, "tmdbVotes": 4063}}, {"id": "movie-vicky-cristina-barcelona-2008", "title": "Vicky Cristina Barcelona", "year": 2008, "type": "movie", "runtimeSeconds": 5804, "seasonCount": null, "communityRating": 6.798, "criticRating": 80, "genres": ["Drama", "Romance"], "overview": "Two girlfriends on a summer holiday in Spain become enamored with the same painter, unaware that his ex-wife, with whom he has a tempestuous relationship, is about to re-enter the picture.", "poster": "assets/movie-vicky-cristina-barcelona-2008-poster.jpg", "backdrop": "assets/movie-vicky-cristina-barcelona-2008-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:25:34.0000000Z", "lastPlayedAt": "2026-08-11T20:12:57.3064089Z", "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 5038, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 80, "rtCriticsLabel": "Certified Fresh", "rtAudience": 74, "rtAudienceLabel": "Upright", "imdb": 7.1, "imdbVotes": 283286, "tmdb": 6.797, "tmdbVotes": 4164}}], "shows": [{"id": "tv-all-creatures-great-small-2020", "title": "All Creatures Great & Small", "year": 2020, "type": "tv", "runtimeSeconds": 3000, "seasonCount": 7, "communityRating": 8.2, "criticRating": null, "genres": ["Drama", "Comedy"], "overview": "The heartwarming and humorous adventures of a young country vet in the Yorkshire Dales in the 1930s. A remake of the 1978 series.", "poster": "assets/tv-all-creatures-great-small-2020-poster.jpg", "backdrop": "assets/tv-all-creatures-great-small-2020-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-11-04T20:13:03.4266156Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 108255, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 99, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.2, "tmdbVotes": 168}}, {"id": "tv-back-to-life-2019", "title": "Back to Life", "year": 2019, "type": "tv", "runtimeSeconds": 1500, "seasonCount": 2, "communityRating": 7.367, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "When Miri Matteson returns home after eighteen years, can she integrate back into her old life? With a terrible event from her past hanging over her, it won\u2019t be easy.", "poster": "assets/tv-back-to-life-2019-poster.jpg", "backdrop": "assets/tv-back-to-life-2019-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0688758Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 88510, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.4, "tmdbVotes": 65}}, {"id": "tv-big-boys-2022", "title": "Big Boys", "year": 2022, "type": "tv", "runtimeSeconds": 1440, "seasonCount": 3, "communityRating": 7.6, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "Two boys from very different ends of the 'spectrum of masculinity' become best friends at Brent University freshers' week; in their first year of uni, they explore, experiment and try to discover themselves, helping\u2026", "poster": "assets/tv-big-boys-2022-poster.jpg", "backdrop": "assets/tv-big-boys-2022-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-11-04T20:25:58.2156837Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 202851, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.6, "tmdbVotes": 49}}, {"id": "tv-call-the-midwife-2012", "title": "Call the Midwife", "year": 2012, "type": "tv", "runtimeSeconds": 3120, "seasonCount": 15, "communityRating": 7.5, "criticRating": null, "genres": ["Drama"], "overview": "Drama following the lives of a group of midwives working in the poverty-stricken East End of London during the 1950s, based on the best-selling memoirs of Jennifer Worth.", "poster": "assets/tv-call-the-midwife-2012-poster.jpg", "backdrop": "assets/tv-call-the-midwife-2012-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0377216Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 39793, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.577, "tmdbVotes": 267}}, {"id": "tv-derry-girls-2018", "title": "Derry Girls", "year": 2018, "type": "tv", "runtimeSeconds": 1380, "seasonCount": 3, "communityRating": 8.144, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "Amidst the political conflict of Northern Ireland in the 1990s, five secondary school students square off with the universal challenges of being a teenager.", "poster": "assets/tv-derry-girls-2018-poster.jpg", "backdrop": "assets/tv-derry-girls-2018-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-02T20:01:55.8955537Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 76148, "artwork": {"posterKind": "center_crop", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 99, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.138, "tmdbVotes": 454}}, {"id": "tv-desperate-housewives-2004", "title": "Desperate Housewives", "year": 2004, "type": "tv", "runtimeSeconds": 2520, "seasonCount": 8, "communityRating": 7.896, "criticRating": null, "genres": ["Mystery", "Drama", "Comedy"], "overview": "Looking down on her friends and family isn't a way of life for Mary Alice Young... it's a way of death. One day, in her perfect house, in the loveliest of suburbs, Mary Alice ended it all. Now she's taking us into\u2026", "poster": "assets/tv-desperate-housewives-2004-poster.jpg", "backdrop": "assets/tv-desperate-housewives-2004-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-29T20:56:40.3505596Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 693, "artwork": {"posterKind": "poster", "backdropKind": "center_crop"}, "ratings": {"rtCritics": 72, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.896, "tmdbVotes": 2171}}, {"id": "tv-the-diplomat-2023", "title": "The Diplomat", "year": 2023, "type": "tv", "runtimeSeconds": null, "seasonCount": 4, "communityRating": 7.569, "criticRating": null, "genres": ["Drama", "War & Politics"], "overview": "Amid an international crisis, a US diplomat contends with her high-profile job as ambassador to the UK and her strained marriage to a political star.", "poster": "assets/tv-the-diplomat-2023-poster.jpg", "backdrop": "assets/tv-the-diplomat-2023-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0640348Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 203857, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 93, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.652, "tmdbVotes": 521}}, {"id": "tv-the-durrells-2016", "title": "The Durrells", "year": 2016, "type": "tv", "runtimeSeconds": 2760, "seasonCount": 4, "communityRating": 7.402, "criticRating": null, "genres": ["Drama", "Comedy", "Family"], "overview": "In 1935, financially strapped widow Louisa Durrell, whose life has fallen apart, decides to move from England, with her four children (three sons, one daughter), to the island of Corfu, Greece. Once there, the family\u2026", "poster": "assets/tv-the-durrells-2016-poster.jpg", "backdrop": "assets/tv-the-durrells-2016-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0619436Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 66134, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 94, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.4, "tmdbVotes": 127}}, {"id": "tv-etoile-2025", "title": "\u00c9toile", "year": 2025, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.197, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "In an ambitious gambit to save their storied institutions, two world-renowned ballet companies in New York City and Paris swap their most talented stars.", "poster": "assets/tv-etoile-2025-poster.jpg", "backdrop": "assets/tv-etoile-2025-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0601383Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 225383, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 86, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.3, "tmdbVotes": 40}}, {"id": "tv-gilmore-girls-2000", "title": "Gilmore Girls", "year": 2000, "type": "tv", "runtimeSeconds": 2640, "seasonCount": 7, "communityRating": 7.893, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "Set in the charming town of Stars Hollow, Connecticut, the series follows the captivating lives of Lorelai and Rory Gilmore, a mother/daughter pair who have a relationship most people only dream of.", "poster": "assets/tv-gilmore-girls-2000-poster.jpg", "backdrop": "assets/tv-gilmore-girls-2000-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0631035Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 4586, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.9, "tmdbVotes": 1339}}, {"id": "tv-ginny-georgia-2021", "title": "Ginny & Georgia", "year": 2021, "type": "tv", "runtimeSeconds": null, "seasonCount": 3, "communityRating": 8.026, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "Free-spirited Georgia and her two kids, Ginny and Austin, move north in search of a fresh start but find that the road to new beginnings can be bumpy.", "poster": "assets/tv-ginny-georgia-2021-poster.jpg", "backdrop": "assets/tv-ginny-georgia-2021-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0694828Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 117581, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 68, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8, "tmdbVotes": 1840}}, {"id": "tv-hellcats-2010", "title": "Hellcats", "year": 2010, "type": "tv", "runtimeSeconds": 2460, "seasonCount": 1, "communityRating": 7.5, "criticRating": null, "genres": ["Drama"], "overview": "Pre-law student Marti Perkins' world is flipped upside down when she loses her scholarship, and realizes the only way she can stay in school is by reigniting her dormant teen gymnastic skills to win a place on Lancer\u2026", "poster": "assets/tv-hellcats-2010-poster.jpg", "backdrop": "assets/tv-hellcats-2010-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-22T20:39:02.7719318Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 32504, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 65, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.5, "tmdbVotes": 116}}, {"id": "tv-high-potential-2024", "title": "High Potential", "year": 2024, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 8.201, "criticRating": null, "genres": ["Drama", "Crime", "Mystery"], "overview": "Morgan is a single mom with an exceptional mind, whose unconventional knack for solving crimes leads to an unusual and unstoppable partnership with a by-the-book seasoned detective.", "poster": "assets/tv-high-potential-2024-poster.jpg", "backdrop": "assets/tv-high-potential-2024-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0686091Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 226637, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 98, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.3, "tmdbVotes": 707}}, {"id": "tv-how-to-get-to-heaven-from-belfast-2026", "title": "How to Get to Heaven from Belfast", "year": 2026, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.027, "criticRating": null, "genres": ["Mystery", "Comedy", "Drama"], "overview": "Three lifelong pals embark on a chaotic quest to solve the mystery of their old friend's suspicious death and keep their own dark secret under wraps.", "poster": "assets/tv-how-to-get-to-heaven-from-belfast-2026-poster.jpg", "backdrop": "assets/tv-how-to-get-to-heaven-from-belfast-2026-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0683192Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 233079, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 95, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.063, "tmdbVotes": 95}}, {"id": "tv-the-hunting-wives-2025", "title": "The Hunting Wives", "year": 2025, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 6.932, "criticRating": null, "genres": ["Drama", "Mystery"], "overview": "Sophie trades New England for East Texas and falls into a wealthy socialite's magnetic orbit \u2014 where a clique of housewives hide deadly secrets.", "poster": "assets/tv-the-hunting-wives-2025-poster.jpg", "backdrop": "assets/tv-the-hunting-wives-2025-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-20T19:42:46.3227892Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 244447, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 81, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.964, "tmdbVotes": 112}}, {"id": "tv-the-lost-flowers-of-alice-hart-2023", "title": "The Lost Flowers of Alice Hart", "year": 2023, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.634, "criticRating": null, "genres": ["Drama", "Mystery"], "overview": "After losing her parents in a mysterious fire, nine-year-old Alice Hart is raised by her grandmother June on a flower farm where she learns there are secrets within secrets. But years on, an unearthed betrayal sees\u2026", "poster": "assets/tv-the-lost-flowers-of-alice-hart-2023-poster.jpg", "backdrop": "assets/tv-the-lost-flowers-of-alice-hart-2023-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0607236Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 125816, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 82, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.64, "tmdbVotes": 161}}, {"id": "tv-love-is-blind-2020", "title": "Love Is Blind", "year": 2020, "type": "tv", "runtimeSeconds": null, "seasonCount": 11, "communityRating": 6.261, "criticRating": null, "genres": ["Reality"], "overview": "Nick and Vanessa Lachey host this social experiment where single men and women look for love and get engaged, all before meeting in person.", "poster": "assets/tv-love-is-blind-2020-poster.jpg", "backdrop": "assets/tv-love-is-blind-2020-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-22T17:11:08.2447226Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 99353, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 66, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.233, "tmdbVotes": 118}}, {"id": "tv-maximum-pleasure-guaranteed-2026", "title": "Maximum Pleasure Guaranteed", "year": 2026, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 6.676, "criticRating": null, "genres": ["Comedy"], "overview": "A newly divorced mom falls down a dangerous rabbit hole of blackmail, murder, and youth soccer.", "poster": "assets/tv-maximum-pleasure-guaranteed-2026-poster.jpg", "backdrop": "assets/tv-maximum-pleasure-guaranteed-2026-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-07T21:04:02.8277793Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 285404, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 93, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.799, "tmdbVotes": 92}}, {"id": "tv-minx-2022", "title": "Minx", "year": 2022, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 6.833, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "An earnest young feminist joins forces with a low-rent publisher to make the world's first erotic magazine for women.", "poster": "assets/tv-minx-2022-poster.jpg", "backdrop": "assets/tv-minx-2022-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0653613Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 118303, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 93, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.9, "tmdbVotes": 123}}, {"id": "tv-offspring-2010", "title": "Offspring", "year": 2010, "type": "tv", "runtimeSeconds": 3600, "seasonCount": 7, "communityRating": 6.9, "criticRating": null, "genres": ["Drama"], "overview": "An exuberant drama set in Melbourne's Fitzroy, centering on Nina Proudman and her struggle to deal with her fabulously messy family, her hunt for a decent love life and her tendency to overthink and fly off into fantasy.", "poster": "assets/tv-offspring-2010-poster.jpg", "backdrop": "assets/tv-offspring-2010-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0664581Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 33155, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.9, "tmdbVotes": 27}}, {"id": "tv-only-murders-in-the-building-2021", "title": "Only Murders in the Building", "year": 2021, "type": "tv", "runtimeSeconds": null, "seasonCount": 5, "communityRating": 8.398, "criticRating": null, "genres": ["Comedy", "Mystery", "Crime"], "overview": "Three strangers share an obsession with true crime and suddenly find themselves wrapped up in one.", "poster": "assets/tv-only-murders-in-the-building-2021-poster.jpg", "backdrop": "assets/tv-only-murders-in-the-building-2021-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-11-04T20:25:58.2163301Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 107113, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 95, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.398, "tmdbVotes": 2333}}, {"id": "tv-outlander-blood-of-my-blood-2025", "title": "Outlander: Blood of My Blood", "year": 2025, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 8.542, "criticRating": null, "genres": ["Drama"], "overview": "From the battlefields of World War I to the rugged Highlands of 18th century Scotland, two fated couples must defy the forces that seek to tear them apart, unfolding in surprising and unforeseen ways in this romantic\u2026", "poster": "assets/tv-outlander-blood-of-my-blood-2025-poster.jpg", "backdrop": "assets/tv-outlander-blood-of-my-blood-2025-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0691373Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 207484, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 94, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.738, "tmdbVotes": 124}}, {"id": "tv-rivals-2024", "title": "Rivals", "year": 2024, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 7.44, "criticRating": null, "genres": ["Drama"], "overview": "It is 1986 and Britain is booming. \"Rivals\" dives headfirst into the cutthroat world of TV where hair-dos are big and ambitions are even bigger. Deals are brokered in boardrooms, as well as bedrooms. Nobody can be\u2026", "poster": "assets/tv-rivals-2024-poster.jpg", "backdrop": "assets/tv-rivals-2024-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0645815Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 208921, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 96, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.4, "tmdbVotes": 93}}, {"id": "tv-rooster-2026", "title": "Rooster", "year": 2026, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.431, "criticRating": null, "genres": ["Comedy"], "overview": "On a college campus, an author navigates a complicated relationship with his daughter.", "poster": "assets/tv-rooster-2026-poster.jpg", "backdrop": "assets/tv-rooster-2026-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.063389Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 254953, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 88, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.423, "tmdbVotes": 144}}, {"id": "tv-sex-and-the-city-1998", "title": "Sex and the City", "year": 1998, "type": "tv", "runtimeSeconds": null, "seasonCount": 6, "communityRating": 7.365, "criticRating": null, "genres": ["Drama", "Comedy"], "overview": "Based on the bestselling book by Candace Bushnell, Sex and the City tells the story of four best friends, all single and in their late thirties, as they pursue their careers and talk about their sex lives, all while\u2026", "poster": "assets/tv-sex-and-the-city-1998-poster.jpg", "backdrop": "assets/tv-sex-and-the-city-1998-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0679324Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 105, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 70, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.351, "tmdbVotes": 2220}}, {"id": "tv-skymed-2022", "title": "SkyMed", "year": 2022, "type": "tv", "runtimeSeconds": 2640, "seasonCount": 4, "communityRating": 6.665, "criticRating": null, "genres": ["Drama"], "overview": "Life, death and drama at 20,000 feet. The series weaves together intense character journeys and high-stakes medical rescues, as we follow the triumphs, heartbreaks and tribulations of budding nurses and pilots flying\u2026", "poster": "assets/tv-skymed-2022-poster.jpg", "backdrop": "assets/tv-skymed-2022-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-22T19:44:29.2431354Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 133908, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.699, "tmdbVotes": 98}}, {"id": "tv-so-you-think-you-can-dance-2008", "title": "So You Think You Can Dance", "year": 2008, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 9.8, "criticRating": null, "genres": ["Family", "Reality"], "overview": "So You Think You Can Dance is a joint Belgian-Dutch dance competition show broadcast on RTL 5 and vtm television stations. The first season was broadcast only in the Netherlands, whereas starting with season 2, the\u2026", "poster": "assets/tv-so-you-think-you-can-dance-2008-poster.jpg", "backdrop": "assets/tv-so-you-think-you-can-dance-2008-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-23T11:11:35.4124418Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 40231, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 9.8, "tmdbVotes": 4}}, {"id": "tv-the-white-lotus-2021", "title": "The White Lotus", "year": 2021, "type": "tv", "runtimeSeconds": null, "seasonCount": 3, "communityRating": 7.597, "criticRating": null, "genres": ["Comedy", "Drama", "Mystery"], "overview": "Follow the exploits of various guests and employees at an exclusive tropical resort over the span of a week as with each passing day, a darker complexity emerges in these picture-perfect travelers, the hotel\u2019s\u2026", "poster": "assets/tv-the-white-lotus-2021-poster.jpg", "backdrop": "assets/tv-the-white-lotus-2021-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-20T02:45:52.8742674Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 111803, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 90, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.599, "tmdbVotes": 1604}}, {"id": "tv-yellowjackets-2021", "title": "Yellowjackets", "year": 2021, "type": "tv", "runtimeSeconds": null, "seasonCount": 3, "communityRating": 7.431, "criticRating": null, "genres": ["Drama", "Mystery"], "overview": "This equal parts survival epic, psychological horror story and coming-of-age drama tells the saga of a team of wildly talented high school girls soccer players who become the (un)lucky survivors of a plane crash deep\u2026", "poster": "assets/tv-yellowjackets-2021-poster.jpg", "backdrop": "assets/tv-yellowjackets-2021-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-11-04T20:31:47.4592756Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 117488, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 92, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.431, "tmdbVotes": 1070}}], "anime": [], "resume": [{"id": "episode-sex-and-the-country-2001-s4e9", "title": "Sex and the Country", "year": 2001, "type": "episode", "runtimeSeconds": 1751, "seasonCount": null, "communityRating": 5.9, "criticRating": null, "genres": ["Comedy", "Drama", "Romance"], "overview": "Carrie is dragged to Aidan's country home in Suffern, New York. Charlotte visits the MacDougal \"compound\" in Connecticut. Miranda yells at Steve when he tells her he has testicular cancer but has no clue about his\u2026", "poster": "assets/episode-sex-and-the-country-2001-s4e9-poster.jpg", "backdrop": "assets/episode-sex-and-the-country-2001-s4e9-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 96.08, "progress": 0.0549, "addedAt": "2026-07-17T10:53:15.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "Sex and the City", "seasonNumber": 4, "episodeNumber": 9, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}], "nextUp": [{"id": "episode-what-more-do-i-need-2008-s5e7", "title": "What More Do I Need?", "year": 2008, "type": "episode", "runtimeSeconds": 2521, "seasonCount": null, "communityRating": 8, "criticRating": null, "genres": ["Comedy", "Drama", "Mystery"], "overview": "Lynette and Tom uncover the unsettling truth about son Porter. Gabrielle suspects Carlos' best client, Virginia, has ulterior motives. Bree's moment of weakness could bring her great embarrassment and shame.\u2026", "poster": "assets/episode-what-more-do-i-need-2008-s5e7-poster.jpg", "backdrop": "assets/episode-what-more-do-i-need-2008-s5e7-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-29T14:37:28.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "Desperate Housewives", "seasonNumber": 5, "episodeNumber": 7, "artwork": {"posterKind": "center_crop", "backdropKind": "backdrop"}}, {"id": "episode-new-day-2021-s1e2", "title": "New Day", "year": 2021, "type": "episode", "runtimeSeconds": 3445, "seasonCount": null, "communityRating": 7.143, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "A cautiously optimistic Belinda walks a fine line with Tanya, while Armond brainstorms ways to deal with Shane. After her husband belittles her work, Rachel approaches Nicole for advice. Paula and Olivia lose track\u2026", "poster": "assets/episode-new-day-2021-s1e2-poster.jpg", "backdrop": "assets/episode-new-day-2021-s1e2-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-19T22:18:57.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "The White Lotus", "seasonNumber": 1, "episodeNumber": 2, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}, {"id": "episode-the-uncomfortability-2010-s1e2", "title": "The Uncomfortability", "year": 2010, "type": "episode", "runtimeSeconds": 2687, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "Nina's insecurities are revealed when a patient poses an awkward request. Meanwhile Geraldine decides to try online dating, and Jimmy is an unexpected saviour to Cherie and Darcy.", "poster": "assets/episode-the-uncomfortability-2010-s1e2-poster.jpg", "backdrop": "assets/episode-the-uncomfortability-2010-s1e2-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T11:47:42.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "Offspring", "seasonNumber": 1, "episodeNumber": 2, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}, {"id": "episode-episode-2-2016-s1e2", "title": "Episode 2", "year": 2016, "type": "episode", "runtimeSeconds": 2766, "seasonCount": null, "communityRating": 8.3, "criticRating": null, "genres": ["Biography", "Comedy", "Drama"], "overview": "Larry falls dangerously ill, and it falls to Theo and his neighbour Sven to put their rudimentary medical skills to the task of saving his life. The family's money worries continue, but Spiros brings them good news\u2026", "poster": "assets/episode-episode-2-2016-s1e2-poster.jpg", "backdrop": "assets/episode-episode-2-2016-s1e2-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-31T07:29:17.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "The Durrells", "seasonNumber": 1, "episodeNumber": 2, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}, {"id": "episode-remembrance-day-2026-s2e1", "title": "Remembrance Day", "year": 2026, "type": "episode", "runtimeSeconds": 3822, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Fantasy", "Romance"], "overview": "The fiery crosses have been lit across the Highlands; lovers must part, as the call to arms brings friends and enemies home and the Jacobite Rebellion begins in earnest.", "poster": "assets/episode-remembrance-day-2026-s2e1-poster.jpg", "backdrop": "assets/episode-remembrance-day-2026-s2e1-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-19T03:50:07.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "Outlander: Blood of My Blood", "seasonNumber": 2, "episodeNumber": 1, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}, {"id": "episode-one-of-us-2024-s1e7", "title": "One of Us", "year": 2024, "type": "episode", "runtimeSeconds": 2555, "seasonCount": null, "communityRating": 7.7, "criticRating": null, "genres": [], "overview": "Morgan agrees to show Ava around the LAPD, but things quickly take a dangerous turn when the precinct is held hostage by the friends of a recently convicted man. Can Morgan and the detectives outsmart their captors\u2026", "poster": "assets/episode-one-of-us-2024-s1e7-poster.jpg", "backdrop": "assets/episode-one-of-us-2024-s1e7-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T13:57:22.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "High Potential", "seasonNumber": 1, "episodeNumber": 7, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}, {"id": "episode-the-breakup-part-2-2001-s1e17", "title": "The Breakup, Part 2", "year": 2001, "type": "episode", "runtimeSeconds": 2669, "seasonCount": null, "communityRating": 7.4, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "After recent events, Rory keeps busy, refusing to give in to self-pity. Meanwhile, Stars Hollow's residents rally around her, much to her dismay.", "poster": "assets/episode-the-breakup-part-2-2001-s1e17-poster.jpg", "backdrop": "assets/episode-the-breakup-part-2-2001-s1e17-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T11:28:05.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "Gilmore Girls", "seasonNumber": 1, "episodeNumber": 17, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}, {"id": "episode-i-heart-ny-2002-s4e18", "title": "I Heart NY", "year": 2002, "type": "episode", "runtimeSeconds": 1905, "seasonCount": null, "communityRating": 6.667, "criticRating": null, "genres": ["Comedy", "Drama", "Romance"], "overview": "Carrie is shocked to find out that Big is moving to Napa, California and plans to give him a New York send-off. Charlotte begins dating another recent divorc\u00e9. Miranda prepares for the new baby as her delivery date\u2026", "poster": "assets/episode-i-heart-ny-2002-s4e18-poster.jpg", "backdrop": "assets/episode-i-heart-ny-2002-s4e18-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T12:35:14.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "Sex and the City", "seasonNumber": 4, "episodeNumber": 18, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}], "recentlyAdded": [{"id": "tv-yellowjackets-2021", "title": "Yellowjackets", "year": 2021, "type": "tv", "runtimeSeconds": null, "seasonCount": 3, "communityRating": 7.431, "criticRating": null, "genres": ["Drama", "Mystery"], "overview": "This equal parts survival epic, psychological horror story and coming-of-age drama tells the saga of a team of wildly talented high school girls soccer players who become the (un)lucky survivors of a plane crash deep\u2026", "poster": "assets/tv-yellowjackets-2021-poster.jpg", "backdrop": "assets/tv-yellowjackets-2021-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-11-04T20:31:47.4592756Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 117488, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 92, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.431, "tmdbVotes": 1070}}, {"id": "tv-only-murders-in-the-building-2021", "title": "Only Murders in the Building", "year": 2021, "type": "tv", "runtimeSeconds": null, "seasonCount": 5, "communityRating": 8.398, "criticRating": null, "genres": ["Comedy", "Mystery", "Crime"], "overview": "Three strangers share an obsession with true crime and suddenly find themselves wrapped up in one.", "poster": "assets/tv-only-murders-in-the-building-2021-poster.jpg", "backdrop": "assets/tv-only-murders-in-the-building-2021-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-11-04T20:25:58.2163301Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 107113, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 95, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.398, "tmdbVotes": 2333}}, {"id": "tv-big-boys-2022", "title": "Big Boys", "year": 2022, "type": "tv", "runtimeSeconds": 1440, "seasonCount": 3, "communityRating": 7.6, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "Two boys from very different ends of the 'spectrum of masculinity' become best friends at Brent University freshers' week; in their first year of uni, they explore, experiment and try to discover themselves, helping\u2026", "poster": "assets/tv-big-boys-2022-poster.jpg", "backdrop": "assets/tv-big-boys-2022-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-11-04T20:25:58.2156837Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 202851, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.6, "tmdbVotes": 49}}, {"id": "tv-all-creatures-great-small-2020", "title": "All Creatures Great & Small", "year": 2020, "type": "tv", "runtimeSeconds": 3000, "seasonCount": 7, "communityRating": 8.2, "criticRating": null, "genres": ["Drama", "Comedy"], "overview": "The heartwarming and humorous adventures of a young country vet in the Yorkshire Dales in the 1930s. A remake of the 1978 series.", "poster": "assets/tv-all-creatures-great-small-2020-poster.jpg", "backdrop": "assets/tv-all-creatures-great-small-2020-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-11-04T20:13:03.4266156Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 108255, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 99, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.2, "tmdbVotes": 168}}, {"id": "movie-the-killing-of-a-sacred-deer-2017", "title": "The Killing of a Sacred Deer", "year": 2017, "type": "movie", "runtimeSeconds": 7262, "seasonCount": null, "communityRating": 7.003, "criticRating": 79, "genres": ["Drama", "Thriller", "Mystery"], "overview": "Dr. Steven Murphy is a renowned cardiovascular surgeon who presides over a spotless household with his wife and two children. Lurking at the margins of his idyllic suburban existence is Martin, a fatherless teen who\u2026", "poster": "assets/movie-the-killing-of-a-sacred-deer-2017-poster.jpg", "backdrop": "assets/movie-the-killing-of-a-sacred-deer-2017-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-22T21:49:26.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 399057, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 79, "rtCriticsLabel": "Certified Fresh", "rtAudience": 63, "rtAudienceLabel": "Upright", "imdb": 7, "imdbVotes": 219488, "tmdb": 7.001, "tmdbVotes": 4640}}, {"id": "tv-derry-girls-2018", "title": "Derry Girls", "year": 2018, "type": "tv", "runtimeSeconds": 1380, "seasonCount": 3, "communityRating": 8.144, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "Amidst the political conflict of Northern Ireland in the 1990s, five secondary school students square off with the universal challenges of being a teenager.", "poster": "assets/tv-derry-girls-2018-poster.jpg", "backdrop": "assets/tv-derry-girls-2018-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-02T20:01:55.8955537Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 76148, "artwork": {"posterKind": "center_crop", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 99, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.138, "tmdbVotes": 454}}, {"id": "tv-so-you-think-you-can-dance-2008", "title": "So You Think You Can Dance", "year": 2008, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 9.8, "criticRating": null, "genres": ["Family", "Reality"], "overview": "So You Think You Can Dance is a joint Belgian-Dutch dance competition show broadcast on RTL 5 and vtm television stations. The first season was broadcast only in the Netherlands, whereas starting with season 2, the\u2026", "poster": "assets/tv-so-you-think-you-can-dance-2008-poster.jpg", "backdrop": "assets/tv-so-you-think-you-can-dance-2008-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-23T11:11:35.4124418Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 40231, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 9.8, "tmdbVotes": 4}}, {"id": "tv-hellcats-2010", "title": "Hellcats", "year": 2010, "type": "tv", "runtimeSeconds": 2460, "seasonCount": 1, "communityRating": 7.5, "criticRating": null, "genres": ["Drama"], "overview": "Pre-law student Marti Perkins' world is flipped upside down when she loses her scholarship, and realizes the only way she can stay in school is by reigniting her dormant teen gymnastic skills to win a place on Lancer\u2026", "poster": "assets/tv-hellcats-2010-poster.jpg", "backdrop": "assets/tv-hellcats-2010-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-22T20:39:02.7719318Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 32504, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 65, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.5, "tmdbVotes": 116}}, {"id": "tv-skymed-2022", "title": "SkyMed", "year": 2022, "type": "tv", "runtimeSeconds": 2640, "seasonCount": 4, "communityRating": 6.665, "criticRating": null, "genres": ["Drama"], "overview": "Life, death and drama at 20,000 feet. The series weaves together intense character journeys and high-stakes medical rescues, as we follow the triumphs, heartbreaks and tribulations of budding nurses and pilots flying\u2026", "poster": "assets/tv-skymed-2022-poster.jpg", "backdrop": "assets/tv-skymed-2022-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-22T19:44:29.2431354Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 133908, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.699, "tmdbVotes": 98}}, {"id": "tv-love-is-blind-2020", "title": "Love Is Blind", "year": 2020, "type": "tv", "runtimeSeconds": null, "seasonCount": 11, "communityRating": 6.261, "criticRating": null, "genres": ["Reality"], "overview": "Nick and Vanessa Lachey host this social experiment where single men and women look for love and get engaged, all before meeting in person.", "poster": "assets/tv-love-is-blind-2020-poster.jpg", "backdrop": "assets/tv-love-is-blind-2020-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-22T17:11:08.2447226Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 99353, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 66, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.233, "tmdbVotes": 118}}, {"id": "tv-the-hunting-wives-2025", "title": "The Hunting Wives", "year": 2025, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 6.932, "criticRating": null, "genres": ["Drama", "Mystery"], "overview": "Sophie trades New England for East Texas and falls into a wealthy socialite's magnetic orbit \u2014 where a clique of housewives hide deadly secrets.", "poster": "assets/tv-the-hunting-wives-2025-poster.jpg", "backdrop": "assets/tv-the-hunting-wives-2025-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-20T19:42:46.3227892Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 244447, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 81, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.964, "tmdbVotes": 112}}, {"id": "tv-the-white-lotus-2021", "title": "The White Lotus", "year": 2021, "type": "tv", "runtimeSeconds": null, "seasonCount": 3, "communityRating": 7.597, "criticRating": null, "genres": ["Comedy", "Drama", "Mystery"], "overview": "Follow the exploits of various guests and employees at an exclusive tropical resort over the span of a week as with each passing day, a darker complexity emerges in these picture-perfect travelers, the hotel\u2019s\u2026", "poster": "assets/tv-the-white-lotus-2021-poster.jpg", "backdrop": "assets/tv-the-white-lotus-2021-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-20T02:45:52.8742674Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 111803, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 90, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.599, "tmdbVotes": 1604}}], "discover": [{"id": "movie-across-the-hall-2009", "title": "Across the Hall", "year": 2009, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Thriller", "Mystery"], "overview": "Convinced that his fiancee is cheating on him, a man follows her to a hotel and calls his best friend to help him avoid a calamity.", "poster": "assets/movie-across-the-hall-2009-poster.jpg", "backdrop": "assets/movie-across-the-hall-2009-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 21469, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": 39, "rtAudienceLabel": "Spilled", "imdb": 5.8, "imdbVotes": 5130, "tmdb": 6, "tmdbVotes": 129}}, {"id": "movie-addicted-2014", "title": "Addicted", "year": 2014, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Thriller"], "overview": "A gallerist risks her family and flourishing career when she enters into an affair with a talented painter and slowly loses control of her life.", "poster": "assets/movie-addicted-2014-poster.jpg", "backdrop": "assets/movie-addicted-2014-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 235271, "ratings": {"rtCritics": 7, "rtCriticsLabel": "Rotten", "rtAudience": 51, "rtAudienceLabel": "Spilled", "imdb": 5, "imdbVotes": 13131, "tmdb": 5.928, "tmdbVotes": 466}}, {"id": "movie-adulterers-2016", "title": "Adulterers", "year": 2016, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Thriller", "Drama"], "overview": "On a steamy New Orleans afternoon, Sam Deuprey decides to surprise his beautiful wife, Ashley, for their anniversary and comes home early. But Ashley is not alone in the bedroom. She and her lover, Damien are about\u2026", "poster": "assets/movie-adulterers-2016-poster.jpg", "backdrop": "assets/movie-adulterers-2016-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 376004, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": 37, "rtAudienceLabel": "Spilled", "imdb": 5.1, "imdbVotes": 2144, "tmdb": 6.2, "tmdbVotes": 116}}, {"id": "movie-alone-with-her-2006", "title": "Alone With Her", "year": 2006, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Crime", "Drama", "Thriller"], "overview": "The harrowing story of a disturbed young man's attempts to win the affections of an unsuspecting young woman. When Doug first sees Amy, he instantly falls for her and begins to watch her every move, going so far as\u2026", "poster": "assets/movie-alone-with-her-2006-poster.jpg", "backdrop": "assets/movie-alone-with-her-2006-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 18206, "ratings": {"rtCritics": 70, "rtCriticsLabel": "Fresh", "rtAudience": 46, "rtAudienceLabel": "Spilled", "imdb": 6, "imdbVotes": 4359, "tmdb": 5.9, "tmdbVotes": 94}}, {"id": "movie-awake-2007", "title": "Awake", "year": 2007, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Thriller", "Crime", "Mystery"], "overview": "While undergoing heart surgery, a man experiences a phenomenon called \u2018anesthetic awareness\u2019, which leaves him awake but paralyzed throughout the operation. As various obstacles present themselves, his wife must make\u2026", "poster": "assets/movie-awake-2007-poster.jpg", "backdrop": "assets/movie-awake-2007-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 13483, "ratings": {"rtCritics": 23, "rtCriticsLabel": "Rotten", "rtAudience": 55, "rtAudienceLabel": "Spilled", "imdb": 6.5, "imdbVotes": 89389, "tmdb": 6.586, "tmdbVotes": 1649}}, {"id": "movie-black-bear-2020", "title": "Black Bear", "year": 2020, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Thriller"], "overview": "At a remote lake house in the Adirondack Mountains, a couple entertains an out-of-town guest looking for inspiration in her filmmaking. The group quickly falls into a calculated game of desire, manipulation, and\u2026", "poster": "assets/movie-black-bear-2020-poster.jpg", "backdrop": "assets/movie-black-bear-2020-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 624788, "ratings": {"rtCritics": 89, "rtCriticsLabel": "Certified Fresh", "rtAudience": 64, "rtAudienceLabel": "Upright", "imdb": 6.5, "imdbVotes": 18408, "tmdb": 6.337, "tmdbVotes": 315}}, {"id": "movie-butterfly-on-a-wheel-2007", "title": "Butterfly on a Wheel", "year": 2007, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Crime", "Drama", "Thriller"], "overview": "A sociopathic kidnapper methodically pushes a desperate pair of parents to their absolute breaking point.", "poster": "assets/movie-butterfly-on-a-wheel-2007-poster.jpg", "backdrop": "assets/movie-butterfly-on-a-wheel-2007-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 13250, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": 61, "rtAudienceLabel": "Upright", "imdb": 6.6, "imdbVotes": 35409, "tmdb": 6.457, "tmdbVotes": 595}}, {"id": "movie-careful-what-you-wish-for-2015", "title": "Careful What You Wish For", "year": 2015, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Thriller"], "overview": "A guy gets more than he bargained for after entering into an affair with the wife of an investment banker. Soon, a suspicious death and substantial life insurance policy embroil him in a scandal.", "poster": "assets/movie-careful-what-you-wish-for-2015-poster.jpg", "backdrop": "assets/movie-careful-what-you-wish-for-2015-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 317744, "ratings": {"rtCritics": 17, "rtCriticsLabel": "Rotten", "rtAudience": 61, "rtAudienceLabel": "Upright", "imdb": 5.6, "imdbVotes": 9452, "tmdb": 6.129, "tmdbVotes": 446}}, {"id": "movie-crime-of-passion-1956", "title": "Crime of Passion", "year": 1956, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Crime", "Thriller"], "overview": "Kathy leaves the newspaper business to marry homicide detective Bill, but is frustrated by his lack of ambition and the banality of life in the suburbs. Her drive to advance Bill's career soon takes her down a\u2026", "poster": "assets/movie-crime-of-passion-1956-poster.jpg", "backdrop": "assets/movie-crime-of-passion-1956-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "center_crop", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 1920, "ratings": {"rtCritics": 80, "rtCriticsLabel": "Fresh", "rtAudience": 34, "rtAudienceLabel": "Spilled", "imdb": 6.4, "imdbVotes": 3750, "tmdb": 6.1, "tmdbVotes": 57}}, {"id": "movie-deep-water-2022", "title": "Deep Water", "year": 2022, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Mystery", "Thriller"], "overview": "A well-to-do husband who allows his wife to have affairs in order to avoid a divorce becomes a prime suspect in the disappearance of her lovers.", "poster": "assets/movie-deep-water-2022-poster.jpg", "backdrop": "assets/movie-deep-water-2022-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 619979, "ratings": {"rtCritics": 35, "rtCriticsLabel": "Rotten", "rtAudience": 25, "rtAudienceLabel": "Spilled", "imdb": 5.5, "imdbVotes": 74098, "tmdb": 5.834, "tmdbVotes": 1755}}, {"id": "movie-derailed-2005", "title": "Derailed", "year": 2005, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Thriller"], "overview": "When two married business executives having an affair are blackmailed by a violent criminal, they are forced to turn the tables on him to save their families.", "poster": "assets/movie-derailed-2005-poster.jpg", "backdrop": "assets/movie-derailed-2005-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 8999, "ratings": {"rtCritics": 20, "rtCriticsLabel": "Rotten", "rtAudience": 58, "rtAudienceLabel": "Spilled", "imdb": 6.6, "imdbVotes": 79563, "tmdb": 6.405, "tmdbVotes": 1193}}, {"id": "movie-die-my-love-2025", "title": "Die My Love", "year": 2025, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama"], "overview": "After inheriting a remote Montana house, Jackson moves there from New York with his partner Grace, and the couple soon welcome a child. As Jackson becomes increasingly absent and rural isolation sets in, Grace\u2026", "poster": "assets/movie-die-my-love-2025-poster.jpg", "backdrop": "assets/movie-die-my-love-2025-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 1033148, "ratings": {"rtCritics": 74, "rtCriticsLabel": "Certified Fresh", "rtAudience": 45, "rtAudienceLabel": "Spilled", "imdb": 6, "imdbVotes": 50664, "tmdb": 6.1, "tmdbVotes": 683}}, {"id": "movie-dream-house-2011", "title": "Dream House", "year": 2011, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Mystery", "Drama", "Thriller"], "overview": "Publisher Will Atenton quits a lucrative job in New York to relocate his wife, Libby, and their daughters to a quaint town in New England. However, as they settle into their home the Atentons discover that a woman\u2026", "poster": "assets/movie-dream-house-2011-poster.jpg", "backdrop": "assets/movie-dream-house-2011-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 69668, "ratings": {"rtCritics": 7, "rtCriticsLabel": "Rotten", "rtAudience": 36, "rtAudienceLabel": "Spilled", "imdb": 6, "imdbVotes": 71386, "tmdb": 6.212, "tmdbVotes": 1480}}, {"id": "movie-dream-lover-1994", "title": "Dream Lover", "year": 1994, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Mystery", "Thriller"], "overview": "Not long after they cross paths at an art gallery, architect Ray Reardon and hypnotically sensual Lena are married with children. But as strange incidents occur, Ray begins to realize he may not really know the woman\u2026", "poster": "assets/movie-dream-lover-1994-poster.jpg", "backdrop": "assets/movie-dream-lover-1994-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 18190, "ratings": {"rtCritics": 57, "rtCriticsLabel": "Rotten", "rtAudience": 38, "rtAudienceLabel": "Spilled", "imdb": 6.2, "imdbVotes": 7865, "tmdb": 6.844, "tmdbVotes": 167}}, {"id": "movie-drop-2025", "title": "Drop", "year": 2025, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Mystery", "Thriller"], "overview": "Violet, a widowed mother on her first date in years, arrives at an upscale restaurant where she is relieved that her date, Henry, is more charming and handsome than she expected. But their chemistry begins to curdle\u2026", "poster": "assets/movie-drop-2025-poster.jpg", "backdrop": "assets/movie-drop-2025-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 1249213, "ratings": {"rtCritics": 83, "rtCriticsLabel": "Certified Fresh", "rtAudience": 79, "rtAudienceLabel": "Upright", "imdb": 6.1, "imdbVotes": 61018, "tmdb": 6.275, "tmdbVotes": 1023}}, {"id": "movie-eastern-promises-2007", "title": "Eastern Promises", "year": 2007, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Thriller", "Crime", "Mystery"], "overview": "A Russian teenager living in London dies during childbirth but leaves clues in her diary that could tie her child to a rape involving a violent Russian mob family.", "poster": "assets/movie-eastern-promises-2007-poster.jpg", "backdrop": "assets/movie-eastern-promises-2007-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 2252, "ratings": {"rtCritics": 89, "rtCriticsLabel": "Certified Fresh", "rtAudience": 83, "rtAudienceLabel": "Upright", "imdb": 7.6, "imdbVotes": 281015, "tmdb": 7.349, "tmdbVotes": 3900}}, {"id": "movie-faces-1968", "title": "Faces", "year": 1968, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama"], "overview": "Middle-aged suburban husband Richard abruptly tells his wife, Maria, that he wants a divorce. As Richard takes up with a younger woman, Maria enjoys a night on the town with her friends and meets a younger man. As\u2026", "poster": "assets/movie-faces-1968-poster.jpg", "backdrop": "assets/movie-faces-1968-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "center_crop", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 753, "ratings": {"rtCritics": 83, "rtCriticsLabel": "Fresh", "rtAudience": 86, "rtAudienceLabel": "Upright", "imdb": 7.4, "imdbVotes": 12950, "tmdb": 7.093, "tmdbVotes": 227}}, {"id": "movie-fatale-2020", "title": "Fatale", "year": 2020, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Thriller"], "overview": "After a wild one-night stand, successful sports agent Derrick Tyler watches his perfect life slowly disappear when he discovers the sexy and mysterious woman he risked everything for is determined police detective\u2026", "poster": "assets/movie-fatale-2020-poster.jpg", "backdrop": "assets/movie-fatale-2020-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 549514, "ratings": {"rtCritics": 46, "rtCriticsLabel": "Rotten", "rtAudience": 87, "rtAudienceLabel": "Upright", "imdb": 5.5, "imdbVotes": 16392, "tmdb": 6, "tmdbVotes": 401}}, {"id": "tv-56-days-2026", "title": "56 Days", "year": 2026, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Crime", "Mystery"], "overview": "When an unidentified body is found in a luxury apartment linked to Oliver Kennedy and his girlfriend Ciara Wyse, Detectives Lee Reardon and Karl Connolly reconstruct the couple's deadly romance across the past 56 days.", "poster": "assets/tv-56-days-2026-poster.jpg", "backdrop": "assets/tv-56-days-2026-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 241372, "ratings": {"rtCritics": 60, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.388, "tmdbVotes": 245}}, {"id": "tv-90-day-fiance-before-the-90-days-2017", "title": "90 Day Fianc\u00e9: Before the 90 Days", "year": 2017, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Reality"], "overview": "Follow couples who have an existing relationship online, but haven't met in person. We'll experience their journey as they travel to the other's foreign country for the first time in an attempt to establish an\u2026", "poster": "assets/tv-90-day-fiance-before-the-90-days-2017-poster.jpg", "backdrop": "assets/tv-90-day-fiance-before-the-90-days-2017-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 73319, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.5, "tmdbVotes": 45}}, {"id": "tv-90-day-fiance-the-other-way-2019", "title": "90 Day Fianc\u00e9: The Other Way", "year": 2019, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Reality"], "overview": "Americans move to a foreign country all in the name of love. Will uprooting their lives in the United States pay off, or will they be packing up and moving back to America brokenhearted?", "poster": "assets/tv-90-day-fiance-the-other-way-2019-poster.jpg", "backdrop": "assets/tv-90-day-fiance-the-other-way-2019-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 90046, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.8, "tmdbVotes": 34}}, {"id": "tv-absolutely-fabulous-1992", "title": "Absolutely Fabulous", "year": 1992, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Comedy"], "overview": "Set in the world of fashion and PR, immature fun-loving mother Edina Monsoon and her best friend Patsy drive Eddie's sensible daughter, Saffron, up the wall with their constant drug abuse and outrageous selfishness.\u2026", "poster": "assets/tv-absolutely-fabulous-1992-poster.jpg", "backdrop": "assets/tv-absolutely-fabulous-1992-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 4493, "ratings": {"rtCritics": 96, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.6, "tmdbVotes": 198}}, {"id": "tv-the-afterparty-2022", "title": "The Afterparty", "year": 2022, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Mystery", "Comedy", "Crime"], "overview": "Nothing is as it seems in this hilarious murder mystery where each suspect's story is told through a different film genre.", "poster": "assets/tv-the-afterparty-2022-poster.jpg", "backdrop": "assets/tv-the-afterparty-2022-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 106454, "ratings": {"rtCritics": 92, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.071, "tmdbVotes": 245}}, {"id": "tv-agatha-christie-s-marple-2004", "title": "Agatha Christie's Marple", "year": 2004, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Crime", "Mystery"], "overview": "The adventures of Miss Jane Marple, an elderly spinster living in the quiet little village of St Mary Mead. During her many visits to friends and relatives in other villages, Miss Marple often stumbles upon\u2026", "poster": "assets/tv-agatha-christie-s-marple-2004-poster.jpg", "backdrop": "assets/tv-agatha-christie-s-marple-2004-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 6127, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.9, "tmdbVotes": 152}}, {"id": "tv-all-american-homecoming-2022", "title": "All American: Homecoming", "year": 2022, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama"], "overview": "Follow the journeys of Simone Hicks, a tennis hopeful from Beverly Hills, and elite baseball player Damon Sims from Chicago, as they navigate life at the prestigious HBCU Bringston University.", "poster": "assets/tv-all-american-homecoming-2022-poster.jpg", "backdrop": "assets/tv-all-american-homecoming-2022-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 153723, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.3, "tmdbVotes": 70}}, {"id": "tv-and-just-like-that-2021", "title": "And Just Like That\u2026", "year": 2021, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "This new chapter of \u201cSex and the City\u201d follows Carrie, Miranda and Charlotte as they navigate the journey from the complicated reality of life and friendship in their 30s to the even more complicated reality of life\u2026", "poster": "assets/tv-and-just-like-that-2021-poster.jpg", "backdrop": "assets/tv-and-just-like-that-2021-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 116450, "ratings": {"rtCritics": 52, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.211, "tmdbVotes": 556}}, {"id": "tv-anne-with-an-e-2017", "title": "Anne with an E", "year": 2017, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Family"], "overview": "A coming-of-age story about an outsider who, against all odds and numerous challenges, fights for love and acceptance and for her place in the world. The series centers on a young orphaned girl in the late 1890s,\u2026", "poster": "assets/tv-anne-with-an-e-2017-poster.jpg", "backdrop": "assets/tv-anne-with-an-e-2017-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 70785, "ratings": {"rtCritics": 63, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.7, "tmdbVotes": 5019}}, {"id": "tv-awkward-2011", "title": "Awkward.", "year": 2011, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "An irreverent look at the conflict, chaos and humor that defines teenage life through the eyes of 15-year-old Jenna Hamilton whose life begins to change when a simple accident becomes an epic misunderstanding and is\u2026", "poster": "assets/tv-awkward-2011-poster.jpg", "backdrop": "assets/tv-awkward-2011-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 39859, "ratings": {"rtCritics": 78, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.4, "tmdbVotes": 427}}, {"id": "tv-the-baby-sitters-club-2020", "title": "The Baby-Sitters Club", "year": 2020, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Kids", "Drama"], "overview": "In this contemporary take on the beloved book series, five best friends launch a baby-sitting business that's big on fun and adventure.", "poster": "assets/tv-the-baby-sitters-club-2020-poster.jpg", "backdrop": "assets/tv-the-baby-sitters-club-2020-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 100412, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.9, "tmdbVotes": 506}}, {"id": "tv-ballers-2015", "title": "Ballers", "year": 2015, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Comedy"], "overview": "Looking at the lives of former and current football players, the show follows former superstar Spencer Strasmore as he gets his life on track in retirement while mentoring other current and former players through the\u2026", "poster": "assets/tv-ballers-2015-poster.jpg", "backdrop": "assets/tv-ballers-2015-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 62704, "ratings": {"rtCritics": 72, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.809, "tmdbVotes": 820}}, {"id": "tv-baretta-1975", "title": "Baretta", "year": 1975, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Crime", "Drama", "Mystery"], "overview": "Baretta is an American detective television series which ran on ABC from 1975 to 1978. The show was a milder version of a successful 1973\u201374 ABC series, Toma, starring Tony Musante as chameleon-like, real-life New\u2026", "poster": "assets/tv-baretta-1975-poster.jpg", "backdrop": "assets/tv-baretta-1975-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 3216, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.5, "tmdbVotes": 43}}, {"id": "tv-based-on-a-true-story-2023", "title": "Based on a True Story", "year": 2023, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "The lives of a realtor, a plumber and a former tennis star unexpectedly collide, exposing America\u2019s obsession with true crime, murder and the slow-close toilet seat.", "poster": "assets/tv-based-on-a-true-story-2023-poster.jpg", "backdrop": "assets/tv-based-on-a-true-story-2023-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 197373, "ratings": {"rtCritics": 79, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7, "tmdbVotes": 160}}, {"id": "tv-the-beast-in-me-2025", "title": "The Beast in Me", "year": 2025, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Mystery"], "overview": "A famous author is pulled into a twisted mind game with her rich, powerful new neighbor \u2014 who might be a murderer.", "poster": "assets/tv-the-beast-in-me-2025-poster.jpg", "backdrop": "assets/tv-the-beast-in-me-2025-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 250504, "ratings": {"rtCritics": 85, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.072, "tmdbVotes": 334}}, {"id": "tv-big-city-greens-2018", "title": "Big City Greens", "year": 2018, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Family", "Animation", "Comedy"], "overview": "The offbeat adventures of 10-year-old Cricket Green, a mischievous and optimistic country boy who moves to the big city with his wildly out of place family \u2013 older sister Tilly, father Bill and Gramma Alice.", "poster": "assets/tv-big-city-greens-2018-poster.jpg", "backdrop": "assets/tv-big-city-greens-2018-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 80587, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.555, "tmdbVotes": 82}}, {"id": "tv-the-bold-type-2017", "title": "The Bold Type", "year": 2017, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Comedy"], "overview": "A glimpse into the outrageous lives of Jane, Kat and Sutton, who are working at the nation's top women's magazine, Scarlet, while navigating their careers, identities and individual voices.", "poster": "assets/tv-the-bold-type-2017-poster.jpg", "backdrop": "assets/tv-the-bold-type-2017-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 69630, "ratings": {"rtCritics": 89, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.7, "tmdbVotes": 204}}, {"id": "tv-brassic-2019", "title": "Brassic", "year": 2019, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Comedy", "Drama", "Crime"], "overview": "A group of working-class friends finding unconventional ways to win at life in suburban northern England. These lads have dealt, scammed, bribed and conned their way through adolescence, but now, their dealing and\u2026", "poster": "assets/tv-brassic-2019-poster.jpg", "backdrop": "assets/tv-brassic-2019-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 92621, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.336, "tmdbVotes": 263}}], "discoverySource": {"state": "materialized_snapshot", "rankKnown": false, "selection": "First 18 alphabetically indexed movie stubs and first 18 series stubs, not ranked feed order", "observedAt": "2026-11-04T20:42:12.030108+00:00"}}, {"key": "shared", "name": "Shared", "initial": "S", "color": "#9be38f", "destinations": {"Home": {"kind": "home"}, "Movies": {"kind": "library", "collection": "movies"}, "Shows": {"kind": "library", "collection": "shows"}, "Discover": {"kind": "discover", "collection": "discover"}}, "movies": [{"id": "movie-american-gangster-2007", "title": "American Gangster", "year": 2007, "type": "movie", "runtimeSeconds": 10546, "seasonCount": null, "communityRating": 7.595, "criticRating": 81, "genres": ["Drama", "Crime"], "overview": "Loosely based on the criminal career of Frank Lucas, a gangster from La Grange, North Carolina, who smuggled heroin into the United States on American service planes returning from the Vietnam War, before being\u2026", "poster": "assets/movie-american-gangster-2007-poster.jpg", "backdrop": "assets/movie-american-gangster-2007-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-08-23T10:22:36.0000000Z", "lastPlayedAt": "2026-08-30T21:05:39.7952451Z", "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 4982, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 81, "rtCriticsLabel": "Certified Fresh", "rtAudience": 90, "rtAudienceLabel": "Upright", "imdb": 7.8, "imdbVotes": 495656, "tmdb": 7.599, "tmdbVotes": 6350}}, {"id": "movie-annie-hall-1977", "title": "Annie Hall", "year": 1977, "type": "movie", "runtimeSeconds": 5604, "seasonCount": null, "communityRating": 7.712, "criticRating": 97, "genres": ["Comedy", "Drama", "Romance"], "overview": "New York comedian Alvy Singer falls in love with the ditsy Annie Hall.", "poster": "assets/movie-annie-hall-1977-poster.jpg", "backdrop": "assets/movie-annie-hall-1977-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:24:23.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 703, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 97, "rtCriticsLabel": "Certified Fresh", "rtAudience": 92, "rtAudienceLabel": "Upright", "imdb": 7.9, "imdbVotes": 293349, "tmdb": 7.71, "tmdbVotes": 4391}}, {"id": "movie-apocalypse-now-1979", "title": "Apocalypse Now", "year": 1979, "type": "movie", "runtimeSeconds": 8835, "seasonCount": null, "communityRating": 8.261, "criticRating": 91, "genres": ["Drama", "War"], "overview": "At the height of the Vietnam war, Captain Benjamin Willard is sent on a dangerous mission that, officially, \"does not exist, nor will it ever exist.\" His goal is to locate - and eliminate - a mysterious Green Beret\u2026", "poster": "assets/movie-apocalypse-now-1979-poster.jpg", "backdrop": "assets/movie-apocalypse-now-1979-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:22:25.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 28, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 91, "rtCriticsLabel": "Certified Fresh", "rtAudience": 94, "rtAudienceLabel": "Upright", "imdb": 8.4, "imdbVotes": 781424, "tmdb": 8.3, "tmdbVotes": 9526}}, {"id": "movie-arrival-2016", "title": "Arrival", "year": 2016, "type": "movie", "runtimeSeconds": 6967, "seasonCount": null, "communityRating": 7.636, "criticRating": 94, "genres": ["Drama", "Science Fiction", "Mystery"], "overview": "Taking place after alien crafts land around the world, an expert linguist is recruited by the military to determine whether they come in peace or are a threat.", "poster": "assets/movie-arrival-2016-poster.jpg", "backdrop": "assets/movie-arrival-2016-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-14T19:54:12.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 329865, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 94, "rtCriticsLabel": "Certified Fresh", "rtAudience": 83, "rtAudienceLabel": "Upright", "imdb": 7.9, "imdbVotes": 883621, "tmdb": 7.638, "tmdbVotes": 20125}}, {"id": "movie-avatar-aang-the-last-airbender-2026", "title": "Avatar Aang: The Last Airbender", "year": 2026, "type": "movie", "runtimeSeconds": 5930, "seasonCount": null, "communityRating": 9.147, "criticRating": 90, "genres": ["Animation", "Adventure", "Fantasy"], "overview": "Avatar Aang, the world's last Airbender, learns of an ancient power that could save his culture from extinction. With the help of his friends, he embarks on a global quest to find it before it falls into the wrong\u2026", "poster": "assets/movie-avatar-aang-the-last-airbender-2026-poster.jpg", "backdrop": "assets/movie-avatar-aang-the-last-airbender-2026-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-25T09:53:09.0000000Z", "lastPlayedAt": "2026-08-02T19:22:33.6155383Z", "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 980431, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 90, "rtCriticsLabel": "Certified Fresh", "rtAudience": 99, "rtAudienceLabel": "Upright", "imdb": 7.7, "imdbVotes": 30792, "tmdb": 9, "tmdbVotes": 1417}}, {"id": "movie-bohemian-rhapsody-2018", "title": "Bohemian Rhapsody", "year": 2018, "type": "movie", "runtimeSeconds": 8077, "seasonCount": null, "communityRating": 7.95, "criticRating": 60, "genres": ["Music", "Drama"], "overview": "Singer Freddie Mercury, guitarist Brian May, drummer Roger Taylor and bass guitarist John Deacon take the music world by storm when they form the rock 'n' roll band Queen in 1970. Hit songs become instant classics.\u2026", "poster": "assets/movie-bohemian-rhapsody-2018-poster.jpg", "backdrop": "assets/movie-bohemian-rhapsody-2018-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:28:20.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 424694, "artwork": {"posterKind": "center_crop", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 60, "rtCriticsLabel": "Fresh", "rtAudience": 85, "rtAudienceLabel": "Upright", "imdb": 7.9, "imdbVotes": 655894, "tmdb": 7.947, "tmdbVotes": 18196}}, {"id": "movie-the-boy-and-the-heron-2023", "title": "The Boy and the Heron", "year": 2023, "type": "movie", "runtimeSeconds": 7437, "seasonCount": null, "communityRating": 7.4, "criticRating": 96, "genres": ["Animation", "Fantasy", "Drama"], "overview": "While the Second World War rages, the teenage Mahito, haunted by his mother's tragic death, is relocated from Tokyo to the serene rural home of his new stepmother Natsuko, a woman who bears a striking resemblance to\u2026", "poster": "assets/movie-the-boy-and-the-heron-2023-poster.jpg", "backdrop": "assets/movie-the-boy-and-the-heron-2023-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:25:15.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 508883, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 96, "rtCriticsLabel": "Certified Fresh", "rtAudience": 88, "rtAudienceLabel": "Upright", "imdb": 7.3, "imdbVotes": 152169, "tmdb": 7.387, "tmdbVotes": 2893}}, {"id": "movie-braveheart-1995", "title": "Braveheart", "year": 1995, "type": "movie", "runtimeSeconds": 10665, "seasonCount": null, "communityRating": 7.945, "criticRating": 74, "genres": ["Drama", "History", "War"], "overview": "Enraged at the slaughter of Murron, his new bride and childhood love, Scottish warrior William Wallace slays a platoon of the local English lord's soldiers. This leads the village to revolt and, eventually, the\u2026", "poster": "assets/movie-braveheart-1995-poster.jpg", "backdrop": "assets/movie-braveheart-1995-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-10T21:24:28.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 197, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 74, "rtCriticsLabel": "Certified Fresh", "rtAudience": 85, "rtAudienceLabel": "Upright", "imdb": 8.3, "imdbVotes": 1174990, "tmdb": 7.947, "tmdbVotes": 11584}}, {"id": "movie-the-breakfast-club-1985", "title": "The Breakfast Club", "year": 1985, "type": "movie", "runtimeSeconds": 5833, "seasonCount": null, "communityRating": 7.7, "criticRating": 87, "genres": ["Comedy", "Drama"], "overview": "Five high school students from different walks of life endure a Saturday detention under a power-hungry principal. The disparate group includes rebel John, princess Claire, outcast Allison, brainy Brian and Andrew,\u2026", "poster": "assets/movie-the-breakfast-club-1985-poster.jpg", "backdrop": "assets/movie-the-breakfast-club-1985-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:25:03.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 2108, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 87, "rtCriticsLabel": "Certified Fresh", "rtAudience": 92, "rtAudienceLabel": "Upright", "imdb": 7.8, "imdbVotes": 478743, "tmdb": 7.713, "tmdbVotes": 8815}}, {"id": "movie-castle-in-the-sky-1986", "title": "Castle in the Sky", "year": 1986, "type": "movie", "runtimeSeconds": 7474, "seasonCount": null, "communityRating": 8, "criticRating": 97, "genres": ["Adventure", "Fantasy", "Animation"], "overview": "A young boy and a girl with a magic crystal must race against pirates and foreign agents in a search for a legendary floating castle.", "poster": "assets/movie-castle-in-the-sky-1986-poster.jpg", "backdrop": "assets/movie-castle-in-the-sky-1986-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:23:09.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 10515, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 96, "rtCriticsLabel": "Fresh", "rtAudience": 91, "rtAudienceLabel": "Upright", "imdb": 8, "imdbVotes": 201545, "tmdb": 7.972, "tmdbVotes": 4868}}, {"id": "movie-citizen-kane-1941", "title": "Citizen Kane", "year": 1941, "type": "movie", "runtimeSeconds": 7173, "seasonCount": null, "communityRating": 7.966, "criticRating": 99, "genres": ["Mystery", "Drama"], "overview": "Newspaper magnate Charles Foster Kane is taken from his mother as a boy and made the ward of a rich industrialist. As a result, every well-meaning, tyrannical or self-destructive move he makes for the rest of his\u2026", "poster": "assets/movie-citizen-kane-1941-poster.jpg", "backdrop": "assets/movie-citizen-kane-1941-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:22:16.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 15, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 99, "rtCriticsLabel": "Certified Fresh", "rtAudience": 98, "rtAudienceLabel": "Upright", "imdb": 8.2, "imdbVotes": 498321, "tmdb": 7.962, "tmdbVotes": 6324}}, {"id": "movie-conclave-2024", "title": "Conclave", "year": 2024, "type": "movie", "runtimeSeconds": 7230, "seasonCount": null, "communityRating": 7.19, "criticRating": 93, "genres": ["Drama", "Thriller"], "overview": "After the unexpected death of the Pope, Cardinal Lawrence is tasked with managing the covert and ancient ritual of electing a new one. Sequestered in the Vatican with the Catholic Church\u2019s most powerful leaders until\u2026", "poster": "assets/movie-conclave-2024-poster.jpg", "backdrop": "assets/movie-conclave-2024-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:30:41.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 974576, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 93, "rtCriticsLabel": "Certified Fresh", "rtAudience": 86, "rtAudienceLabel": "Upright", "imdb": 7.4, "imdbVotes": 290498, "tmdb": 7.19, "tmdbVotes": 3744}}, {"id": "movie-the-dry-2021", "title": "The Dry", "year": 2021, "type": "movie", "runtimeSeconds": 7037, "seasonCount": null, "communityRating": 6.779, "criticRating": null, "genres": ["Crime", "Thriller", "Mystery"], "overview": "Aaron Falk returns to his drought-stricken hometown to attend a tragic funeral. But his return opens a decades-old wound - the unsolved death of a teenage girl.", "poster": "assets/movie-the-dry-2021-poster.jpg", "backdrop": "assets/movie-the-dry-2021-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:29:20.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 567797, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 90, "rtCriticsLabel": "Certified Fresh", "rtAudience": 89, "rtAudienceLabel": "Upright", "imdb": 6.8, "imdbVotes": 41935, "tmdb": 6.8, "tmdbVotes": 892}}, {"id": "movie-easy-a-2010", "title": "Easy A", "year": 2010, "type": "movie", "runtimeSeconds": 5545, "seasonCount": null, "communityRating": 6.8, "criticRating": 85, "genres": ["Comedy"], "overview": "Olive, an average high school student, sees her below-the-radar existence turn around overnight once she decides to use the school's gossip grapevine to advance her social standing. Now her classmates are turning\u2026", "poster": "assets/movie-easy-a-2010-poster.jpg", "backdrop": "assets/movie-easy-a-2010-backdrop.jpg", "played": true, "playCount": 1, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-17T19:59:04.0000000Z", "lastPlayedAt": "2026-10-17T20:02:51.1083337Z", "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 37735, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 85, "rtCriticsLabel": "Certified Fresh", "rtAudience": 77, "rtAudienceLabel": "Upright", "imdb": 7, "imdbVotes": 448780, "tmdb": 6.8, "tmdbVotes": 7619}}, {"id": "movie-el-camino-a-breaking-bad-movie-2019", "title": "El Camino: A Breaking Bad Movie", "year": 2019, "type": "movie", "runtimeSeconds": 7362, "seasonCount": null, "communityRating": 7.055, "criticRating": 92, "genres": ["Crime", "Drama", "Thriller"], "overview": "In the wake of his dramatic escape from captivity, Jesse Pinkman must come to terms with his past in order to forge some kind of future.", "poster": "assets/movie-el-camino-a-breaking-bad-movie-2019-poster.jpg", "backdrop": "assets/movie-el-camino-a-breaking-bad-movie-2019-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-21T23:31:11.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 559969, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 92, "rtCriticsLabel": "Certified Fresh", "rtAudience": 81, "rtAudienceLabel": "Upright", "imdb": 7.3, "imdbVotes": 354488, "tmdb": 7.056, "tmdbVotes": 5950}}, {"id": "movie-emancipation-2022", "title": "Emancipation", "year": 2022, "type": "movie", "runtimeSeconds": 7949, "seasonCount": null, "communityRating": 7.7, "criticRating": 45, "genres": ["Drama", "War", "History"], "overview": "Inspired by the gripping true story of a man who would do anything for his family\u2014and for freedom. When Peter, an enslaved man, risks his life to escape and return to his family, he embarks on a perilous journey of\u2026", "poster": "assets/movie-emancipation-2022-poster.jpg", "backdrop": "assets/movie-emancipation-2022-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-10T20:37:34.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 715931, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 45, "rtCriticsLabel": "Rotten", "rtAudience": 58, "rtAudienceLabel": "Spilled", "imdb": 6.3, "imdbVotes": 32079, "tmdb": 7.744, "tmdbVotes": 1319}}, {"id": "movie-fighting-with-my-family-2019", "title": "Fighting with My Family", "year": 2019, "type": "movie", "runtimeSeconds": 6509, "seasonCount": null, "communityRating": 6.84, "criticRating": 93, "genres": ["Comedy"], "overview": "Born into a tight-knit wrestling family, Paige and her brother Zak are ecstatic when they get the once-in-a-lifetime opportunity to try out for the WWE. But when only Paige earns a spot in the competitive training\u2026", "poster": "assets/movie-fighting-with-my-family-2019-poster.jpg", "backdrop": "assets/movie-fighting-with-my-family-2019-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-22T22:10:59.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 445629, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 93, "rtCriticsLabel": "Certified Fresh", "rtAudience": 86, "rtAudienceLabel": "Upright", "imdb": 7, "imdbVotes": 94576, "tmdb": 6.837, "tmdbVotes": 1952}}, {"id": "movie-force-of-nature-the-dry-2-2024", "title": "Force of Nature: The Dry 2", "year": 2024, "type": "movie", "runtimeSeconds": 6753, "seasonCount": null, "communityRating": 6.3, "criticRating": 66, "genres": ["Mystery", "Thriller"], "overview": "When five women take part in a corporate hiking retreat and only four come out on the other side, Federal Agents Aaron Falk and Carmen Cooper head deep into the Victorian mountain ranges to investigate in the hopes\u2026", "poster": "assets/movie-force-of-nature-the-dry-2-2024-poster.jpg", "backdrop": "assets/movie-force-of-nature-the-dry-2-2024-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:29:49.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 832262, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 66, "rtCriticsLabel": "Fresh", "rtAudience": 43, "rtAudienceLabel": "Spilled", "imdb": 5.9, "imdbVotes": 10343, "tmdb": 6.269, "tmdbVotes": 305}}, {"id": "movie-free-state-of-jones-2016", "title": "Free State of Jones", "year": 2016, "type": "movie", "runtimeSeconds": 8376, "seasonCount": null, "communityRating": 6.79, "criticRating": 48, "genres": ["Action", "Drama", "History"], "overview": "In 1863, Mississippi farmer Newt Knight serves as a medic for the Confederate Army. Opposed to slavery, Knight would rather help the wounded than fight the Union. After his nephew dies in battle, Newt returns home to\u2026", "poster": "assets/movie-free-state-of-jones-2016-poster.jpg", "backdrop": "assets/movie-free-state-of-jones-2016-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-11T17:56:53.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 316152, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 48, "rtCriticsLabel": "Rotten", "rtAudience": 64, "rtAudienceLabel": "Upright", "imdb": 6.9, "imdbVotes": 68931, "tmdb": 6.788, "tmdbVotes": 1730}}, {"id": "movie-from-up-on-poppy-hill-2011", "title": "From Up on Poppy Hill", "year": 2011, "type": "movie", "runtimeSeconds": 5482, "seasonCount": null, "communityRating": 7.5, "criticRating": 87, "genres": ["Animation", "Drama"], "overview": "Yokohama, 1963. Japan is picking itself up from the devastation of World War II and preparing to host the 1964 Olympics\u2014and the mood is one of both optimism and conflict as the young generation struggles to throw off\u2026", "poster": "assets/movie-from-up-on-poppy-hill-2011-poster.jpg", "backdrop": "assets/movie-from-up-on-poppy-hill-2011-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-07T14:41:03.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 83389, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 87, "rtCriticsLabel": "Certified Fresh", "rtAudience": 80, "rtAudienceLabel": "Upright", "imdb": 7.4, "imdbVotes": 60769, "tmdb": 7.509, "tmdbVotes": 2026}}, {"id": "movie-ghost-in-the-shell-1995", "title": "Ghost in the Shell", "year": 1995, "type": "movie", "runtimeSeconds": 4959, "seasonCount": null, "communityRating": 7.929, "criticRating": 95, "genres": ["Action", "Animation", "Science Fiction"], "overview": "In the year 2029, the barriers of our world have been broken down by the net and by cybernetics, but this brings new vulnerability to humans in the form of brain-hacking. When a highly-wanted hacker known as 'The\u2026", "poster": "assets/movie-ghost-in-the-shell-1995-poster.jpg", "backdrop": "assets/movie-ghost-in-the-shell-1995-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:22:57.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 9323, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 97, "rtCriticsLabel": "Certified Fresh", "rtAudience": 90, "rtAudienceLabel": "Upright", "imdb": 7.9, "imdbVotes": 178061, "tmdb": 7.928, "tmdbVotes": 4130}}, {"id": "movie-ghost-in-the-shell-2-innocence-2004", "title": "Ghost in the Shell 2: Innocence", "year": 2004, "type": "movie", "runtimeSeconds": 5950, "seasonCount": null, "communityRating": 7.352, "criticRating": 65, "genres": ["Animation", "Drama", "Science Fiction"], "overview": "Cyborg detective Batou is assigned to investigate a series of murders committed by gynoids\u2014doll-like cyborgs, which all malfunctioned, killed, then self-destructed afterwards. The brains of the gynoids initialize in\u2026", "poster": "assets/movie-ghost-in-the-shell-2-innocence-2004-poster.jpg", "backdrop": "assets/movie-ghost-in-the-shell-2-innocence-2004-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:23:38.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 12140, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 65, "rtCriticsLabel": "Fresh", "rtAudience": 80, "rtAudienceLabel": "Upright", "imdb": 7.4, "imdbVotes": 43280, "tmdb": 7.356, "tmdbVotes": 1049}}, {"id": "movie-the-godfather-1972", "title": "The Godfather", "year": 1972, "type": "movie", "runtimeSeconds": 10603, "seasonCount": null, "communityRating": 8.687, "criticRating": 97, "genres": ["Drama", "Crime"], "overview": "Spanning the years 1945 to 1955, a chronicle of the fictional Italian-American Corleone crime family. When organized crime family patriarch, Vito Corleone barely survives an attempt on his life, his youngest son,\u2026", "poster": "assets/movie-the-godfather-1972-poster.jpg", "backdrop": "assets/movie-the-godfather-1972-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:24:12.0000000Z", "lastPlayedAt": "2026-09-18T19:24:44.9855867Z", "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 238, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 97, "rtCriticsLabel": "Certified Fresh", "rtAudience": 98, "rtAudienceLabel": "Upright", "imdb": 9.2, "imdbVotes": 2262024, "tmdb": 8.688, "tmdbVotes": 23907}}, {"id": "movie-the-godfather-part-ii-1974", "title": "The Godfather Part II", "year": 1974, "type": "movie", "runtimeSeconds": 12031, "seasonCount": null, "communityRating": 8.573, "criticRating": 96, "genres": ["Drama", "Crime"], "overview": "In the continuing saga of the Corleone crime family, a young Vito Corleone grows up in Sicily and in 1910s New York. In the 1950s, Michael Corleone attempts to expand the family business into Las Vegas, Hollywood and\u2026", "poster": "assets/movie-the-godfather-part-ii-1974-poster.jpg", "backdrop": "assets/movie-the-godfather-part-ii-1974-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:24:18.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 240, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 96, "rtCriticsLabel": "Certified Fresh", "rtAudience": 97, "rtAudienceLabel": "Upright", "imdb": 9, "imdbVotes": 1521308, "tmdb": 8.571, "tmdbVotes": 14559}}, {"id": "movie-the-godfather-part-iii-1990", "title": "The Godfather Part III", "year": 1990, "type": "movie", "runtimeSeconds": 9476, "seasonCount": null, "communityRating": 7.416, "criticRating": 67, "genres": ["Crime", "Drama", "Thriller"], "overview": "In the midst of trying to legitimize his business dealings in 1979 New York and Italy, aging mafia don, Michael Corleone seeks forgiveness for his sins while taking a young protege under his wing.", "poster": "assets/movie-the-godfather-part-iii-1990-poster.jpg", "backdrop": "assets/movie-the-godfather-part-iii-1990-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:26:29.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 242, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 68, "rtCriticsLabel": "Fresh", "rtAudience": 68, "rtAudienceLabel": "Upright", "imdb": 7.5, "imdbVotes": 462448, "tmdb": 7.413, "tmdbVotes": 7159}}, {"id": "movie-gosford-park-2001", "title": "Gosford Park", "year": 2001, "type": "movie", "runtimeSeconds": 8247, "seasonCount": null, "communityRating": 6.815, "criticRating": 87, "genres": ["Drama", "Mystery", "Thriller"], "overview": "In 1930s England, a group of pretentious rich and famous gather together for a weekend of relaxation at a hunting resort. But when a murder occurs, each one of these interesting characters becomes a suspect.", "poster": "assets/movie-gosford-park-2001-poster.jpg", "backdrop": "assets/movie-gosford-park-2001-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:25:49.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 5279, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 87, "rtCriticsLabel": "Certified Fresh", "rtAudience": 78, "rtAudienceLabel": "Upright", "imdb": 7.2, "imdbVotes": 103883, "tmdb": 6.822, "tmdbVotes": 1317}}, {"id": "movie-grave-of-the-fireflies-1988", "title": "Grave of the Fireflies", "year": 1988, "type": "movie", "runtimeSeconds": 5313, "seasonCount": null, "communityRating": 8.45, "criticRating": 100, "genres": ["Animation", "Drama", "War"], "overview": "In the final months of World War II, 14-year-old Seita and his sister Setsuko are orphaned when their mother is killed during an air raid in Kobe, Japan. After a falling out with their aunt, they move into an\u2026", "poster": "assets/movie-grave-of-the-fireflies-1988-poster.jpg", "backdrop": "assets/movie-grave-of-the-fireflies-1988-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:24:14.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 12477, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Certified Fresh", "rtAudience": 95, "rtAudienceLabel": "Upright", "imdb": 8.5, "imdbVotes": 399802, "tmdb": 8.45, "tmdbVotes": 6938}}, {"id": "movie-the-great-gatsby-2013", "title": "The Great Gatsby", "year": 2013, "type": "movie", "runtimeSeconds": 8525, "seasonCount": null, "communityRating": 7.346, "criticRating": 49, "genres": ["Drama", "Romance"], "overview": "Nick Carraway arrives in New York in 1922, an era of loose morals, glittering jazz and bootleg kings. Chasing his own American Dream, Nick encounters the mysterious millionaire Gatsby and his bewitching cousin Daisy.\u2026", "poster": "assets/movie-the-great-gatsby-2013-poster.jpg", "backdrop": "assets/movie-the-great-gatsby-2013-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:26:50.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 64682, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 48, "rtCriticsLabel": "Rotten", "rtAudience": 67, "rtAudienceLabel": "Upright", "imdb": 7.2, "imdbVotes": 651882, "tmdb": 7.346, "tmdbVotes": 13290}}, {"id": "movie-the-hours-2002", "title": "The Hours", "year": 2002, "type": "movie", "runtimeSeconds": 6887, "seasonCount": null, "communityRating": 7.25, "criticRating": 79, "genres": ["Drama"], "overview": "The story of three women searching for more potent, meaningful lives. Each is alive at a different time and place, all are linked by their yearnings and their fears. Their stories intertwine, and finally come\u2026", "poster": "assets/movie-the-hours-2002-poster.jpg", "backdrop": "assets/movie-the-hours-2002-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:23:27.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 590, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 79, "rtCriticsLabel": "Certified Fresh", "rtAudience": 84, "rtAudienceLabel": "Upright", "imdb": 7.5, "imdbVotes": 148367, "tmdb": 7.249, "tmdbVotes": 1931}}, {"id": "movie-howl-s-moving-castle-2004", "title": "Howl's Moving Castle", "year": 2004, "type": "movie", "runtimeSeconds": 7149, "seasonCount": null, "communityRating": 8.4, "criticRating": 88, "genres": ["Fantasy", "Animation", "Adventure"], "overview": "Sophie, a young milliner, is turned into an elderly woman by a witch who enters her shop and curses her. She encounters a wizard named Howl and gets caught up in his resistance to fighting for the king.", "poster": "assets/movie-howl-s-moving-castle-2004-poster.jpg", "backdrop": "assets/movie-howl-s-moving-castle-2004-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:22:47.0000000Z", "lastPlayedAt": "2026-05-21T18:46:08.0000000Z", "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 4935, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 87, "rtCriticsLabel": "Certified Fresh", "rtAudience": 93, "rtAudienceLabel": "Upright", "imdb": 8.2, "imdbVotes": 524520, "tmdb": 8.391, "tmdbVotes": 11642}}, {"id": "movie-in-the-heights-2021", "title": "In the Heights", "year": 2021, "type": "movie", "runtimeSeconds": 8579, "seasonCount": null, "communityRating": 7.111, "criticRating": null, "genres": ["Drama", "Romance"], "overview": "The story of Usnavi, a bodega owner who has mixed feelings about closing his store and retiring to the Dominican Republic or staying in Washington Heights.", "poster": "assets/movie-in-the-heights-2021-poster.jpg", "backdrop": "assets/movie-in-the-heights-2021-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:29:11.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 467909, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 94, "rtCriticsLabel": "Certified Fresh", "rtAudience": 94, "rtAudienceLabel": "Upright", "imdb": 7.2, "imdbVotes": 56513, "tmdb": 7.104, "tmdbVotes": 826}}, {"id": "movie-jennifer-s-body-2009", "title": "Jennifer's Body", "year": 2009, "type": "movie", "runtimeSeconds": 6450, "seasonCount": null, "communityRating": 6.012, "criticRating": 47, "genres": ["Horror", "Comedy"], "overview": "Jennifer, a gorgeous, seductive cheerleader takes evil to a whole new level after she's possessed by a sinister demon. Now it's up to her best friend to stop Jennifer's reign of terror before it's too late.", "poster": "assets/movie-jennifer-s-body-2009-poster.jpg", "backdrop": "assets/movie-jennifer-s-body-2009-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-30T03:37:04.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 19994, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 47, "rtCriticsLabel": "Rotten", "rtAudience": 36, "rtAudienceLabel": "Spilled", "imdb": 5.6, "imdbVotes": 179710, "tmdb": 6.013, "tmdbVotes": 4481}}, {"id": "movie-kiki-s-delivery-service-1989", "title": "Kiki's Delivery Service", "year": 1989, "type": "movie", "runtimeSeconds": 6183, "seasonCount": null, "communityRating": 7.839, "criticRating": null, "genres": ["Animation", "Family", "Fantasy"], "overview": "A young witch, on her mandatory year of independent life, finds fitting into a new community difficult while she supports herself by running an air courier service.", "poster": "assets/movie-kiki-s-delivery-service-1989-poster.jpg", "backdrop": "assets/movie-kiki-s-delivery-service-1989-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:24:20.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 16859, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 98, "rtCriticsLabel": "Certified Fresh", "rtAudience": 89, "rtAudienceLabel": "Upright", "imdb": 7.8, "imdbVotes": 192477, "tmdb": 7.839, "tmdbVotes": 4811}}, {"id": "movie-the-last-of-the-mohicans-1992", "title": "The Last of the Mohicans", "year": 1992, "type": "movie", "runtimeSeconds": 6874, "seasonCount": null, "communityRating": 7.388, "criticRating": 88, "genres": ["History", "War", "Drama"], "overview": "In war-torn colonial America, in the midst of a bloody battle between British, the French and Native American allies, the aristocratic daughter of a British Colonel and her party are captured by a group of Huron\u2026", "poster": "assets/movie-the-last-of-the-mohicans-1992-poster.jpg", "backdrop": "assets/movie-the-last-of-the-mohicans-1992-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-10T20:59:22.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 9361, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 88, "rtCriticsLabel": "Certified Fresh", "rtAudience": 88, "rtAudienceLabel": "Upright", "imdb": 7.6, "imdbVotes": 210791, "tmdb": 7.39, "tmdbVotes": 3593}}, {"id": "movie-the-last-samurai-2003", "title": "The Last Samurai", "year": 2003, "type": "movie", "runtimeSeconds": 9251, "seasonCount": null, "communityRating": 7.61, "criticRating": 65, "genres": ["Drama", "Action", "War"], "overview": "Nathan Algren is an American hired to instruct the Japanese army in the ways of modern warfare, which finds him learning to respect the samurai and the honorable principles that rule them. Pressed to destroy the\u2026", "poster": "assets/movie-the-last-samurai-2003-poster.jpg", "backdrop": "assets/movie-the-last-samurai-2003-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-26T05:25:10.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 616, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 66, "rtCriticsLabel": "Fresh", "rtAudience": 83, "rtAudienceLabel": "Upright", "imdb": 7.8, "imdbVotes": 512982, "tmdb": 7.614, "tmdbVotes": 7887}}, {"id": "movie-lemony-snicket-s-a-series-of-unfortunate-events-2004", "title": "Lemony Snicket's A Series of Unfortunate Events", "year": 2004, "type": "movie", "runtimeSeconds": 6479, "seasonCount": null, "communityRating": 6.8, "criticRating": 72, "genres": ["Adventure", "Comedy", "Family"], "overview": "Three wealthy children's parents are killed in a fire. When they are sent to a distant relative, they find out that he is plotting to kill them and seize their fortune.", "poster": "assets/movie-lemony-snicket-s-a-series-of-unfortunate-events-2004-poster.jpg", "backdrop": "assets/movie-lemony-snicket-s-a-series-of-unfortunate-events-2004-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:26:09.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 11774, "artwork": {"posterKind": "center_crop", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 72, "rtCriticsLabel": "Fresh", "rtAudience": 63, "rtAudienceLabel": "Upright", "imdb": 6.8, "imdbVotes": 233636, "tmdb": 6.82, "tmdbVotes": 5447}}, {"id": "movie-the-lighthouse-2019", "title": "The Lighthouse", "year": 2019, "type": "movie", "runtimeSeconds": 6549, "seasonCount": null, "communityRating": 7.463, "criticRating": 90, "genres": ["Drama", "Fantasy", "Thriller"], "overview": "Two lighthouse keepers try to maintain their sanity while living on a remote and mysterious New England island in the 1890s.", "poster": "assets/movie-the-lighthouse-2019-poster.jpg", "backdrop": "assets/movie-the-lighthouse-2019-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:29:01.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 503919, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 90, "rtCriticsLabel": "Certified Fresh", "rtAudience": 72, "rtAudienceLabel": "Upright", "imdb": 7.3, "imdbVotes": 312344, "tmdb": 7.46, "tmdbVotes": 5895}}, {"id": "movie-locke-2014", "title": "Locke", "year": 2014, "type": "movie", "runtimeSeconds": 5090, "seasonCount": null, "communityRating": 6.888, "criticRating": 91, "genres": ["Drama", "Thriller"], "overview": "Ivan Locke has worked hard to craft a good life for himself. Tonight, that life will collapse around him. On the eve of the biggest challenge of his career, Ivan receives a phone call that sets in motion a series of\u2026", "poster": "assets/movie-locke-2014-poster.jpg", "backdrop": "assets/movie-locke-2014-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T17:38:48.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 210479, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 90, "rtCriticsLabel": "Certified Fresh", "rtAudience": 72, "rtAudienceLabel": "Upright", "imdb": 7.1, "imdbVotes": 171265, "tmdb": 6.889, "tmdbVotes": 3088}}, {"id": "movie-the-matrix-1999", "title": "The Matrix", "year": 1999, "type": "movie", "runtimeSeconds": 8179, "seasonCount": null, "communityRating": 8.259, "criticRating": 83, "genres": ["Action", "Science Fiction"], "overview": "Set in the 22nd century, The Matrix tells the story of a computer hacker who joins a group of underground insurgents fighting the vast and powerful computers who now rule the earth.", "poster": "assets/movie-the-matrix-1999-poster.jpg", "backdrop": "assets/movie-the-matrix-1999-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:18:12.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 603, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 83, "rtCriticsLabel": "Certified Fresh", "rtAudience": 85, "rtAudienceLabel": "Upright", "imdb": 8.7, "imdbVotes": 2289808, "tmdb": 8.262, "tmdbVotes": 29153}}, {"id": "movie-the-matrix-reloaded-2003", "title": "The Matrix Reloaded", "year": 2003, "type": "movie", "runtimeSeconds": 8298, "seasonCount": null, "communityRating": 7.085, "criticRating": 74, "genres": ["Adventure", "Action", "Thriller"], "overview": "The Resistance builds in numbers as humans are freed from the Matrix and brought to the city of Zion. Neo discovers his superpowers, including the ability to see the code inside the Matrix. With machine sentinels\u2026", "poster": "assets/movie-the-matrix-reloaded-2003-poster.jpg", "backdrop": "assets/movie-the-matrix-reloaded-2003-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:24:03.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 604, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 73, "rtCriticsLabel": "Certified Fresh", "rtAudience": 72, "rtAudienceLabel": "Upright", "imdb": 7.2, "imdbVotes": 678013, "tmdb": 7.087, "tmdbVotes": 12504}}, {"id": "movie-the-matrix-resurrections-2021", "title": "The Matrix Resurrections", "year": 2021, "type": "movie", "runtimeSeconds": 8875, "seasonCount": null, "communityRating": 6.303, "criticRating": 63, "genres": ["Science Fiction", "Action", "Adventure"], "overview": "Plagued by strange memories, Neo's life takes an unexpected turn when he finds himself back inside the Matrix.", "poster": "assets/movie-the-matrix-resurrections-2021-poster.jpg", "backdrop": "assets/movie-the-matrix-resurrections-2021-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:31:22.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 624860, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 63, "rtCriticsLabel": "Fresh", "rtAudience": 63, "rtAudienceLabel": "Upright", "imdb": 5.6, "imdbVotes": 307780, "tmdb": 6.294, "tmdbVotes": 6842}}, {"id": "movie-the-matrix-revolutions-2003", "title": "The Matrix Revolutions", "year": 2003, "type": "movie", "runtimeSeconds": 7756, "seasonCount": null, "communityRating": 6.758, "criticRating": 33, "genres": ["Adventure", "Action", "Thriller"], "overview": "The human city of Zion defends itself against the massive invasion of the machines as Neo fights to end the war at another front while also opposing the rogue Agent Smith.", "poster": "assets/movie-the-matrix-revolutions-2003-poster.jpg", "backdrop": "assets/movie-the-matrix-revolutions-2003-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:25:47.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 605, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 34, "rtCriticsLabel": "Rotten", "rtAudience": 60, "rtAudienceLabel": "Upright", "imdb": 6.8, "imdbVotes": 581553, "tmdb": 6.762, "tmdbVotes": 11292}}, {"id": "movie-mercy-2026", "title": "Mercy", "year": 2026, "type": "movie", "runtimeSeconds": 5968, "seasonCount": null, "communityRating": 7.077, "criticRating": null, "genres": ["Science Fiction", "Thriller", "Crime"], "overview": "In the near future, a detective stands on trial accused of murdering his wife. He has ninety minutes to prove his innocence to the advanced AI Judge he once championed, before it determines his fate.", "poster": "assets/movie-mercy-2026-poster.jpg", "backdrop": "assets/movie-mercy-2026-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:31:40.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 1236153, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 24, "rtCriticsLabel": "Rotten", "rtAudience": 81, "rtAudienceLabel": "Upright", "imdb": 6.2, "imdbVotes": 83878, "tmdb": 7.054, "tmdbVotes": 1812}}, {"id": "movie-normal-2026", "title": "Normal", "year": 2026, "type": "movie", "runtimeSeconds": 5514, "seasonCount": null, "communityRating": 7.267, "criticRating": 77, "genres": ["Action", "Crime", "Thriller"], "overview": "An unassuming substitute sheriff with a troubled past responds to a bank robbery in a small, sleepy town and unknowingly uncovers something far more explosive.", "poster": "assets/movie-normal-2026-poster.jpg", "backdrop": "assets/movie-normal-2026-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-08-21T08:33:18.0000000Z", "lastPlayedAt": "2026-09-24T23:07:52.1161581Z", "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 1242332, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 78, "rtCriticsLabel": "Certified Fresh", "rtAudience": 75, "rtAudienceLabel": "Upright", "imdb": 6.3, "imdbVotes": 37501, "tmdb": 7.241, "tmdbVotes": 786}}, {"id": "movie-outlaw-king-2018", "title": "Outlaw King", "year": 2018, "type": "movie", "runtimeSeconds": 7297, "seasonCount": null, "communityRating": 6.829, "criticRating": 63, "genres": ["Action", "History", "War"], "overview": "Forced into exile by the English after being crowned King of Scotland, legendary warrior Robert the Bruce fights to reclaim the throne.", "poster": "assets/movie-outlaw-king-2018-poster.jpg", "backdrop": "assets/movie-outlaw-king-2018-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:28:32.0000000Z", "lastPlayedAt": "2026-07-26T22:35:35.0000000Z", "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 454227, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 63, "rtCriticsLabel": "Fresh", "rtAudience": 69, "rtAudienceLabel": "Upright", "imdb": 6.9, "imdbVotes": 89876, "tmdb": 6.844, "tmdbVotes": 1780}}, {"id": "movie-panic-room-2002", "title": "Panic Room", "year": 2002, "type": "movie", "runtimeSeconds": 6717, "seasonCount": null, "communityRating": 6.794, "criticRating": 76, "genres": ["Crime", "Drama", "Thriller"], "overview": "Trapped in their New York brownstone's panic room, a hidden chamber built as a sanctuary in the event of break-ins, newly divorced Meg Altman and her young daughter Sarah play a deadly game of cat-and-mouse with\u2026", "poster": "assets/movie-panic-room-2002-poster.jpg", "backdrop": "assets/movie-panic-room-2002-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-19T20:50:01.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 4547, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 76, "rtCriticsLabel": "Certified Fresh", "rtAudience": 64, "rtAudienceLabel": "Upright", "imdb": 6.8, "imdbVotes": 317468, "tmdb": 6.796, "tmdbVotes": 5653}}, {"id": "movie-the-patriot-2000", "title": "The Patriot", "year": 2000, "type": "movie", "runtimeSeconds": 9887, "seasonCount": null, "communityRating": 7.214, "criticRating": 61, "genres": ["Drama", "History", "War"], "overview": "After proving himself on the field of battle in the French and Indian War, Benjamin Martin wants nothing more to do with such things, preferring the simple life of a farmer. But when his son Gabriel enlists in the\u2026", "poster": "assets/movie-the-patriot-2000-poster.jpg", "backdrop": "assets/movie-the-patriot-2000-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-10T20:50:00.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 2024, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 61, "rtCriticsLabel": "Fresh", "rtAudience": 81, "rtAudienceLabel": "Upright", "imdb": 7.2, "imdbVotes": 317639, "tmdb": 7.215, "tmdbVotes": 4535}}, {"id": "movie-peaky-blinders-the-immortal-man-2026", "title": "Peaky Blinders: The Immortal Man", "year": 2026, "type": "movie", "runtimeSeconds": 6844, "seasonCount": null, "communityRating": 7.187, "criticRating": 90, "genres": ["Crime", "Drama"], "overview": "After his estranged son gets embroiled in a Nazi plot, self-exiled gangster Tommy Shelby must return to Birmingham to save his family \u2014 and his nation.", "poster": "assets/movie-peaky-blinders-the-immortal-man-2026-poster.jpg", "backdrop": "assets/movie-peaky-blinders-the-immortal-man-2026-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:30:01.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 875828, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 90, "rtCriticsLabel": "Certified Fresh", "rtAudience": 87, "rtAudienceLabel": "Upright", "imdb": 6.5, "imdbVotes": 92130, "tmdb": 7.189, "tmdbVotes": 1304}}, {"id": "movie-ponyo-2008", "title": "Ponyo", "year": 2008, "type": "movie", "runtimeSeconds": 6530, "seasonCount": null, "communityRating": 7.763, "criticRating": 91, "genres": ["Animation", "Fantasy", "Family"], "overview": "When Sosuke, a young boy who lives on a clifftop overlooking the sea, rescues a stranded goldfish named Ponyo, he discovers more than he bargained for. Ponyo is a curious, energetic young creature who yearns to be\u2026", "poster": "assets/movie-ponyo-2008-poster.jpg", "backdrop": "assets/movie-ponyo-2008-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:23:53.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 12429, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 91, "rtCriticsLabel": "Certified Fresh", "rtAudience": 84, "rtAudienceLabel": "Upright", "imdb": 7.6, "imdbVotes": 190294, "tmdb": 7.759, "tmdbVotes": 5050}}, {"id": "movie-porco-rosso-1992", "title": "Porco Rosso", "year": 1992, "type": "movie", "runtimeSeconds": 5600, "seasonCount": null, "communityRating": 7.794, "criticRating": 96, "genres": ["Animation", "Adventure", "Fantasy"], "overview": "In Italy in the 1930s, sky pirates in biplanes terrorize wealthy cruise ships as they sail the Adriatic Sea. The only pilot brave enough to stop the scourge is the mysterious Porco Rosso, a former World War I flying\u2026", "poster": "assets/movie-porco-rosso-1992-poster.jpg", "backdrop": "assets/movie-porco-rosso-1992-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:23:22.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 11621, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 96, "rtCriticsLabel": "Fresh", "rtAudience": 87, "rtAudienceLabel": "Upright", "imdb": 7.7, "imdbVotes": 119396, "tmdb": 7.789, "tmdbVotes": 3879}}, {"id": "movie-princess-mononoke-1997", "title": "Princess Mononoke", "year": 1997, "type": "movie", "runtimeSeconds": 8003, "seasonCount": null, "communityRating": 8.321, "criticRating": 93, "genres": ["Adventure", "Fantasy", "Animation"], "overview": "Ashitaka, a prince of the disappearing Emishi people, is cursed by a demonized boar god and must journey to the west to find a cure. Along the way, he encounters San, a young human woman fighting to protect the\u2026", "poster": "assets/movie-princess-mononoke-1997-poster.jpg", "backdrop": "assets/movie-princess-mononoke-1997-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:22:28.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 128, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 94, "rtCriticsLabel": "Certified Fresh", "rtAudience": 99, "rtAudienceLabel": "Upright", "imdb": 8.3, "imdbVotes": 493735, "tmdb": 8.321, "tmdbVotes": 9438}}, {"id": "movie-prisoners-2013", "title": "Prisoners", "year": 2013, "type": "movie", "runtimeSeconds": 9192, "seasonCount": null, "communityRating": 8.106, "criticRating": 81, "genres": ["Drama", "Thriller", "Crime"], "overview": "After his six-year-old daughter is abducted, a desperate father takes justice into his own hands when he loses faith in the detective leading the investigation, setting both men on a collision course as the search\u2026", "poster": "assets/movie-prisoners-2013-poster.jpg", "backdrop": "assets/movie-prisoners-2013-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:27:33.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 146233, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 82, "rtCriticsLabel": "Certified Fresh", "rtAudience": 87, "rtAudienceLabel": "Upright", "imdb": 8.2, "imdbVotes": 963062, "tmdb": 8.105, "tmdbVotes": 13722}}, {"id": "movie-racing-stripes-2005", "title": "Racing Stripes", "year": 2005, "type": "movie", "runtimeSeconds": 6117, "seasonCount": null, "communityRating": 5.945, "criticRating": 35, "genres": ["Comedy", "Family"], "overview": "Shattered illusions are hard to repair -- especially for a good-hearted zebra named Stripes who's spent his life on a Kentucky farm amidst the sorely mistaken notion that he's a debonair thoroughbred. Once he faces\u2026", "poster": "assets/movie-racing-stripes-2005-poster.jpg", "backdrop": "assets/movie-racing-stripes-2005-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:26:02.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 6439, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 35, "rtCriticsLabel": "Rotten", "rtAudience": 42, "rtAudienceLabel": "Spilled", "imdb": 5.3, "imdbVotes": 19569, "tmdb": 5.962, "tmdbVotes": 705}}, {"id": "movie-requiem-for-a-dream-2000", "title": "Requiem for a Dream", "year": 2000, "type": "movie", "runtimeSeconds": 6086, "seasonCount": null, "communityRating": 8.005, "criticRating": 80, "genres": ["Crime", "Drama"], "overview": "The drug-induced utopias of four Coney Island residents are shattered when their addictions run deep.", "poster": "assets/movie-requiem-for-a-dream-2000-poster.jpg", "backdrop": "assets/movie-requiem-for-a-dream-2000-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:24:15.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 641, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 81, "rtCriticsLabel": "Certified Fresh", "rtAudience": 93, "rtAudienceLabel": "Upright", "imdb": 8.3, "imdbVotes": 989090, "tmdb": 8, "tmdbVotes": 11454}}, {"id": "movie-rogue-one-a-star-wars-story-2016", "title": "Rogue One: A Star Wars Story", "year": 2016, "type": "movie", "runtimeSeconds": 8038, "seasonCount": null, "communityRating": 7.51, "criticRating": 84, "genres": ["Action", "Adventure", "Science Fiction"], "overview": "A rogue band of resistance fighters unite for a mission to steal the Death Star plans and bring a new hope to the galaxy.", "poster": "assets/movie-rogue-one-a-star-wars-story-2016-poster.jpg", "backdrop": "assets/movie-rogue-one-a-star-wars-story-2016-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:28:00.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 330459, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 84, "rtCriticsLabel": "Certified Fresh", "rtAudience": 87, "rtAudienceLabel": "Upright", "imdb": 7.8, "imdbVotes": 768365, "tmdb": 7.512, "tmdbVotes": 16937}}, {"id": "movie-secondhand-lions-2003", "title": "Secondhand Lions", "year": 2003, "type": "movie", "runtimeSeconds": 6547, "seasonCount": null, "communityRating": 7.237, "criticRating": 60, "genres": ["Family", "Comedy", "Drama"], "overview": "The comedic adventures of an introverted boy left on the doorstep of a pair of reluctant, eccentric great-uncles, whose exotic remembrances stir the boy's spirit and re-ignite the men's lives.", "poster": "assets/movie-secondhand-lions-2003-poster.jpg", "backdrop": "assets/movie-secondhand-lions-2003-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-12T07:16:13.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 13156, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 59, "rtCriticsLabel": "Rotten", "rtAudience": 84, "rtAudienceLabel": "Upright", "imdb": 7.5, "imdbVotes": 66911, "tmdb": 7.242, "tmdbVotes": 872}}, {"id": "movie-the-secret-life-of-pets-2-2019", "title": "The Secret Life of Pets 2", "year": 2019, "type": "movie", "runtimeSeconds": 5164, "seasonCount": null, "communityRating": 6.95, "criticRating": 60, "genres": ["Animation", "Comedy", "Family"], "overview": "Max the terrier must cope with some major life changes when his owner gets married and has a baby. When the family takes a trip to the countryside, nervous Max has numerous run-ins with canine-intolerant cows,\u2026", "poster": "assets/movie-the-secret-life-of-pets-2-2019-poster.jpg", "backdrop": "assets/movie-the-secret-life-of-pets-2-2019-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-05T07:00:53.0000000Z", "lastPlayedAt": "2026-09-17T18:07:00.7024231Z", "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 412117, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 60, "rtCriticsLabel": "Fresh", "rtAudience": 90, "rtAudienceLabel": "Upright", "imdb": 6.4, "imdbVotes": 80464, "tmdb": 6.948, "tmdbVotes": 3450}}, {"id": "movie-self-reliance-2024", "title": "Self Reliance", "year": 2024, "type": "movie", "runtimeSeconds": 5461, "seasonCount": null, "communityRating": 5.888, "criticRating": 73, "genres": ["Comedy", "Thriller"], "overview": "When a man is offered a million dollars to play a game in which hunters try to kill him, he thinks he has found the perfect loophole: they can only attack when he\u2019s alone. His only problem is that none of his friends\u2026", "poster": "assets/movie-self-reliance-2024-poster.jpg", "backdrop": "assets/movie-self-reliance-2024-backdrop.jpg", "played": false, "playCount": 1, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:31:00.0000000Z", "lastPlayedAt": "2026-10-02T19:59:16.9286868Z", "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 1072876, "artwork": {"posterKind": "center_crop", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 73, "rtCriticsLabel": "Certified Fresh", "rtAudience": 56, "rtAudienceLabel": "Spilled", "imdb": 6, "imdbVotes": 23771, "tmdb": 5.866, "tmdbVotes": 346}}, {"id": "movie-serpico-1973", "title": "Serpico", "year": 1973, "type": "movie", "runtimeSeconds": 7805, "seasonCount": null, "communityRating": 7.5, "criticRating": 93, "genres": ["Crime", "Drama", "History"], "overview": "New York cop Frank Serpico blows the whistle on the rampant corruption in the force only to have his comrades turn against him.", "poster": "assets/movie-serpico-1973-poster.jpg", "backdrop": "assets/movie-serpico-1973-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-10T21:45:02.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 9040, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 93, "rtCriticsLabel": "Certified Fresh", "rtAudience": 88, "rtAudienceLabel": "Upright", "imdb": 7.7, "imdbVotes": 149750, "tmdb": 7.525, "tmdbVotes": 2323}}, {"id": "movie-shaft-2000", "title": "Shaft", "year": 2000, "type": "movie", "runtimeSeconds": 5960, "seasonCount": null, "communityRating": 6.026, "criticRating": 67, "genres": ["Action", "Adventure", "Crime"], "overview": "New York police detective John Shaft arrests Walter Wade Jr. for a racially motivated slaying. But the only eyewitness disappears, and Wade jumps bail for Switzerland. Two years later Wade returns to face trial,\u2026", "poster": "assets/movie-shaft-2000-poster.jpg", "backdrop": "assets/movie-shaft-2000-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-10T21:30:40.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 479, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 68, "rtCriticsLabel": "Fresh", "rtAudience": 40, "rtAudienceLabel": "Spilled", "imdb": 6, "imdbVotes": 86257, "tmdb": 6.024, "tmdbVotes": 1531}}, {"id": "movie-a-silent-voice-the-movie-2016", "title": "A Silent Voice: The Movie", "year": 2016, "type": "movie", "runtimeSeconds": 7804, "seasonCount": null, "communityRating": 8.398, "criticRating": null, "genres": ["Animation", "Drama", "Romance"], "overview": "Shouya Ishida starts bullying the new girl in class, Shouko Nishimiya, because she is deaf. But as the teasing continues, the rest of the class starts to turn on Shouya for his lack of compassion. When they leave\u2026", "poster": "assets/movie-a-silent-voice-the-movie-2016-poster.jpg", "backdrop": "assets/movie-a-silent-voice-the-movie-2016-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T17:39:46.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 378064, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 95, "rtCriticsLabel": "Fresh", "rtAudience": 94, "rtAudienceLabel": "Upright", "imdb": 8.2, "imdbVotes": 151926, "tmdb": 8.396, "tmdbVotes": 4764}}, {"id": "movie-sinbad-legend-of-the-seven-seas-2003", "title": "Sinbad: Legend of the Seven Seas", "year": 2003, "type": "movie", "runtimeSeconds": 5143, "seasonCount": null, "communityRating": 7.067, "criticRating": 44, "genres": ["Action", "Adventure", "Animation"], "overview": "The sailor of legend is framed by the goddess Eris for the theft of the Book of Peace, and must travel to her realm at the end of the world to retrieve it and save the life of his childhood friend Prince Proteus.", "poster": "assets/movie-sinbad-legend-of-the-seven-seas-2003-poster.jpg", "backdrop": "assets/movie-sinbad-legend-of-the-seven-seas-2003-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:26:25.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 14411, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 46, "rtCriticsLabel": "Rotten", "rtAudience": 57, "rtAudienceLabel": "Spilled", "imdb": 6.8, "imdbVotes": 65298, "tmdb": 7.071, "tmdbVotes": 2323}}, {"id": "movie-sleeping-with-other-people-2015", "title": "Sleeping with Other People", "year": 2015, "type": "movie", "runtimeSeconds": 6076, "seasonCount": null, "communityRating": 6.274, "criticRating": 64, "genres": ["Comedy", "Romance"], "overview": "Can two serial cheaters get a second chance at love? After a one-night stand in college, New Yorkers Lainey and Jake meet by chance twelve years later and discover they each have the same problem: because of their\u2026", "poster": "assets/movie-sleeping-with-other-people-2015-poster.jpg", "backdrop": "assets/movie-sleeping-with-other-people-2015-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:27:42.0000000Z", "lastPlayedAt": "2026-07-17T17:50:44.0000000Z", "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 288036, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 64, "rtCriticsLabel": "Fresh", "rtAudience": 56, "rtAudienceLabel": "Spilled", "imdb": 6.5, "imdbVotes": 52275, "tmdb": 6.275, "tmdbVotes": 1020}}, {"id": "movie-snowpiercer-2013", "title": "Snowpiercer", "year": 2013, "type": "movie", "runtimeSeconds": 7573, "seasonCount": null, "communityRating": 6.909, "criticRating": 94, "genres": ["Action", "Science Fiction", "Drama"], "overview": "In a future where a failed global-warming experiment kills off most life on the planet, a class system evolves aboard the Snowpiercer; a train that travels around the globe via a perpetual-motion engine.", "poster": "assets/movie-snowpiercer-2013-poster.jpg", "backdrop": "assets/movie-snowpiercer-2013-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:27:07.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 110415, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 94, "rtCriticsLabel": "Certified Fresh", "rtAudience": 72, "rtAudienceLabel": "Upright", "imdb": 7.1, "imdbVotes": 426976, "tmdb": 6.9, "tmdbVotes": 10807}}, {"id": "movie-spider-man-brand-new-day-2026", "title": "Spider-Man: Brand New Day", "year": 2026, "type": "movie", "runtimeSeconds": 8701, "seasonCount": null, "communityRating": 8.374, "criticRating": 90, "genres": ["Science Fiction", "Action", "Adventure"], "overview": "Fighting crime full-time as Spider-Man in a world that doesn't remember him\u2014and the pressure of seeing his old friends move on without him\u2014sparks a change in Peter Parker he may not have the power to control. But\u2026", "poster": "assets/movie-spider-man-brand-new-day-2026-poster.jpg", "backdrop": "assets/movie-spider-man-brand-new-day-2026-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-10T14:14:27.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 969681, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 90, "rtCriticsLabel": "Certified Fresh", "rtAudience": 97, "rtAudienceLabel": "Upright", "imdb": 7.9, "imdbVotes": 366886, "tmdb": 8.5, "tmdbVotes": 6537}}, {"id": "movie-spider-man-far-from-home-2019", "title": "Spider-Man: Far From Home", "year": 2019, "type": "movie", "runtimeSeconds": 7762, "seasonCount": null, "communityRating": 7.389, "criticRating": 91, "genres": ["Action", "Adventure", "Science Fiction"], "overview": "Peter Parker and his friends go on a summer trip to Europe. However, they will hardly be able to rest - Peter will have to agree to help Nick Fury uncover the mystery of creatures that cause natural disasters and\u2026", "poster": "assets/movie-spider-man-far-from-home-2019-poster.jpg", "backdrop": "assets/movie-spider-man-far-from-home-2019-backdrop.jpg", "played": true, "playCount": 1, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-10T14:25:47.0000000Z", "lastPlayedAt": "2026-10-10T17:50:35.6193119Z", "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 429617, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 91, "rtCriticsLabel": "Certified Fresh", "rtAudience": 95, "rtAudienceLabel": "Upright", "imdb": 7.3, "imdbVotes": 682887, "tmdb": 7.387, "tmdbVotes": 17847}}, {"id": "movie-spider-man-homecoming-2017", "title": "Spider-Man: Homecoming", "year": 2017, "type": "movie", "runtimeSeconds": 8008, "seasonCount": null, "communityRating": 7.333, "criticRating": 92, "genres": ["Action", "Adventure", "Science Fiction"], "overview": "Following the events of Captain America: Civil War, Peter Parker, with the help of his mentor Tony Stark, tries to balance his life as an ordinary high school student in Queens, New York City, with fighting crime as\u2026", "poster": "assets/movie-spider-man-homecoming-2017-poster.jpg", "backdrop": "assets/movie-spider-man-homecoming-2017-backdrop.jpg", "played": true, "playCount": 1, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-10T14:33:13.0000000Z", "lastPlayedAt": "2026-10-10T20:31:23.4444213Z", "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 315635, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 92, "rtCriticsLabel": "Certified Fresh", "rtAudience": 87, "rtAudienceLabel": "Upright", "imdb": 7.4, "imdbVotes": 840974, "tmdb": 7.332, "tmdbVotes": 24183}}, {"id": "movie-spider-man-no-way-home-2021", "title": "Spider-Man: No Way Home", "year": 2021, "type": "movie", "runtimeSeconds": 8890, "seasonCount": null, "communityRating": 7.947, "criticRating": 93, "genres": ["Action", "Adventure", "Science Fiction"], "overview": "Peter Parker is unmasked and no longer able to separate his normal life from the high-stakes of being a super-hero. When he asks for help from Doctor Strange the stakes become even more dangerous, forcing him to\u2026", "poster": "assets/movie-spider-man-no-way-home-2021-poster.jpg", "backdrop": "assets/movie-spider-man-no-way-home-2021-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-10T14:21:05.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 634649, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 93, "rtCriticsLabel": "Certified Fresh", "rtAudience": 97, "rtAudienceLabel": "Upright", "imdb": 8.1, "imdbVotes": 1082660, "tmdb": 7.947, "tmdbVotes": 23505}}, {"id": "movie-spirited-away-2001", "title": "Spirited Away", "year": 2001, "type": "movie", "runtimeSeconds": 7472, "seasonCount": null, "communityRating": 8.535, "criticRating": 96, "genres": ["Animation", "Family", "Fantasy"], "overview": "A young girl, Chihiro, becomes trapped in a strange new world of spirits. When her parents undergo a mysterious transformation, she must call upon the courage she never knew she had to free her family.", "poster": "assets/movie-spirited-away-2001-poster.jpg", "backdrop": "assets/movie-spirited-away-2001-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:22:42.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 129, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 96, "rtCriticsLabel": "Certified Fresh", "rtAudience": 99, "rtAudienceLabel": "Upright", "imdb": 8.6, "imdbVotes": 987658, "tmdb": 8.536, "tmdbVotes": 19176}}, {"id": "movie-the-substance-2024", "title": "The Substance", "year": 2024, "type": "movie", "runtimeSeconds": 8531, "seasonCount": null, "communityRating": 7.135, "criticRating": 89, "genres": ["Horror", "Science Fiction"], "overview": "A fading celebrity decides to use a black market drug, a cell-replicating substance that temporarily creates a younger, better version of herself.", "poster": "assets/movie-the-substance-2024-poster.jpg", "backdrop": "assets/movie-the-substance-2024-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:30:22.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 933260, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 89, "rtCriticsLabel": "Certified Fresh", "rtAudience": 76, "rtAudienceLabel": "Upright", "imdb": 7.2, "imdbVotes": 466542, "tmdb": 7.13, "tmdbVotes": 6746}}, {"id": "movie-the-tale-of-the-princess-kaguya-2013", "title": "The Tale of The Princess Kaguya", "year": 2013, "type": "movie", "runtimeSeconds": 8218, "seasonCount": null, "communityRating": 8.1, "criticRating": 100, "genres": ["Animation", "Drama", "Fantasy"], "overview": "Found inside a shining stalk of bamboo by an old bamboo cutter and his wife, a tiny girl grows rapidly into an exquisite young lady. The mysterious young princess enthrals all who encounter her. But, ultimately, she\u2026", "poster": "assets/movie-the-tale-of-the-princess-kaguya-2013-poster.jpg", "backdrop": "assets/movie-the-tale-of-the-princess-kaguya-2013-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-07T13:40:15.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 149871, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Certified Fresh", "rtAudience": 90, "rtAudienceLabel": "Upright", "imdb": 8, "imdbVotes": 63574, "tmdb": 8.083, "tmdbVotes": 2079}}, {"id": "movie-taxi-driver-1976", "title": "Taxi Driver", "year": 1976, "type": "movie", "runtimeSeconds": 6831, "seasonCount": null, "communityRating": 8.121, "criticRating": 89, "genres": ["Crime", "Drama"], "overview": "Suffering from insomnia, disturbed loner Travis Bickle takes a job as a New York City cabbie, haunting the streets nightly, growing increasingly detached from reality as he dreams of cleaning up the filthy city.", "poster": "assets/movie-taxi-driver-1976-poster.jpg", "backdrop": "assets/movie-taxi-driver-1976-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:23:04.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 103, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 89, "rtCriticsLabel": "Certified Fresh", "rtAudience": 93, "rtAudienceLabel": "Upright", "imdb": 8.2, "imdbVotes": 1046700, "tmdb": 8.116, "tmdbVotes": 13973}}, {"id": "movie-triangle-of-sadness-2022", "title": "Triangle of Sadness", "year": 2022, "type": "movie", "runtimeSeconds": 8833, "seasonCount": null, "communityRating": 7.005, "criticRating": 71, "genres": ["Comedy", "Drama"], "overview": "A celebrity model couple are invited on a luxury cruise for the uber-rich, helmed by an unhinged, alcoholic captain. What first appears Instagrammable ends catastrophically, leaving the survivors stranded on a desert\u2026", "poster": "assets/movie-triangle-of-sadness-2022-poster.jpg", "backdrop": "assets/movie-triangle-of-sadness-2022-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:29:00.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 497828, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 72, "rtCriticsLabel": "Fresh", "rtAudience": 80, "rtAudienceLabel": "Upright", "imdb": 7.2, "imdbVotes": 221069, "tmdb": 7, "tmdbVotes": 3104}}, {"id": "movie-tsotsi-2005", "title": "Tsotsi", "year": 2005, "type": "movie", "runtimeSeconds": 5663, "seasonCount": null, "communityRating": 6.937, "criticRating": 82, "genres": ["Crime", "Drama"], "overview": "A young South African boy from the Johannesburg ghetto named Tsotsi, meaning Gangster, leaves home as a child to get away from his helpless parents. Now a teenage thug, Tsotsi finds a baby in the back seat of a car\u2026", "poster": "assets/movie-tsotsi-2005-poster.jpg", "backdrop": "assets/movie-tsotsi-2005-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:24:58.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 868, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 82, "rtCriticsLabel": "Certified Fresh", "rtAudience": 86, "rtAudienceLabel": "Upright", "imdb": 7.2, "imdbVotes": 32526, "tmdb": 6.941, "tmdbVotes": 372}}, {"id": "movie-unknown-number-the-high-school-catfish-2025", "title": "Unknown Number: The High School Catfish", "year": 2025, "type": "movie", "runtimeSeconds": 5691, "seasonCount": null, "communityRating": 6.746, "criticRating": 85, "genres": ["Documentary"], "overview": "Vulgar, taunting texts blow up the phones of a teen and her boyfriend. Who's sending them \u2014 and why? This twisty documentary reveals the shocking answer.", "poster": "assets/movie-unknown-number-the-high-school-catfish-2025-poster.jpg", "backdrop": "assets/movie-unknown-number-the-high-school-catfish-2025-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:32:10.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 1517772, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 85, "rtCriticsLabel": "Fresh", "rtAudience": 69, "rtAudienceLabel": "Upright", "imdb": 6.7, "imdbVotes": 23039, "tmdb": 6.737, "tmdbVotes": 257}}, {"id": "movie-the-uprising-2026", "title": "The Uprising", "year": 2026, "type": "movie", "runtimeSeconds": 7684, "seasonCount": null, "communityRating": 7.846, "criticRating": 55, "genres": ["Action", "Drama", "History"], "overview": "As war and plague devastate 14th-century England, a humble peasant ignites a rebellion, uniting an army of commoners to defy the King\u2019s might in a desperate fight for justice and survival.", "poster": "assets/movie-the-uprising-2026-poster.jpg", "backdrop": "assets/movie-the-uprising-2026-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-11-02T16:37:03.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 977942, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 57, "rtCriticsLabel": "Rotten", "rtAudience": 65, "rtAudienceLabel": "Upright", "imdb": 6.2, "imdbVotes": 6622, "tmdb": 7.8, "tmdbVotes": 404}}, {"id": "movie-vice-2018", "title": "Vice", "year": 2018, "type": "movie", "runtimeSeconds": 7948, "seasonCount": null, "communityRating": 7.013, "criticRating": 64, "genres": ["Drama", "Comedy", "History"], "overview": "George W. Bush picks Dick Cheney, the CEO of Halliburton Co., to be his Republican running mate in the 2000 presidential election. No stranger to politics, Cheney's impressive r\u00e9sum\u00e9 includes stints as White House\u2026", "poster": "assets/movie-vice-2018-poster.jpg", "backdrop": "assets/movie-vice-2018-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:28:30.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 429197, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 64, "rtCriticsLabel": "Fresh", "rtAudience": 61, "rtAudienceLabel": "Upright", "imdb": 7.2, "imdbVotes": 177299, "tmdb": 7.014, "tmdbVotes": 3723}}, {"id": "movie-warriors-of-the-wind-1984", "title": "Warriors of the Wind", "year": 1984, "type": "movie", "runtimeSeconds": 7022, "seasonCount": null, "communityRating": 7.941, "criticRating": 87, "genres": ["Adventure", "Animation", "Fantasy"], "overview": "After a global war, the seaside kingdom known as the Valley of the Wind remains one of the last strongholds on Earth untouched by a poisonous jungle and the powerful insects that guard it. Led by the courageous\u2026", "poster": "assets/movie-warriors-of-the-wind-1984-poster.jpg", "backdrop": "assets/movie-warriors-of-the-wind-1984-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:22:20.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 81, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 87, "rtCriticsLabel": "Fresh", "rtAudience": 91, "rtAudienceLabel": "Upright", "imdb": 8, "imdbVotes": 200154, "tmdb": 7.94, "tmdbVotes": 4260}}, {"id": "movie-we-bury-the-dead-2026", "title": "We Bury the Dead", "year": 2026, "type": "movie", "runtimeSeconds": 5693, "seasonCount": null, "communityRating": 6.153, "criticRating": 87, "genres": ["Horror", "Thriller"], "overview": "After a catastrophic military disaster reanimates the dead, Ava searches for her missing husband amidst an increasingly hostile world.", "poster": "assets/movie-we-bury-the-dead-2026-poster.jpg", "backdrop": "assets/movie-we-bury-the-dead-2026-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-08-26T05:36:00.4272328Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 1198984, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 87, "rtCriticsLabel": "Certified Fresh", "rtAudience": 45, "rtAudienceLabel": "Spilled", "imdb": 5.6, "imdbVotes": 20693, "tmdb": 6.137, "tmdbVotes": 433}}, {"id": "movie-white-hot-the-rise-fall-of-abercrombie-fitch-2022", "title": "White Hot: The Rise & Fall of Abercrombie & Fitch", "year": 2022, "type": "movie", "runtimeSeconds": 5187, "seasonCount": null, "communityRating": 5.663, "criticRating": 66, "genres": ["Documentary"], "overview": "All the cool kids were wearing it. This documentary explores A&F's pop culture reign in the late '90s and early 2000s and how it thrived on exclusion.", "poster": "assets/movie-white-hot-the-rise-fall-of-abercrombie-fitch-2022-poster.jpg", "backdrop": "assets/movie-white-hot-the-rise-fall-of-abercrombie-fitch-2022-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:30:34.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 953371, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 66, "rtCriticsLabel": "Fresh", "rtAudience": 29, "rtAudienceLabel": "Spilled", "imdb": 5.8, "imdbVotes": 5655, "tmdb": 5.7, "tmdbVotes": 102}}, {"id": "movie-the-wild-robot-2024", "title": "The Wild Robot", "year": 2024, "type": "movie", "runtimeSeconds": 6101, "seasonCount": null, "communityRating": 8.308, "criticRating": 97, "genres": ["Family", "Animation", "Science Fiction"], "overview": "After a shipwreck, an intelligent robot called Roz is stranded on an uninhabited island. To survive the harsh environment, Roz bonds with the island's animals and cares for an orphaned baby goose.", "poster": "assets/movie-the-wild-robot-2024-poster.jpg", "backdrop": "assets/movie-the-wild-robot-2024-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:31:49.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 1184918, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 97, "rtCriticsLabel": "Certified Fresh", "rtAudience": 98, "rtAudienceLabel": "Upright", "imdb": 8.1, "imdbVotes": 241134, "tmdb": 8.309, "tmdbVotes": 6819}}, {"id": "movie-the-wind-rises-2013", "title": "The Wind Rises", "year": 2013, "type": "movie", "runtimeSeconds": 8031, "seasonCount": null, "communityRating": 7.784, "criticRating": 88, "genres": ["Animation", "Drama", "History"], "overview": "A lifelong love of flight inspires Japanese aviation engineer Jiro Horikoshi, whose storied career includes the creation of the A-6M World War II fighter plane.", "poster": "assets/movie-the-wind-rises-2013-poster.jpg", "backdrop": "assets/movie-the-wind-rises-2013-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:24:38.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 149870, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 89, "rtCriticsLabel": "Certified Fresh", "rtAudience": 85, "rtAudienceLabel": "Upright", "imdb": 7.8, "imdbVotes": 115756, "tmdb": 7.783, "tmdbVotes": 3536}}, {"id": "movie-the-witcher-nightmare-of-the-wolf-2021", "title": "The Witcher: Nightmare of the Wolf", "year": 2021, "type": "movie", "runtimeSeconds": 5015, "seasonCount": null, "communityRating": 7.422, "criticRating": 100, "genres": ["Animation", "Action", "Fantasy"], "overview": "Escaping from poverty to become a witcher, Vesemir slays monsters for coin and glory, but when a new menace rises, he must face the demons of his past.", "poster": "assets/movie-the-witcher-nightmare-of-the-wolf-2021-poster.jpg", "backdrop": "assets/movie-the-witcher-nightmare-of-the-wolf-2021-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-26T04:42:03.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 666243, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": 83, "rtAudienceLabel": "Upright", "imdb": 7.2, "imdbVotes": 55759, "tmdb": 7.407, "tmdbVotes": 1159}}, {"id": "movie-the-witcher-sirens-of-the-deep-2025", "title": "The Witcher: Sirens of the Deep", "year": 2025, "type": "movie", "runtimeSeconds": 5517, "seasonCount": null, "communityRating": 6.8, "criticRating": 60, "genres": ["Animation", "Fantasy", "Action"], "overview": "When human sailors are attacked by mysterious creatures of the deep, only one person can stop the war between land and sea: the Witcher, Geralt of Rivia.", "poster": "assets/movie-the-witcher-sirens-of-the-deep-2025-poster.jpg", "backdrop": "assets/movie-the-witcher-sirens-of-the-deep-2025-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-26T05:03:26.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 1203329, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 60, "rtCriticsLabel": "Fresh", "rtAudience": 37, "rtAudienceLabel": "Spilled", "imdb": 6.1, "imdbVotes": 11799, "tmdb": 6.741, "tmdbVotes": 303}}], "shows": [{"id": "tv-adults-2025", "title": "Adults", "year": 2025, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 6.495, "criticRating": null, "genres": ["Comedy"], "overview": "A group of twenty-somethings in New York trying to be good people, despite being neither \"good\" nor \"people\" yet.", "poster": "assets/tv-adults-2025-poster.jpg", "backdrop": "assets/tv-adults-2025-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-23T21:01:41.1814765Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 260458, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 88, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.5, "tmdbVotes": 102}}, {"id": "tv-american-crime-story-2016", "title": "American Crime Story", "year": 2016, "type": "tv", "runtimeSeconds": null, "seasonCount": 3, "communityRating": 7.573, "criticRating": null, "genres": ["Crime", "Drama"], "overview": "An anthology series centered around some of history's most famous criminal investigations.", "poster": "assets/tv-american-crime-story-2016-poster.jpg", "backdrop": "assets/tv-american-crime-story-2016-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0490488Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 64513, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 84, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.585, "tmdbVotes": 1094}}, {"id": "tv-american-primeval-2025", "title": "American Primeval", "year": 2025, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.691, "criticRating": null, "genres": ["Western", "Drama", "Action & Adventure"], "overview": "A mother and son fleeing from their past form a found family while confronting a harsh landscape of freedom and cruelty in the American West.", "poster": "assets/tv-american-primeval-2025-poster.jpg", "backdrop": "assets/tv-american-primeval-2025-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0573221Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 215866, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 71, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.741, "tmdbVotes": 538}}, {"id": "tv-arrested-development-2003", "title": "Arrested Development", "year": 2003, "type": "tv", "runtimeSeconds": null, "seasonCount": 5, "communityRating": 7.925, "criticRating": null, "genres": ["Comedy"], "overview": "The story of a wealthy family that lost everything, and the one son who had no choice but to keep them all together.", "poster": "assets/tv-arrested-development-2003-poster.jpg", "backdrop": "assets/tv-arrested-development-2003-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0513048Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 4589, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 75, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.906, "tmdbVotes": 1793}}, {"id": "tv-avatar-the-last-airbender-2005", "title": "Avatar: The Last Airbender", "year": 2005, "type": "tv", "runtimeSeconds": 1440, "seasonCount": 3, "communityRating": 8.78, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "In a war-torn world of elemental magic, a young boy reawakens to undertake a dangerous mystic quest to fulfill his destiny as the Avatar, and bring peace to the world.", "poster": "assets/tv-avatar-the-last-airbender-2005-poster.jpg", "backdrop": "assets/tv-avatar-the-last-airbender-2005-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0504536Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 246, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.787, "tmdbVotes": 5215}}, {"id": "tv-b-b-vol-liefde-2021", "title": "B&B Vol Liefde", "year": 2021, "type": "tv", "runtimeSeconds": 3720, "seasonCount": 1, "communityRating": 7.2, "criticRating": null, "genres": ["Reality"], "overview": "B&B Vol Liefde is a heartwarming adventure, full of romance, excitement, and unforgettable moments. Adventurous Dutch B&B owners abroad throw their doors wide open and let their hearts speak, determined to find that\u2026", "poster": "assets/tv-b-b-vol-liefde-2021-poster.jpg", "backdrop": "assets/tv-b-b-vol-liefde-2021-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-31T22:30:11.129657Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 124428, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.2, "tmdbVotes": 10}}, {"id": "tv-the-bear-2022", "title": "The Bear", "year": 2022, "type": "tv", "runtimeSeconds": null, "seasonCount": 5, "communityRating": 8.139, "criticRating": null, "genres": ["Drama", "Comedy"], "overview": "Carmy, a young fine-dining chef, comes home to Chicago to run his family sandwich shop. As he fights to transform the shop and himself, he works alongside a rough-around-the-edges crew that ultimately reveal\u2026", "poster": "assets/tv-the-bear-2022-poster.jpg", "backdrop": "assets/tv-the-bear-2022-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0467371Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 136315, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 93, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.158, "tmdbVotes": 2025}}, {"id": "tv-blue-planet-ii-2017", "title": "Blue Planet II", "year": 2017, "type": "tv", "runtimeSeconds": 3600, "seasonCount": 1, "communityRating": 8.64, "criticRating": null, "genres": ["Documentary", "Family"], "overview": "There is nowhere more powerful and unforgiving yet more beautiful and compelling than the ocean. Join us and explore the greatest yet least known parts of our planet.", "poster": "assets/tv-blue-planet-ii-2017-poster.jpg", "backdrop": "assets/tv-blue-planet-ii-2017-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0634849Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 74313, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 97, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.6, "tmdbVotes": 380}}, {"id": "tv-breeders-2020", "title": "Breeders", "year": 2020, "type": "tv", "runtimeSeconds": 1500, "seasonCount": 4, "communityRating": 6.8, "criticRating": null, "genres": ["Comedy"], "overview": "Exposing the parental-paradox that it is possible, in the very same moment, to love your child to the horizon of the universe, while being apoplectically angry enough to want to send them there.", "poster": "assets/tv-breeders-2020-poster.jpg", "backdrop": "assets/tv-breeders-2020-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-28T18:54:21.8885435Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 93290, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 92, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.8, "tmdbVotes": 104}}, {"id": "tv-chernobyl-2019", "title": "Chernobyl", "year": 2019, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 8.718, "criticRating": null, "genres": ["Drama"], "overview": "The true story of one of the worst man-made catastrophes in history: the catastrophic nuclear accident at Chernobyl. A tale of the brave men and women who sacrificed to save Europe from unimaginable disaster.", "poster": "assets/tv-chernobyl-2019-poster.jpg", "backdrop": "assets/tv-chernobyl-2019-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0469903Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 87108, "artwork": {"posterKind": "poster", "backdropKind": "center_crop"}, "ratings": {"rtCritics": 95, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.731, "tmdbVotes": 8496}}, {"id": "tv-community-2009", "title": "Community", "year": 2009, "type": "tv", "runtimeSeconds": null, "seasonCount": 6, "communityRating": 7.997, "criticRating": null, "genres": ["Comedy"], "overview": "Follow the lives of a group of students at what is possibly the world\u2019s worst community college in the fictional locale of Greendale, Colorado.", "poster": "assets/tv-community-2009-poster.jpg", "backdrop": "assets/tv-community-2009-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0531416Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 18347, "artwork": {"posterKind": "center_crop", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 88, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.994, "tmdbVotes": 2226}}, {"id": "tv-dead-end-job-2026", "title": "Dead-End Job", "year": 2026, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.7, "criticRating": null, "genres": ["Mystery"], "overview": "Drowning in debt, a young man takes lucrative part-time jobs from a mysterious agency \u2014 only to find his hustle for more money turning nightmarish.", "poster": "assets/tv-dead-end-job-2026-poster.jpg", "backdrop": "assets/tv-dead-end-job-2026-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-11-04T18:58:01.8352857Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 289517, "artwork": {"posterKind": "center_crop", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.7, "tmdbVotes": 38}}, {"id": "tv-dopesick-2021", "title": "Dopesick", "year": 2021, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 8.015, "criticRating": null, "genres": ["Crime", "Drama"], "overview": "The story of how one company triggered the worst drug epidemic in American history. Look into the epicenter of America's struggle with opioid addiction, from a distressed Virginia mining community, to the hallways of\u2026", "poster": "assets/tv-dopesick-2021-poster.jpg", "backdrop": "assets/tv-dopesick-2021-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0580168Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 110695, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 89, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.035, "tmdbVotes": 565}}, {"id": "tv-dune-prophecy-2024", "title": "Dune: Prophecy", "year": 2024, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.213, "criticRating": null, "genres": ["Sci-Fi & Fantasy", "Drama", "Action & Adventure"], "overview": "Ten thousand years before the ascension of Paul Atreides, sisters Valya and Tula Harkonnen establish the fabled sect and female order that would become known as the Bene Gesserit to control the future of humankind.", "poster": "assets/tv-dune-prophecy-2024-poster.jpg", "backdrop": "assets/tv-dune-prophecy-2024-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-11-04T18:23:01.2908568Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 90228, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 64, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.213, "tmdbVotes": 677}}, {"id": "tv-east-of-eden-2026", "title": "East of Eden", "year": 2026, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.931, "criticRating": null, "genres": ["Drama", "Crime"], "overview": "In the early 1900s, a fiercely independent woman drives a rift between two brothers, igniting a saga that unfolds across two generations.", "poster": "assets/tv-east-of-eden-2026-poster.jpg", "backdrop": "assets/tv-east-of-eden-2026-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-23T18:07:11.3965096Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 258165, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 88, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.982, "tmdbVotes": 139}}, {"id": "tv-fallout-2024", "title": "Fallout", "year": 2024, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 8.124, "criticRating": null, "genres": ["Action & Adventure", "Sci-Fi & Fantasy", "Drama"], "overview": "The story of haves and have-nots in a world in which there's almost nothing left to have. 200 years after the apocalypse, the gentle denizens of luxury fallout shelters are forced to return to the irradiated\u2026", "poster": "assets/tv-fallout-2024-poster.jpg", "backdrop": "assets/tv-fallout-2024-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0669262Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 106379, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 94, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.106, "tmdbVotes": 3233}}, {"id": "tv-fawlty-towers-1975", "title": "Fawlty Towers", "year": 1975, "type": "tv", "runtimeSeconds": 1800, "seasonCount": 2, "communityRating": 8.295, "criticRating": null, "genres": ["Comedy"], "overview": "Owner Basil Fawlty, his wife Sybil, a chambermaid Polly, and Spanish waiter Manuel attempt to run their hotel amidst farcical situations and an array of demanding guests.", "poster": "assets/tv-fawlty-towers-1975-poster.jpg", "backdrop": "assets/tv-fawlty-towers-1975-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-19T23:26:39.7658344Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 2207, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.296, "tmdbVotes": 867}}, {"id": "tv-the-final-problem-2026", "title": "The Final Problem", "year": 2026, "type": "tv", "runtimeSeconds": 3420, "seasonCount": 1, "communityRating": 7.041, "criticRating": null, "genres": ["Crime", "Mystery"], "overview": "In the spring of 1959, a retired actor, who previously played Sherlock Holmes, must investigate a murder at a small hotel on a tiny island near Mallorca.", "poster": "assets/tv-the-final-problem-2026-poster.jpg", "backdrop": "assets/tv-the-final-problem-2026-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-11-04T19:16:12.4822791Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 290720, "artwork": {"posterKind": "center_crop", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.041, "tmdbVotes": 49}}, {"id": "tv-the-four-seasons-2025", "title": "The Four Seasons", "year": 2025, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 6.879, "criticRating": null, "genres": ["Comedy"], "overview": "The decades-long friendship between three married couples is tested when one divorces, complicating their tradition of quarterly weekend getaways.", "poster": "assets/tv-the-four-seasons-2025-poster.jpg", "backdrop": "assets/tv-the-four-seasons-2025-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-28T18:36:42.5326384Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 243316, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 81, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.892, "tmdbVotes": 204}}, {"id": "tv-the-get-down-2016", "title": "The Get Down", "year": 2016, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.3, "criticRating": null, "genres": ["Drama"], "overview": "In 1977 New York City, the talented and soulful youth of the South Bronx chase dreams and breakneck beats to transform music history.", "poster": "assets/tv-the-get-down-2016-poster.jpg", "backdrop": "assets/tv-the-get-down-2016-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0497737Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 65345, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 81, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.3, "tmdbVotes": 196}}, {"id": "tv-how-to-change-your-mind-2022", "title": "How to Change Your Mind", "year": 2022, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.76, "criticRating": null, "genres": ["Documentary", "Mystery"], "overview": "Author Michael Pollan leads the way in this docuseries exploring the history and uses of psychedelics, including LSD, psilocybin, MDMA and mescaline.", "poster": "assets/tv-how-to-change-your-mind-2022-poster.jpg", "backdrop": "assets/tv-how-to-change-your-mind-2022-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0601399Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 204304, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.8, "tmdbVotes": 53}}, {"id": "tv-interrogation-2020", "title": "Interrogation", "year": 2020, "type": "tv", "runtimeSeconds": 2700, "seasonCount": 1, "communityRating": 6.788, "criticRating": null, "genres": ["Drama", "Crime"], "overview": "Based on a true story that spanned more than 30 years in which a young man was charged and convicted of brutally murdering his mother. Each episode is structured around an interrogation taken directly from the real\u2026", "poster": "assets/tv-interrogation-2020-poster.jpg", "backdrop": "assets/tv-interrogation-2020-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-26T05:52:06.1068207Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 96488, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 57, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.9, "tmdbVotes": 54}}, {"id": "tv-it-s-always-sunny-in-philadelphia-2005", "title": "It's Always Sunny in Philadelphia", "year": 2005, "type": "tv", "runtimeSeconds": null, "seasonCount": 18, "communityRating": 8.2, "criticRating": null, "genres": ["Comedy"], "overview": "Four egocentric friends run a neighborhood Irish pub in Philadelphia and try to find their way through the adult world of work and relationships. Unfortunately, their warped views and precarious judgments often lead\u2026", "poster": "assets/tv-it-s-always-sunny-in-philadelphia-2005-poster.jpg", "backdrop": "assets/tv-it-s-always-sunny-in-philadelphia-2005-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0485774Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 2710, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 94, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.253, "tmdbVotes": 1457}}, {"id": "tv-a-knight-of-the-seven-kingdoms-2026", "title": "A Knight of the Seven Kingdoms", "year": 2026, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 8.431, "criticRating": null, "genres": ["Drama", "Sci-Fi & Fantasy", "Action & Adventure"], "overview": "A century before the events of Game of Thrones, two unlikely heroes wandered Westeros: a young, naive but courageous knight, Ser Duncan the Tall, and his diminutive squire, Egg. Set in an age when the Targaryen line\u2026", "poster": "assets/tv-a-knight-of-the-seven-kingdoms-2026-poster.jpg", "backdrop": "assets/tv-a-knight-of-the-seven-kingdoms-2026-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0493344Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 224372, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 94, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.4, "tmdbVotes": 1266}}, {"id": "tv-landman-2024", "title": "Landman", "year": 2024, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 8.194, "criticRating": null, "genres": ["Drama"], "overview": "Set in the proverbial boomtowns of West-Texas and a modern-day tale of fortune-seeking in the world of oil rigs, the series is an upstairs/downstairs story of roughnecks and wildcat billionaires that are fueling a\u2026", "poster": "assets/tv-landman-2024-poster.jpg", "backdrop": "assets/tv-landman-2024-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-22T21:38:18.0973875Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 157741, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 80, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.209, "tmdbVotes": 668}}, {"id": "tv-the-last-of-us-2023", "title": "The Last of Us", "year": 2023, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 8.419, "criticRating": null, "genres": ["Drama"], "overview": "Twenty years after modern civilization has been destroyed, Joel, a hardened survivor, is hired to smuggle Ellie, a 14-year-old girl, out of an oppressive quarantine zone. What starts as a small job soon becomes a\u2026", "poster": "assets/tv-the-last-of-us-2023-poster.jpg", "backdrop": "assets/tv-the-last-of-us-2023-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0640955Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 100088, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 94, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.4, "tmdbVotes": 7485}}, {"id": "tv-last-samurai-standing-2025", "title": "Last Samurai Standing", "year": 2025, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.805, "criticRating": null, "genres": ["Action & Adventure", "Drama"], "overview": "In the early Meiji era, Shujiro, once known as an undefeated samurai, decides to participate in a deadly survival game to save his family and villagers.", "poster": "assets/tv-last-samurai-standing-2025-poster.jpg", "backdrop": "assets/tv-last-samurai-standing-2025-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0622526Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 252193, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.812, "tmdbVotes": 271}}, {"id": "tv-lord-of-the-flies-2026", "title": "Lord of the Flies", "year": 2026, "type": "tv", "runtimeSeconds": 3480, "seasonCount": 1, "communityRating": 7.571, "criticRating": null, "genres": ["Drama", "Action & Adventure"], "overview": "After a plane crash, a group of schoolboys find themselves stranded on a tropical island without adults. Ralph is elected leader and, with the help of the intelligent Piggy, strives to maintain order and\u2026", "poster": "assets/tv-lord-of-the-flies-2026-poster.jpg", "backdrop": "assets/tv-lord-of-the-flies-2026-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0645648Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 270572, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 91, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.58, "tmdbVotes": 138}}, {"id": "tv-the-lord-of-the-rings-the-rings-of-power-2022", "title": "The Lord of the Rings: The Rings of Power", "year": 2022, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 7.233, "criticRating": null, "genres": ["Action & Adventure", "Sci-Fi & Fantasy", "Drama"], "overview": "Beginning in a time of relative peace, we follow an ensemble cast of characters as they confront the re-emergence of evil to Middle-earth. From the darkest depths of the Misty Mountains, to the majestic forests of\u2026", "poster": "assets/tv-the-lord-of-the-rings-the-rings-of-power-2022-poster.jpg", "backdrop": "assets/tv-the-lord-of-the-rings-the-rings-of-power-2022-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0618904Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 84773, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 84, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.211, "tmdbVotes": 4003}}, {"id": "tv-love-death-robots-2019", "title": "Love, Death & Robots", "year": 2019, "type": "tv", "runtimeSeconds": null, "seasonCount": 4, "communityRating": 8.21, "criticRating": null, "genres": ["Animation", "Sci-Fi & Fantasy"], "overview": "Terrifying creatures, wicked surprises and dark comedy converge in this NSFW anthology of animated stories presented by Tim Miller and David Fincher.", "poster": "assets/tv-love-death-robots-2019-poster.jpg", "backdrop": "assets/tv-love-death-robots-2019-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0460964Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 86831, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 89, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.203, "tmdbVotes": 4238}}, {"id": "tv-maniac-2018", "title": "Maniac", "year": 2018, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.338, "criticRating": null, "genres": ["Comedy", "Drama", "Sci-Fi & Fantasy"], "overview": "Two strangers are drawn to a mysterious pharmaceutical trial that will, they're assured, with no complications or side-effects whatsoever, solve all of their problems, permanently. Things do not go as planned.", "poster": "assets/tv-maniac-2018-poster.jpg", "backdrop": "assets/tv-maniac-2018-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-20T19:42:30.955548Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 73411, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 84, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.323, "tmdbVotes": 1073}}, {"id": "tv-mussolini-son-of-the-century-2024", "title": "Mussolini: Son of the Century", "year": 2024, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 8.135, "criticRating": null, "genres": ["Drama", "War & Politics"], "overview": "The rise of Benito Mussolini and the birth of fascism in Italy, chronicling a country\u2019s surrender to dictatorship and the relentless ascent of a man who rose from his ashes time and again.", "poster": "assets/tv-mussolini-son-of-the-century-2024-poster.jpg", "backdrop": "assets/tv-mussolini-son-of-the-century-2024-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0586588Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 212333, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 96, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.1, "tmdbVotes": 179}}, {"id": "tv-the-night-manager-2016", "title": "The Night Manager", "year": 2016, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 7.74, "criticRating": null, "genres": ["Drama", "Mystery", "Crime"], "overview": "Former British soldier Jonathan Pine navigates the shadowy recesses of Whitehall and Washington where an unholy alliance operates between the intelligence community and the secret arms trade. To infiltrate the inner\u2026", "poster": "assets/tv-the-night-manager-2016-poster.jpg", "backdrop": "assets/tv-the-night-manager-2016-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0663672Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 61859, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 88, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.7, "tmdbVotes": 1422}}, {"id": "tv-one-piece-2023", "title": "ONE PIECE", "year": 2023, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 8.118, "criticRating": null, "genres": ["Action & Adventure", "Sci-Fi & Fantasy"], "overview": "With his straw hat and ragtag crew, young pirate Monkey D. Luffy goes on an epic voyage for treasure.", "poster": "assets/tv-one-piece-2023-poster.jpg", "backdrop": "assets/tv-one-piece-2023-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0439378Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 111110, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 93, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.104, "tmdbVotes": 1988}}, {"id": "tv-only-murders-in-the-building-2021", "title": "Only Murders in the Building", "year": 2021, "type": "tv", "runtimeSeconds": null, "seasonCount": 5, "communityRating": 8.438, "criticRating": null, "genres": ["Comedy", "Mystery", "Crime"], "overview": "Three strangers share an obsession with true crime and suddenly find themselves wrapped up in one.", "poster": "assets/tv-only-murders-in-the-building-2021-poster.jpg", "backdrop": "assets/tv-only-murders-in-the-building-2021-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0594614Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 107113, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 95, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.398, "tmdbVotes": 2333}}, {"id": "tv-over-the-garden-wall-2014", "title": "Over the Garden Wall", "year": 2014, "type": "tv", "runtimeSeconds": 720, "seasonCount": 1, "communityRating": 8.6, "criticRating": null, "genres": ["Mystery", "Sci-Fi & Fantasy", "Animation"], "overview": "Two brothers, Wirt and Greg, find themselves lost in the Unknown; a strange forest adrift in time. With the help of a wise old Woodsman and a foul-tempered bluebird named Beatrice, Wirt and Greg must travel across\u2026", "poster": "assets/tv-over-the-garden-wall-2014-poster.jpg", "backdrop": "assets/tv-over-the-garden-wall-2014-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0455757Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 61617, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.6, "tmdbVotes": 1854}}, {"id": "tv-peaky-blinders-2013", "title": "Peaky Blinders", "year": 2013, "type": "tv", "runtimeSeconds": null, "seasonCount": 6, "communityRating": 8.5, "criticRating": null, "genres": ["Drama", "Crime"], "overview": "A gangster family epic set in 1919 Birmingham, England and centered on a gang who sew razor blades in the peaks of their caps, and their fierce boss Tommy Shelby, who means to move up in the world.", "poster": "assets/tv-peaky-blinders-2013-poster.jpg", "backdrop": "assets/tv-peaky-blinders-2013-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0539185Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 60574, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 93, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.5, "tmdbVotes": 11506}}, {"id": "tv-the-pitt-2025", "title": "The Pitt", "year": 2025, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 8.729, "criticRating": null, "genres": ["Drama"], "overview": "The staff of Pittsburgh's Trauma Medical Center work around the clock to save lives in an overcrowded and underfunded emergency department.", "poster": "assets/tv-the-pitt-2025-poster.jpg", "backdrop": "assets/tv-the-pitt-2025-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0582942Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 250307, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 96, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.731, "tmdbVotes": 1046}}, {"id": "tv-pluribus-2025", "title": "Pluribus", "year": 2025, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.936, "criticRating": null, "genres": ["Drama", "Sci-Fi & Fantasy"], "overview": "The most miserable person on Earth must save the world from happiness.", "poster": "assets/tv-pluribus-2025-poster.jpg", "backdrop": "assets/tv-pluribus-2025-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0674462Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 225171, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 99, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.921, "tmdbVotes": 1191}}, {"id": "tv-ripley-2024", "title": "RIPLEY", "year": 2024, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.911, "criticRating": null, "genres": ["Drama"], "overview": "A grifter in 1960s New York is hired to convince a wealthy man's son to return home from Italy and begins a life of deceit, fraud and murder.", "poster": "assets/tv-ripley-2024-poster.jpg", "backdrop": "assets/tv-ripley-2024-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0658942Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 94028, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 86, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.909, "tmdbVotes": 453}}, {"id": "tv-say-nothing-2024", "title": "Say Nothing", "year": 2024, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.462, "criticRating": null, "genres": ["Drama", "Crime"], "overview": "Through the eyes of various Irish Republican Army (IRA) members, explore the extremes some people will go to in the name of their beliefs, the way a deeply divided society can suddenly tip over into armed conflict,\u2026", "poster": "assets/tv-say-nothing-2024-poster.jpg", "backdrop": "assets/tv-say-nothing-2024-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0499752Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 245256, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 94, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.475, "tmdbVotes": 122}}, {"id": "tv-severance-2022", "title": "Severance", "year": 2022, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 8.396, "criticRating": null, "genres": ["Drama", "Mystery", "Sci-Fi & Fantasy"], "overview": "Mark leads a team of office workers whose memories have been surgically divided between their work and personal lives. When a mysterious colleague appears outside of work, it begins a journey to discover the truth\u2026", "poster": "assets/tv-severance-2022-poster.jpg", "backdrop": "assets/tv-severance-2022-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0598478Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 95396, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 95, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.389, "tmdbVotes": 3095}}, {"id": "tv-six-feet-under-2001", "title": "Six Feet Under", "year": 2001, "type": "tv", "runtimeSeconds": null, "seasonCount": 5, "communityRating": 8.115, "criticRating": null, "genres": ["Drama"], "overview": "When death is your business, what is your life? For the Fisher family, the world outside of their family-owned funeral home continues to be at least as challenging as\u2014and far less predictable than\u2014the one inside.", "poster": "assets/tv-six-feet-under-2001-poster.jpg", "backdrop": "assets/tv-six-feet-under-2001-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-26T04:04:05.108787Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 1274, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 81, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.1, "tmdbVotes": 1192}}, {"id": "tv-undercover-2019", "title": "Undercover", "year": 2019, "type": "tv", "runtimeSeconds": 3000, "seasonCount": 3, "communityRating": 7.5, "criticRating": null, "genres": ["Crime", "Drama"], "overview": "Undercover agents infiltrate a drug kingpin's operation by posing as a couple at the campground where he spends his weekends. Inspired by real events.", "poster": "assets/tv-undercover-2019-poster.jpg", "backdrop": "assets/tv-undercover-2019-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0570153Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 86942, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.5, "tmdbVotes": 186}}, {"id": "tv-upload-2020", "title": "Upload", "year": 2020, "type": "tv", "runtimeSeconds": null, "seasonCount": 4, "communityRating": 7.781, "criticRating": null, "genres": ["Comedy", "Sci-Fi & Fantasy", "Drama"], "overview": "In 2033, people who are near death can be \u201cuploaded\u201d into virtual reality hotels run by 6 tech firms. Cash-strapped Nora lives in Brooklyn and works customer service for the luxurious \u201cLakeview\u201d digital afterlife.\u2026", "poster": "assets/tv-upload-2020-poster.jpg", "backdrop": "assets/tv-upload-2020-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0566967Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 86248, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 87, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.757, "tmdbVotes": 1511}}, {"id": "tv-the-walk-in-2022", "title": "The Walk-In", "year": 2022, "type": "tv", "runtimeSeconds": 2760, "seasonCount": 1, "communityRating": 6.9, "criticRating": null, "genres": ["Drama", "Crime"], "overview": "Forced to flee the UK and go into hiding in the 1990s, when he became a mole from within the BNP, Matthew Collins returned to Britain to make a new life for himself, working with young white men in the fight against\u2026", "poster": "assets/tv-the-walk-in-2022-poster.jpg", "backdrop": "assets/tv-the-walk-in-2022-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0654569Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 210664, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 80, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7, "tmdbVotes": 50}}, {"id": "tv-the-white-lotus-2021", "title": "The White Lotus", "year": 2021, "type": "tv", "runtimeSeconds": null, "seasonCount": 3, "communityRating": 7.596, "criticRating": null, "genres": ["Comedy", "Drama", "Mystery"], "overview": "Follow the exploits of various guests and employees at an exclusive tropical resort over the span of a week as with each passing day, a darker complexity emerges in these picture-perfect travelers, the hotel\u2019s\u2026", "poster": "assets/tv-the-white-lotus-2021-poster.jpg", "backdrop": "assets/tv-the-white-lotus-2021-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0546438Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 111803, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 90, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.599, "tmdbVotes": 1604}}, {"id": "tv-widow-s-bay-2026", "title": "Widow's Bay", "year": 2026, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 8.172, "criticRating": null, "genres": ["Drama", "Comedy", "Mystery"], "overview": "The mayor of a New England town resolves to turn it into the next tourist hot spot, despite local warnings that it's cursed.", "poster": "assets/tv-widow-s-bay-2026-poster.jpg", "backdrop": "assets/tv-widow-s-bay-2026-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-20T10:27:12.7003979Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 270476, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 98, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8, "tmdbVotes": 585}}, {"id": "tv-the-witcher-2019", "title": "The Witcher", "year": 2019, "type": "tv", "runtimeSeconds": null, "seasonCount": 4, "communityRating": 7.905, "criticRating": null, "genres": ["Drama", "Action & Adventure"], "overview": "Geralt of Rivia, a mutated monster-hunter for hire, journeys toward his destiny in a turbulent world where people often prove more wicked than beasts.", "poster": "assets/tv-the-witcher-2019-poster.jpg", "backdrop": "assets/tv-the-witcher-2019-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0552369Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 71912, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 75, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.88, "tmdbVotes": 6997}}, {"id": "tv-yellowjackets-2021", "title": "Yellowjackets", "year": 2021, "type": "tv", "runtimeSeconds": null, "seasonCount": 3, "communityRating": 7.449, "criticRating": null, "genres": ["Drama", "Mystery"], "overview": "This equal parts survival epic, psychological horror story and coming-of-age drama tells the saga of a team of wildly talented high school girls soccer players who become the (un)lucky survivors of a plane crash deep\u2026", "poster": "assets/tv-yellowjackets-2021-poster.jpg", "backdrop": "assets/tv-yellowjackets-2021-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0577612Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 117488, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 92, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.431, "tmdbVotes": 1070}}], "anime": [], "resume": [{"id": "episode-episode-1-2025-s1e1", "title": "Episode 1", "year": 2025, "type": "episode", "runtimeSeconds": 3618, "seasonCount": null, "communityRating": 7.357, "criticRating": null, "genres": ["Biography", "Drama", "History"], "overview": "Mussolini had just founded the Fasci di Combattimento when D'Annunzio took Fiume. Mussolini hoped to capitalize on the poet's achievement in the electoral arena.", "poster": "assets/episode-episode-1-2025-s1e1-poster.jpg", "backdrop": "assets/episode-episode-1-2025-s1e1-backdrop.jpg", "played": false, "playCount": 1, "resumeSeconds": 489.55, "progress": 0.1353, "addedAt": "2026-07-17T13:52:48.0000000Z", "lastPlayedAt": "2026-11-04T19:01:49.9731435Z", "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "Mussolini: Son of the Century", "seasonNumber": 1, "episodeNumber": 1, "artwork": {"posterKind": "center_crop", "backdropKind": "backdrop"}}], "nextUp": [{"id": "episode-no-honeymoon-2020-s1e8", "title": "No Honeymoon", "year": 2020, "type": "episode", "runtimeSeconds": 1499, "seasonCount": null, "communityRating": 6.7, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "Paul attempts to focus on his upcoming wedding but is constantly thwarted by his family; Ally is distracted by work, Luke is misbehaving at school and Leah (Stella Gonet) doesn\u2019t understand why they are even\u2026", "poster": "assets/episode-no-honeymoon-2020-s1e8-poster.jpg", "backdrop": "assets/episode-no-honeymoon-2020-s1e8-backdrop.jpg", "played": false, "playCount": 1, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-28T19:00:50.0000000Z", "lastPlayedAt": "2026-11-03T20:57:58.3314947Z", "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "Breeders", "seasonNumber": 1, "episodeNumber": 8, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}, {"id": "episode-notapusy-2005-s3e4", "title": "Notapusy", "year": 2005, "type": "episode", "runtimeSeconds": 1334, "seasonCount": null, "communityRating": 8.125, "criticRating": null, "genres": ["Comedy"], "overview": "To prove he's a man to Rita, Michael and his nephew Steve Holt compete in the Church And State Fair's annual triathlon. George Sr. tries to scare some at-risk youth, and Tobias tries to help George-Michael's\u2026", "poster": "assets/episode-notapusy-2005-s3e4-poster.jpg", "backdrop": "assets/episode-notapusy-2005-s3e4-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T12:17:58.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "Arrested Development", "seasonNumber": 3, "episodeNumber": 4, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}, {"id": "episode-the-man-who-would-be-vogue-2018-s2e1", "title": "The Man Who Would Be Vogue", "year": 2018, "type": "episode", "runtimeSeconds": 3203, "seasonCount": null, "communityRating": 7.459, "criticRating": null, "genres": ["Biography", "Crime", "Drama"], "overview": "The murder of Gianni Versace turns the eyes of the world onto Miami Beach.", "poster": "assets/episode-the-man-who-would-be-vogue-2018-s2e1-poster.jpg", "backdrop": "assets/episode-the-man-who-would-be-vogue-2018-s2e1-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T13:29:35.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "American Crime Story", "seasonNumber": 2, "episodeNumber": 1, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}, {"id": "episode-tomorrow-2024-s3e1", "title": "Tomorrow", "year": 2024, "type": "episode", "runtimeSeconds": 2207, "seasonCount": null, "communityRating": 7.6, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "The next day and the days that led to it.", "poster": "assets/episode-tomorrow-2024-s3e1-poster.jpg", "backdrop": "assets/episode-tomorrow-2024-s3e1-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T13:46:39.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "The Bear", "seasonNumber": 3, "episodeNumber": 1, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}, {"id": "episode-episode-1-2025-s1e1", "title": "Episode 1", "year": 2025, "type": "episode", "runtimeSeconds": 3618, "seasonCount": null, "communityRating": 7.357, "criticRating": null, "genres": ["Biography", "Drama", "History"], "overview": "Mussolini had just founded the Fasci di Combattimento when D'Annunzio took Fiume. Mussolini hoped to capitalize on the poet's achievement in the electoral arena.", "poster": "assets/episode-episode-1-2025-s1e1-poster.jpg", "backdrop": "assets/episode-episode-1-2025-s1e1-backdrop.jpg", "played": false, "playCount": 1, "resumeSeconds": 489.55, "progress": 0.1353, "addedAt": "2026-07-17T13:52:48.0000000Z", "lastPlayedAt": "2026-11-04T19:01:49.9731435Z", "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "Mussolini: Son of the Century", "seasonNumber": 1, "episodeNumber": 1, "artwork": {"posterKind": "center_crop", "backdropKind": "backdrop"}}], "recentlyAdded": [{"id": "tv-the-final-problem-2026", "title": "The Final Problem", "year": 2026, "type": "tv", "runtimeSeconds": 3420, "seasonCount": 1, "communityRating": 7.041, "criticRating": null, "genres": ["Crime", "Mystery"], "overview": "In the spring of 1959, a retired actor, who previously played Sherlock Holmes, must investigate a murder at a small hotel on a tiny island near Mallorca.", "poster": "assets/tv-the-final-problem-2026-poster.jpg", "backdrop": "assets/tv-the-final-problem-2026-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-11-04T19:16:12.4822791Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 290720, "artwork": {"posterKind": "center_crop", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.041, "tmdbVotes": 49}}, {"id": "tv-dead-end-job-2026", "title": "Dead-End Job", "year": 2026, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.7, "criticRating": null, "genres": ["Mystery"], "overview": "Drowning in debt, a young man takes lucrative part-time jobs from a mysterious agency \u2014 only to find his hustle for more money turning nightmarish.", "poster": "assets/tv-dead-end-job-2026-poster.jpg", "backdrop": "assets/tv-dead-end-job-2026-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-11-04T18:58:01.8352857Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 289517, "artwork": {"posterKind": "center_crop", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.7, "tmdbVotes": 38}}, {"id": "tv-dune-prophecy-2024", "title": "Dune: Prophecy", "year": 2024, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.213, "criticRating": null, "genres": ["Sci-Fi & Fantasy", "Drama", "Action & Adventure"], "overview": "Ten thousand years before the ascension of Paul Atreides, sisters Valya and Tula Harkonnen establish the fabled sect and female order that would become known as the Bene Gesserit to control the future of humankind.", "poster": "assets/tv-dune-prophecy-2024-poster.jpg", "backdrop": "assets/tv-dune-prophecy-2024-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-11-04T18:23:01.2908568Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 90228, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 64, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.213, "tmdbVotes": 677}}, {"id": "movie-the-uprising-2026", "title": "The Uprising", "year": 2026, "type": "movie", "runtimeSeconds": 7684, "seasonCount": null, "communityRating": 7.846, "criticRating": 55, "genres": ["Action", "Drama", "History"], "overview": "As war and plague devastate 14th-century England, a humble peasant ignites a rebellion, uniting an army of commoners to defy the King\u2019s might in a desperate fight for justice and survival.", "poster": "assets/movie-the-uprising-2026-poster.jpg", "backdrop": "assets/movie-the-uprising-2026-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-11-02T16:37:03.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 977942, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 57, "rtCriticsLabel": "Rotten", "rtAudience": 65, "rtAudienceLabel": "Upright", "imdb": 6.2, "imdbVotes": 6622, "tmdb": 7.8, "tmdbVotes": 404}}, {"id": "movie-jennifer-s-body-2009", "title": "Jennifer's Body", "year": 2009, "type": "movie", "runtimeSeconds": 6450, "seasonCount": null, "communityRating": 6.012, "criticRating": 47, "genres": ["Horror", "Comedy"], "overview": "Jennifer, a gorgeous, seductive cheerleader takes evil to a whole new level after she's possessed by a sinister demon. Now it's up to her best friend to stop Jennifer's reign of terror before it's too late.", "poster": "assets/movie-jennifer-s-body-2009-poster.jpg", "backdrop": "assets/movie-jennifer-s-body-2009-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-30T03:37:04.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 19994, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 47, "rtCriticsLabel": "Rotten", "rtAudience": 36, "rtAudienceLabel": "Spilled", "imdb": 5.6, "imdbVotes": 179710, "tmdb": 6.013, "tmdbVotes": 4481}}, {"id": "tv-breeders-2020", "title": "Breeders", "year": 2020, "type": "tv", "runtimeSeconds": 1500, "seasonCount": 4, "communityRating": 6.8, "criticRating": null, "genres": ["Comedy"], "overview": "Exposing the parental-paradox that it is possible, in the very same moment, to love your child to the horizon of the universe, while being apoplectically angry enough to want to send them there.", "poster": "assets/tv-breeders-2020-poster.jpg", "backdrop": "assets/tv-breeders-2020-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-28T18:54:21.8885435Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 93290, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 92, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.8, "tmdbVotes": 104}}, {"id": "tv-the-four-seasons-2025", "title": "The Four Seasons", "year": 2025, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 6.879, "criticRating": null, "genres": ["Comedy"], "overview": "The decades-long friendship between three married couples is tested when one divorces, complicating their tradition of quarterly weekend getaways.", "poster": "assets/tv-the-four-seasons-2025-poster.jpg", "backdrop": "assets/tv-the-four-seasons-2025-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-28T18:36:42.5326384Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 243316, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 81, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.892, "tmdbVotes": 204}}, {"id": "tv-adults-2025", "title": "Adults", "year": 2025, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 6.495, "criticRating": null, "genres": ["Comedy"], "overview": "A group of twenty-somethings in New York trying to be good people, despite being neither \"good\" nor \"people\" yet.", "poster": "assets/tv-adults-2025-poster.jpg", "backdrop": "assets/tv-adults-2025-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-23T21:01:41.1814765Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 260458, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 88, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.5, "tmdbVotes": 102}}, {"id": "tv-east-of-eden-2026", "title": "East of Eden", "year": 2026, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.931, "criticRating": null, "genres": ["Drama", "Crime"], "overview": "In the early 1900s, a fiercely independent woman drives a rift between two brothers, igniting a saga that unfolds across two generations.", "poster": "assets/tv-east-of-eden-2026-poster.jpg", "backdrop": "assets/tv-east-of-eden-2026-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-23T18:07:11.3965096Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 258165, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 88, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.982, "tmdbVotes": 139}}, {"id": "movie-fighting-with-my-family-2019", "title": "Fighting with My Family", "year": 2019, "type": "movie", "runtimeSeconds": 6509, "seasonCount": null, "communityRating": 6.84, "criticRating": 93, "genres": ["Comedy"], "overview": "Born into a tight-knit wrestling family, Paige and her brother Zak are ecstatic when they get the once-in-a-lifetime opportunity to try out for the WWE. But when only Paige earns a spot in the competitive training\u2026", "poster": "assets/movie-fighting-with-my-family-2019-poster.jpg", "backdrop": "assets/movie-fighting-with-my-family-2019-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-22T22:10:59.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 445629, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 93, "rtCriticsLabel": "Certified Fresh", "rtAudience": 86, "rtAudienceLabel": "Upright", "imdb": 7, "imdbVotes": 94576, "tmdb": 6.837, "tmdbVotes": 1952}}, {"id": "tv-landman-2024", "title": "Landman", "year": 2024, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 8.194, "criticRating": null, "genres": ["Drama"], "overview": "Set in the proverbial boomtowns of West-Texas and a modern-day tale of fortune-seeking in the world of oil rigs, the series is an upstairs/downstairs story of roughnecks and wildcat billionaires that are fueling a\u2026", "poster": "assets/tv-landman-2024-poster.jpg", "backdrop": "assets/tv-landman-2024-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-22T21:38:18.0973875Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 157741, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 80, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.209, "tmdbVotes": 668}}, {"id": "tv-fawlty-towers-1975", "title": "Fawlty Towers", "year": 1975, "type": "tv", "runtimeSeconds": 1800, "seasonCount": 2, "communityRating": 8.295, "criticRating": null, "genres": ["Comedy"], "overview": "Owner Basil Fawlty, his wife Sybil, a chambermaid Polly, and Spanish waiter Manuel attempt to run their hotel amidst farcical situations and an array of demanding guests.", "poster": "assets/tv-fawlty-towers-1975-poster.jpg", "backdrop": "assets/tv-fawlty-towers-1975-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-19T23:26:39.7658344Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 2207, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.296, "tmdbVotes": 867}}], "discover": [{"id": "movie-12-years-a-slave-2013", "title": "12 Years a Slave", "year": 2013, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "History"], "overview": "In the pre-Civil War United States, Solomon Northup, a free black man from upstate New York, is abducted and sold into slavery. Facing cruelty as well as unexpected kindnesses Solomon struggles not only to stay\u2026", "poster": "assets/movie-12-years-a-slave-2013-poster.jpg", "backdrop": "assets/movie-12-years-a-slave-2013-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 76203, "ratings": {"rtCritics": 95, "rtCriticsLabel": "Certified Fresh", "rtAudience": 90, "rtAudienceLabel": "Upright", "imdb": 8.1, "imdbVotes": 796313, "tmdb": 7.927, "tmdbVotes": 12335}}, {"id": "movie-101-dalmatians-ii-patch-s-london-adventure-2003", "title": "101 Dalmatians II: Patch's London Adventure", "year": 2003, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Family", "Animation", "Adventure"], "overview": "Being one of 101 takes its toll on Patch, who doesn't feel unique. When he's accidentally left behind on moving day, he meets his idol, Thunderbolt, who enlists him on a publicity campaign.", "poster": "assets/movie-101-dalmatians-ii-patch-s-london-adventure-2003-poster.jpg", "backdrop": "assets/movie-101-dalmatians-ii-patch-s-london-adventure-2003-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 13654, "ratings": {"rtCritics": 67, "rtCriticsLabel": "Fresh", "rtAudience": 41, "rtAudienceLabel": "Spilled", "imdb": 5.7, "imdbVotes": 12343, "tmdb": 6.025, "tmdbVotes": 1274}}, {"id": "movie-absolution-2024", "title": "Absolution", "year": 2024, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action", "Crime", "Thriller"], "overview": "An aging ex-boxer gangster working as muscle for a Boston crime boss receives an upsetting diagnosis. Despite a faltering memory, he attempts to rectify the sins of his past and reconnect with his estranged\u2026", "poster": "assets/movie-absolution-2024-poster.jpg", "backdrop": "assets/movie-absolution-2024-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 974453, "ratings": {"rtCritics": 56, "rtCriticsLabel": "Rotten", "rtAudience": 32, "rtAudienceLabel": "Spilled", "imdb": 5.2, "imdbVotes": 11413, "tmdb": 5.906, "tmdbVotes": 564}}, {"id": "movie-addicted-2014", "title": "Addicted", "year": 2014, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Thriller"], "overview": "A gallerist risks her family and flourishing career when she enters into an affair with a talented painter and slowly loses control of her life.", "poster": "assets/movie-addicted-2014-poster.jpg", "backdrop": "assets/movie-addicted-2014-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 235271, "ratings": {"rtCritics": 7, "rtCriticsLabel": "Rotten", "rtAudience": 51, "rtAudienceLabel": "Spilled", "imdb": 5, "imdbVotes": 13131, "tmdb": 5.928, "tmdbVotes": 466}}, {"id": "movie-all-the-money-in-the-world-2017", "title": "All the Money in the World", "year": 2017, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Crime", "History", "Thriller"], "overview": "The story of the kidnapping of 16-year-old John Paul Getty III and the desperate attempt by his devoted mother to convince his billionaire grandfather Jean Paul Getty to pay the ransom.", "poster": "assets/movie-all-the-money-in-the-world-2017-poster.jpg", "backdrop": "assets/movie-all-the-money-in-the-world-2017-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 446791, "ratings": {"rtCritics": 79, "rtCriticsLabel": "Certified Fresh", "rtAudience": 66, "rtAudienceLabel": "Upright", "imdb": 6.8, "imdbVotes": 97448, "tmdb": 6.493, "tmdbVotes": 2493}}, {"id": "movie-the-alto-knights-2025", "title": "The Alto Knights", "year": 2025, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Crime", "Drama"], "overview": "Two of New York's most notorious organized crime bosses, Frank Costello and Vito Genovese, vie for control of the city's streets. Once the best of friends, petty jealousies and a series of betrayals place them on a\u2026", "poster": "assets/movie-the-alto-knights-2025-poster.jpg", "backdrop": "assets/movie-the-alto-knights-2025-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 1013601, "ratings": {"rtCritics": 39, "rtCriticsLabel": "Rotten", "rtAudience": 71, "rtAudienceLabel": "Upright", "imdb": 5.9, "imdbVotes": 23017, "tmdb": 6.223, "tmdbVotes": 485}}, {"id": "movie-the-amazing-spider-man-2-2014", "title": "The Amazing Spider-Man 2", "year": 2014, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action", "Adventure", "Science Fiction"], "overview": "For Peter Parker, life is busy. Between taking out the bad guys as Spider-Man and spending time with the person he loves, Gwen Stacy, high school graduation cannot come quickly enough. Peter has not forgotten about\u2026", "poster": "assets/movie-the-amazing-spider-man-2-2014-poster.jpg", "backdrop": "assets/movie-the-amazing-spider-man-2-2014-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 102382, "ratings": {"rtCritics": 51, "rtCriticsLabel": "Rotten", "rtAudience": 64, "rtAudienceLabel": "Upright", "imdb": 6.6, "imdbVotes": 611981, "tmdb": 6.567, "tmdbVotes": 14919}}, {"id": "movie-ant-man-and-the-wasp-quantumania-2023", "title": "Ant-Man and the Wasp: Quantumania", "year": 2023, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action", "Adventure", "Science Fiction"], "overview": "Super-Hero partners Scott Lang and Hope van Dyne, along with with Hope's parents Janet van Dyne and Hank Pym, and Scott's daughter Cassie Lang, find themselves exploring the Quantum Realm, interacting with strange\u2026", "poster": "assets/movie-ant-man-and-the-wasp-quantumania-2023-poster.jpg", "backdrop": "assets/movie-ant-man-and-the-wasp-quantumania-2023-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 640146, "ratings": {"rtCritics": 46, "rtCriticsLabel": "Rotten", "rtAudience": 81, "rtAudienceLabel": "Upright", "imdb": 6, "imdbVotes": 281738, "tmdb": 6.197, "tmdbVotes": 6236}}, {"id": "movie-arctic-dogs-2019", "title": "Arctic Dogs", "year": 2019, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Animation", "Adventure", "Comedy"], "overview": "Animals band together to save the day when the evil Otto Von Walrus hatches a sinister scheme to accelerate global warming and melt the Arctic Circle.", "poster": "assets/movie-arctic-dogs-2019-poster.jpg", "backdrop": "assets/movie-arctic-dogs-2019-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 416153, "ratings": {"rtCritics": 13, "rtCriticsLabel": "Rotten", "rtAudience": 60, "rtAudienceLabel": "Upright", "imdb": 4.9, "imdbVotes": 2580, "tmdb": 5.9, "tmdbVotes": 148}}, {"id": "movie-the-avengers-2012", "title": "The Avengers", "year": 2012, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Science Fiction", "Action", "Adventure"], "overview": "When an unexpected enemy emerges and threatens global safety and security, Nick Fury, director of the international peacekeeping agency known as S.H.I.E.L.D., finds himself in need of a team to pull the world back\u2026", "poster": "assets/movie-the-avengers-2012-poster.jpg", "backdrop": "assets/movie-the-avengers-2012-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 24428, "ratings": {"rtCritics": 91, "rtCriticsLabel": "Certified Fresh", "rtAudience": 91, "rtAudienceLabel": "Upright", "imdb": 8, "imdbVotes": 1590693, "tmdb": 8.084, "tmdbVotes": 40262}}, {"id": "movie-black-bear-2020", "title": "Black Bear", "year": 2020, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Thriller"], "overview": "At a remote lake house in the Adirondack Mountains, a couple entertains an out-of-town guest looking for inspiration in her filmmaking. The group quickly falls into a calculated game of desire, manipulation, and\u2026", "poster": "assets/movie-black-bear-2020-poster.jpg", "backdrop": "assets/movie-black-bear-2020-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 624788, "ratings": {"rtCritics": 89, "rtCriticsLabel": "Certified Fresh", "rtAudience": 64, "rtAudienceLabel": "Upright", "imdb": 6.5, "imdbVotes": 18408, "tmdb": 6.337, "tmdbVotes": 315}}, {"id": "movie-black-panther-2018", "title": "Black Panther", "year": 2018, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action", "Adventure", "Science Fiction"], "overview": "King T'Challa returns home to the reclusive, technologically advanced African nation of Wakanda to serve as his country's new leader. However, T'Challa soon finds that he is challenged for the throne by factions\u2026", "poster": "assets/movie-black-panther-2018-poster.jpg", "backdrop": "assets/movie-black-panther-2018-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 284054, "ratings": {"rtCritics": 96, "rtCriticsLabel": "Certified Fresh", "rtAudience": null, "rtAudienceLabel": "Spilled", "imdb": 7.3, "imdbVotes": 931120, "tmdb": 7.36, "tmdbVotes": 24190}}, {"id": "movie-a-bronx-tale-1993", "title": "A Bronx Tale", "year": 1993, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Crime"], "overview": "Set in the Bronx during the tumultuous 1960s, an adolescent boy is torn between his honest, working-class father and a violent yet charismatic crime boss. Complicating matters is the youngster's growing attraction -\u2026", "poster": "assets/movie-a-bronx-tale-1993-poster.jpg", "backdrop": "assets/movie-a-bronx-tale-1993-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 1607, "ratings": {"rtCritics": 97, "rtCriticsLabel": "Fresh", "rtAudience": 92, "rtAudienceLabel": "Upright", "imdb": 7.8, "imdbVotes": 191930, "tmdb": 7.913, "tmdbVotes": 3075}}, {"id": "movie-by-any-means-2026", "title": "By Any Means", "year": 2026, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Thriller", "History", "Crime"], "overview": "In 1960s Mississippi, a young Black FBI agent is forced to partner with a notorious mafia hitman to investigate a wave of brutal civil rights murders.", "poster": "assets/movie-by-any-means-2026-poster.jpg", "backdrop": "assets/movie-by-any-means-2026-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 1380417, "ratings": {"rtCritics": 49, "rtCriticsLabel": "Rotten", "rtAudience": 88, "rtAudienceLabel": "Upright", "imdb": 6.8, "imdbVotes": 3534, "tmdb": 6.6, "tmdbVotes": 92}}, {"id": "movie-captain-america-civil-war-2016", "title": "Captain America: Civil War", "year": 2016, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Adventure", "Action", "Science Fiction"], "overview": "Following the events of Age of Ultron, the collective governments of the world pass an act designed to regulate all superhuman activity. This polarizes opinion amongst the Avengers, causing two factions to side with\u2026", "poster": "assets/movie-captain-america-civil-war-2016-poster.jpg", "backdrop": "assets/movie-captain-america-civil-war-2016-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 271110, "ratings": {"rtCritics": 90, "rtCriticsLabel": "Certified Fresh", "rtAudience": 89, "rtAudienceLabel": "Upright", "imdb": 7.8, "imdbVotes": 954943, "tmdb": 7.455, "tmdbVotes": 24808}}, {"id": "movie-captain-america-the-first-avenger-2011", "title": "Captain America: The First Avenger", "year": 2011, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action", "Adventure", "Science Fiction"], "overview": "During World War II, Steve Rogers is a sickly man from Brooklyn who's transformed into super-soldier Captain America to aid in the war effort. Rogers must stop the Red Skull \u2013 Adolf Hitler's ruthless head of\u2026", "poster": "assets/movie-captain-america-the-first-avenger-2011-poster.jpg", "backdrop": "assets/movie-captain-america-the-first-avenger-2011-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 1771, "ratings": {"rtCritics": 80, "rtCriticsLabel": "Certified Fresh", "rtAudience": 75, "rtAudienceLabel": "Upright", "imdb": 6.9, "imdbVotes": 993453, "tmdb": 7.012, "tmdbVotes": 23473}}, {"id": "movie-captain-america-the-winter-soldier-2014", "title": "Captain America: The Winter Soldier", "year": 2014, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action", "Adventure", "Science Fiction"], "overview": "After the cataclysmic events in New York with The Avengers, Steve Rogers, aka Captain America is living quietly in Washington, D.C. and trying to adjust to the modern world. But when a S.H.I.E.L.D. colleague comes\u2026", "poster": "assets/movie-captain-america-the-winter-soldier-2014-poster.jpg", "backdrop": "assets/movie-captain-america-the-winter-soldier-2014-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 100402, "ratings": {"rtCritics": 90, "rtCriticsLabel": "Certified Fresh", "rtAudience": 92, "rtAudienceLabel": "Upright", "imdb": 7.7, "imdbVotes": 995514, "tmdb": 7.654, "tmdbVotes": 20688}}, {"id": "movie-careful-what-you-wish-for-2015", "title": "Careful What You Wish For", "year": 2015, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Thriller"], "overview": "A guy gets more than he bargained for after entering into an affair with the wife of an investment banker. Soon, a suspicious death and substantial life insurance policy embroil him in a scandal.", "poster": "assets/movie-careful-what-you-wish-for-2015-poster.jpg", "backdrop": "assets/movie-careful-what-you-wish-for-2015-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 317744, "ratings": {"rtCritics": 17, "rtCriticsLabel": "Rotten", "rtAudience": 61, "rtAudienceLabel": "Upright", "imdb": 5.6, "imdbVotes": 9452, "tmdb": 6.129, "tmdbVotes": 446}}, {"id": "tv-12-monkeys-2015", "title": "12 Monkeys", "year": 2015, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Sci-Fi & Fantasy", "Drama"], "overview": "The provocative story of Cole, a time traveler from a decimated future in a high-stakes race against the clock. Utilizing a dangerous and untested method of time travel, he journeys from 2043 to the present day on a\u2026", "poster": "assets/tv-12-monkeys-2015-poster.jpg", "backdrop": "assets/tv-12-monkeys-2015-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 60948, "ratings": {"rtCritics": 88, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.441, "tmdbVotes": 1245}}, {"id": "tv-90-day-fiance-before-the-90-days-2017", "title": "90 Day Fianc\u00e9: Before the 90 Days", "year": 2017, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Reality"], "overview": "Follow couples who have an existing relationship online, but haven't met in person. We'll experience their journey as they travel to the other's foreign country for the first time in an attempt to establish an\u2026", "poster": "assets/tv-90-day-fiance-before-the-90-days-2017-poster.jpg", "backdrop": "assets/tv-90-day-fiance-before-the-90-days-2017-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 73319, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.5, "tmdbVotes": 45}}, {"id": "tv-90-day-fiance-the-other-way-2019", "title": "90 Day Fianc\u00e9: The Other Way", "year": 2019, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Reality"], "overview": "Americans move to a foreign country all in the name of love. Will uprooting their lives in the United States pay off, or will they be packing up and moving back to America brokenhearted?", "poster": "assets/tv-90-day-fiance-the-other-way-2019-poster.jpg", "backdrop": "assets/tv-90-day-fiance-the-other-way-2019-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 90046, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.8, "tmdbVotes": 34}}, {"id": "tv-the-100-2014", "title": "The 100", "year": 2014, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Sci-Fi & Fantasy", "Action & Adventure", "Drama"], "overview": "100 years in the future, when the Earth has been abandoned due to radioactivity, the last surviving humans live on an ark orbiting the planet \u2014 but the ark won't last forever. So the repressive regime picks 100\u2026", "poster": "assets/tv-the-100-2014-poster.jpg", "backdrop": "assets/tv-the-100-2014-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 48866, "ratings": {"rtCritics": 93, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.878, "tmdbVotes": 8855}}, {"id": "tv-accused-2023", "title": "Accused", "year": 2023, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Crime", "Drama"], "overview": "In this crime anthology series, viewers discover how an ordinary person got caught up in an extraordinary situation, ultimately revealing how one wrong turn leads to another, until it\u2019s too late to turn back. Told\u2026", "poster": "assets/tv-accused-2023-poster.jpg", "backdrop": "assets/tv-accused-2023-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 202097, "ratings": {"rtCritics": 61, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.851, "tmdbVotes": 87}}, {"id": "tv-after-life-2019", "title": "After Life", "year": 2019, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "Tony had a perfect life. But after his wife Lisa suddenly dies, Tony changes. After contemplating taking his own life, he decides instead to live long enough to punish the world by saying and doing whatever he likes\u2026", "poster": "assets/tv-after-life-2019-poster.jpg", "backdrop": "assets/tv-after-life-2019-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 79410, "ratings": {"rtCritics": 72, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.902, "tmdbVotes": 1169}}, {"id": "tv-all-creatures-great-and-small-1978", "title": "All Creatures Great and Small", "year": 1978, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "The trials and misadventures of the staff at a country veterinary office in Yorkshire. James Herriot, a young animal surgeon, moves to a small Yorkshire town to begin his first job.", "poster": "assets/tv-all-creatures-great-and-small-1978-poster.jpg", "backdrop": "assets/tv-all-creatures-great-and-small-1978-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "center_crop", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 7406, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.8, "tmdbVotes": 50}}, {"id": "tv-american-housewife-2016", "title": "American Housewife", "year": 2016, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Comedy"], "overview": "A family comedy narrated by Katie, a strong-willed mother, raising her flawed family in a wealthy town filled with perfect wives and their perfect offspring.", "poster": "assets/tv-american-housewife-2016-poster.jpg", "backdrop": "assets/tv-american-housewife-2016-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 67117, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.7, "tmdbVotes": 187}}, {"id": "tv-atlantis-2013", "title": "Atlantis", "year": 2013, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action & Adventure", "Sci-Fi & Fantasy"], "overview": "A fantasy drama set in a world of legendary heroes and mythical creatures. Far from home and desperate for answers, Jason washes up on the shores of an ancient land. A mysterious place; a world of bull leaping, of\u2026", "poster": "assets/tv-atlantis-2013-poster.jpg", "backdrop": "assets/tv-atlantis-2013-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 47054, "ratings": {"rtCritics": 62, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.4, "tmdbVotes": 155}}, {"id": "tv-avatar-the-last-airbender-2024", "title": "Avatar: The Last Airbender", "year": 2024, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action & Adventure", "Sci-Fi & Fantasy", "Drama"], "overview": "A young boy known as the Avatar must master the four elemental powers to save a world at war \u2014 and fight a ruthless enemy bent on stopping him.", "poster": "assets/tv-avatar-the-last-airbender-2024-poster.jpg", "backdrop": "assets/tv-avatar-the-last-airbender-2024-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 82452, "ratings": {"rtCritics": 66, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.8, "tmdbVotes": 1406}}, {"id": "tv-avatar-seven-havens-2026", "title": "Avatar: Seven Havens", "year": 2026, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "In a world shattered by a devastating cataclysm, a young Earthbender discovers she's the new Avatar after Korra. But in this dangerous era, that title marks her as humanity's destroyer, not its savior. Hunted by both\u2026", "poster": "assets/tv-avatar-seven-havens-2026-poster.jpg", "backdrop": "assets/tv-avatar-seven-havens-2026-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 284833, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.9, "tmdbVotes": 183}}, {"id": "tv-batman-the-brave-and-the-bold-2008", "title": "Batman: The Brave and the Bold", "year": 2008, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "The Caped Crusader is teamed up with Blue Beetle, Green Arrow, Aquaman and countless others in his quest to uphold justice.", "poster": "assets/tv-batman-the-brave-and-the-bold-2008-poster.jpg", "backdrop": "assets/tv-batman-the-brave-and-the-bold-2008-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 15804, "ratings": {"rtCritics": 96, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.6, "tmdbVotes": 295}}, {"id": "tv-beat-bobby-flay-2013", "title": "Beat Bobby Flay", "year": 2013, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Reality"], "overview": "Two talented chefs go head-to-head for the chance to Beat Bobby Flay. To get to Bobby the chefs must first face off against each other, creating a spectacular dish with a secret ingredient of Bobby's choice. Judges\u2026", "poster": "assets/tv-beat-bobby-flay-2013-poster.jpg", "backdrop": "assets/tv-beat-bobby-flay-2013-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 62481, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.5, "tmdbVotes": 31}}, {"id": "tv-benson-1979", "title": "Benson", "year": 1979, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Comedy"], "overview": "A butler deals with life at the governor's mansion.", "poster": "assets/tv-benson-1979-poster.jpg", "backdrop": "assets/tv-benson-1979-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 1849, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7, "tmdbVotes": 46}}, {"id": "tv-black-rabbit-2025", "title": "Black Rabbit", "year": 2025, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Crime"], "overview": "A rising-star restaurateur is forced into New York's criminal underworld when his chaotic brother returns to town with loan sharks on his trail.", "poster": "assets/tv-black-rabbit-2025-poster.jpg", "backdrop": "assets/tv-black-rabbit-2025-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 249039, "ratings": {"rtCritics": 66, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.983, "tmdbVotes": 240}}, {"id": "tv-black-ish-2014", "title": "black-ish", "year": 2014, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Comedy"], "overview": "A family man struggles to gain a sense of cultural identity while raising his kids in a predominantly white, upper-middle-class neighborhood.", "poster": "assets/tv-black-ish-2014-poster.jpg", "backdrop": "assets/tv-black-ish-2014-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 61381, "ratings": {"rtCritics": 92, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.1, "tmdbVotes": 352}}, {"id": "tv-breaking-bad-2008", "title": "Breaking Bad", "year": 2008, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Crime"], "overview": "Walter White, a New Mexico chemistry teacher, is diagnosed with Stage III cancer and given a prognosis of only two years left to live. He becomes filled with a sense of fearlessness and an unrelenting desire to\u2026", "poster": "assets/tv-breaking-bad-2008-poster.jpg", "backdrop": "assets/tv-breaking-bad-2008-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "center_crop", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 1396, "ratings": {"rtCritics": 96, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.959, "tmdbVotes": 19030}}, {"id": "tv-the-capture-2019", "title": "The Capture", "year": 2019, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Crime", "Drama", "Mystery"], "overview": "When soldier Shaun Emery's conviction for a murder in Afghanistan is overturned due to flawed video evidence, he returns to life as a free man with his young daughter. But when damning CCTV footage from a night out\u2026", "poster": "assets/tv-the-capture-2019-poster.jpg", "backdrop": "assets/tv-the-capture-2019-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 93166, "ratings": {"rtCritics": 97, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.634, "tmdbVotes": 361}}], "discoverySource": {"state": "materialized_snapshot", "rankKnown": false, "selection": "First 18 alphabetically indexed movie stubs and first 18 series stubs, not ranked feed order", "observedAt": "2026-11-04T20:42:12.030108+00:00"}}], "notes": {"real": ["Profile keys and library membership derive from deployed Conductarr configuration and viewer-scoped Jellyfin GET responses.", "Names, years, overviews, library ratings, genres, season-container counts and watch/resume data come from actual Jellyfin metadata.", "All local artwork is copied from Jellyfin; discovery posters are the real materialized Conductarr recommendation artwork.", "Discover contains 36 real materialized personal recommendations per profile, with profile-scoped availability from read-only retained membership/request state.", "Justin has no playable resume items. Mindel and Shared each have one. No progress or watched flags were invented."], "approximations": ["Default profile initials and display capitalization are frontend presentation choices; colours reuse the existing PWA palette, not live user appearance configuration.", "Conductarr catalogue and recommendation GET endpoints both returned 401. Authentication was not bypassed. SQLite contains no retained recommendation feed/candidate snapshot tables; the source keeps ranked feeds in memory. Discovery therefore reads existing per-profile Jellyfin recommendation stubs as metadata only.", "Discovery selection is 18 alphabetically indexed movie suggestions plus 18 series suggestions, not personal rank order; rank is null. Materialization age and original feed ordering are unknown.", "Discovery stub runtime is synthetic (two seconds), so runtime, season count, rating and watch state are null rather than presenting stub values as real media facts.", "93 selected identities lack original landscape art in the materialized metadata; their backdrop is a marked crop of the real poster, not an original film backdrop. Existing artwork is reused; new artwork is centre-cropped to the required dimensions.", "Jellyfin server-side resizing requests maxWidth/maxHeight/quality. When the result had the wrong aspect ratio, sequential single-thread ffmpeg center crops produce exact 300x450 and 1280x720 JPEGs.", "Series seasonCount is Jellyfin ChildCount, including season containers for specials when present.", "Discover availability is a retained profile-membership/request snapshot, not a fresh playback or acquisition guarantee. not_here means absent from that profile in retained state, not absent from the entire household."], "missing": ["Justin Movies has seven live viewer-scoped films, not 200. No titles are invented or borrowed across profile boundaries.", "Discovery community/critic ratings, reliable runtime/season counts, personal feed ranking/freshness and 93 original landscape backdrops are unavailable through the permitted read paths."], "unmetRequirements": ["At least 200 real profile-scoped Justin Movies"], "mustNotBeShown": ["Recs Movies", "Recs Shows", "Justin Movies", "Justin Shows", "Mindel Movies", "Mindel Shows", "Shared Movies", "Shared Shows", "DGiC", "Stored names padded with spaces", "Internal bucket and acquisition-instance names"], "privacy": ["Includes actual watched and resume history for Justin, Mindel and Shared independently; Shared is not a union.", "No Jellyfin item/user IDs, source paths, service URLs, credentials, request actor identities, or private hotlinks are included. tmdbId is a public external title identity.", "Only the seven configured playable libraries are selected. Extra observed DGiC views and all recommendation stubs are excluded from playable collections.", "No profile is assumed to be a child or age-restricted. Each playable list and episode shelf is limited to that profile\u2019s configured libraries."], "sourceReadPaths": ["GET /Users (allowlisted mapping only)", "GET /Users/{userId}/Views", "GET /Users/{userId}/Items (parent-scoped playable libraries and metadata-only recommendation libraries)", "GET /Users/{userId}/Items/Resume", "GET /Shows/NextUp?UserId=...", "GET /Items/{itemId}/Images/Primary", "GET /Items/{itemId}/Images/Backdrop/0", "Conductarr GET /catalogue/discover?page=1&media_type=movie (401)", "Conductarr GET /api/v1/recommendations/profiles/justin/feed (401)", "SQLite file URI mode=ro plus PRAGMA query_only=ON: catalogue_metadata, bucket_memberships, native_requests; sqlite_master for schema inspection"], "productionMutations": 0, "artwork": {"files": 632, "bytes": 35201423, "posterDimensions": [300, 450], "backdropDimensions": [1280, 720], "posterQualityRequested": 70, "backdropQualityRequested": 65, "posterDerivedBackdropCount": 93}, "consumerContract": ["profiles is an array in Justin/Mindel/Shared order. Every profile owns movies/shows/anime/resume/nextUp/recentlyAdded/discover item arrays; empty shelves are intentional.", "Item paths are relative to fixture.json. Resolve assets against the fixture directory, not against the outer prototype document.", "Use destinations for visible navigation. No raw library display/stored names belong in UI.", "Deduplicate library/resume/discover by stable local id or (type,tmdbId). Never treat a materialized recommendation as a playable library item.", "played=null and watchStateKnown=false mean unknown, not unwatched. Null ratings are missing, not zero; communityRating source is Jellyfin, not an asserted TMDB/IMDb score.", "availability values are in_library/requested/not_here. No requested examples were observed in the selected discover set; do not fabricate them.", "Render artwork.backdropKind=poster_crop as a poster-derived landscape; prefer the poster over pretending it is original landscape art.", "This static fixture preserves actual current collection sizes, viewer-scoped watch state and unknown discovery ranking; request and playback demonstrations must remain labelled simulations."]}} \ No newline at end of file diff --git a/app/src/debug/assets/wolfskin-library.json b/app/src/debug/assets/wolfskin-library.json new file mode 100644 index 00000000..76617014 --- /dev/null +++ b/app/src/debug/assets/wolfskin-library.json @@ -0,0 +1 @@ +{"profiles":[{"key":"justin","movies":[{"id":"movie-the-girl-who-leapt-through-time-2006","title":"The Girl Who Leapt Through Time","year":2006,"type":"movie","runtimeSeconds":5886,"seasonCount":null,"communityRating":7.772,"criticRating":87,"genres":["Fantasy","Animation","Drama"],"overview":"When 17-year-old Makoto Konno gains the ability to 'leap' backwards through time, she immediately sets about improving her grades and preventing personal mishaps. However, she soon realises that changing the past\u2026","poster":"assets/movie-the-girl-who-leapt-through-time-2006-poster.jpg","backdrop":"assets/movie-the-girl-who-leapt-through-time-2006-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T17:39:11.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":14069,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":87,"rtCriticsLabel":"Fresh","rtAudience":90,"rtAudienceLabel":"Upright","imdb":7.6,"imdbVotes":76917,"tmdb":7.775,"tmdbVotes":2345}},{"id":"movie-locke-2014","title":"Locke","year":2014,"type":"movie","runtimeSeconds":5090,"seasonCount":null,"communityRating":6.891,"criticRating":91,"genres":["Drama","Thriller"],"overview":"Ivan Locke has worked hard to craft a good life for himself. Tonight, that life will collapse around him. On the eve of the biggest challenge of his career, Ivan receives a phone call that sets in motion a series of\u2026","poster":"assets/movie-locke-2014-poster.jpg","backdrop":"assets/movie-locke-2014-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T17:38:48.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":210479,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":90,"rtCriticsLabel":"Certified Fresh","rtAudience":72,"rtAudienceLabel":"Upright","imdb":7.1,"imdbVotes":171265,"tmdb":6.889,"tmdbVotes":3088}},{"id":"movie-look-who-s-back-2015","title":"Look Who's Back","year":2015,"type":"movie","runtimeSeconds":6936,"seasonCount":null,"communityRating":6.793,"criticRating":null,"genres":["Comedy"],"overview":"When Adolf Hitler reawakens at the site of his former bunker in present-day Berlin, he is mistaken for a comedian and quickly becomes a media phenomenon.","poster":"assets/movie-look-who-s-back-2015-poster.jpg","backdrop":"assets/movie-look-who-s-back-2015-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:27:48.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":318917,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":81,"rtAudienceLabel":"Upright","imdb":7,"imdbVotes":54672,"tmdb":6.796,"tmdbVotes":1990}},{"id":"movie-memories-1995","title":"Memories","year":1995,"type":"movie","runtimeSeconds":6805,"seasonCount":null,"communityRating":7.465,"criticRating":null,"genres":["Fantasy","Animation","Science Fiction"],"overview":"Three back-to-back anime films by three different directors make up this sci-fi trilogy three years in the making.","poster":"assets/movie-memories-1995-poster.jpg","backdrop":"assets/movie-memories-1995-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-30T21:36:03.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":42994,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":82,"rtAudienceLabel":"Upright","imdb":7.5,"imdbVotes":26638,"tmdb":7.459,"tmdbVotes":622}},{"id":"movie-reincarnated-2012","title":"Reincarnated","year":2012,"type":"movie","runtimeSeconds":5759,"seasonCount":null,"communityRating":6.145,"criticRating":28,"genres":["Music","Documentary"],"overview":"Evolution as an artist is often times what separates legends from the more mundane. After being heavily influenced by his experience in Jamaica \u2013 and his subsequent name change from Snoop Dogg to Snoop Lion \u2013 the LBC\u2026","poster":"assets/movie-reincarnated-2012-poster.jpg","backdrop":"assets/movie-reincarnated-2012-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:27:26.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":123431,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":28,"rtCriticsLabel":"Rotten","rtAudience":41,"rtAudienceLabel":"Spilled","imdb":6.2,"imdbVotes":2563,"tmdb":6.1,"tmdbVotes":69}},{"id":"movie-shipwrecked-nightmare-at-sea-2026","title":"Shipwrecked: Nightmare at Sea","year":2026,"type":"movie","runtimeSeconds":5385,"seasonCount":null,"communityRating":7.181,"criticRating":null,"genres":["Documentary"],"overview":"Never-before-seen footage and survivor accounts trace the 2012 shipwreck of a luxury cruise and the disaster that ensued, in this immersive documentary.","poster":"assets/movie-shipwrecked-nightmare-at-sea-2026-poster.jpg","backdrop":"assets/movie-shipwrecked-nightmare-at-sea-2026-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-20T20:11:43.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":1715492,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":6.5,"imdbVotes":5080,"tmdb":7.172,"tmdbVotes":87}},{"id":"movie-steins-gate-the-movie-load-region-of-deja-vu-2013","title":"Steins;Gate: The Movie - Load Region of D\u00e9j\u00e0 Vu","year":2013,"type":"movie","runtimeSeconds":5403,"seasonCount":null,"communityRating":7.8,"criticRating":null,"genres":["Animation","Mystery","Sci-Fi"],"overview":"After the events of the anime, Rintarou begins to feel the repercussions of extensive time travel, and eventually completely fades from reality. Kurisu, being the only companion to remember him, now must find a way\u2026","poster":"assets/movie-steins-gate-the-movie-load-region-of-deja-vu-2013-poster.jpg","backdrop":"assets/movie-steins-gate-the-movie-load-region-of-deja-vu-2013-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-22T14:55:54.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","artwork":{"posterKind":"poster","backdropKind":"backdrop"}}],"shows":[{"id":"tv-andor-2022","title":"Andor","year":2022,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":8.293,"criticRating":null,"genres":["Sci-Fi & Fantasy","Action & Adventure","Drama"],"overview":"In an era filled with danger, deception and intrigue, Cassian Andor will discover the difference he can make in the struggle against the tyrannical Galactic Empire. He embarks on a path that is destined to turn him\u2026","poster":"assets/tv-andor-2022-poster.jpg","backdrop":"assets/tv-andor-2022-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0432996Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":83867,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":96,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.321,"tmdbVotes":2312}},{"id":"tv-the-boys-2019","title":"The Boys","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":5,"communityRating":8.443,"criticRating":null,"genres":["Sci-Fi & Fantasy","Action & Adventure"],"overview":"A group of vigilantes known informally as \u201cThe Boys\u201d set out to take down corrupt superheroes with no more than blue-collar grit and a willingness to fight dirty.","poster":"assets/tv-the-boys-2019-poster.jpg","backdrop":"assets/tv-the-boys-2019-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0410131Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":76479,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":92,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.4,"tmdbVotes":13628}},{"id":"tv-californication-2007","title":"Californication","year":2007,"type":"tv","runtimeSeconds":1680,"seasonCount":7,"communityRating":7.632,"criticRating":null,"genres":["Comedy","Drama"],"overview":"A self-loathing, alcoholic writer attempts to repair his damaged relationships with his daughter and her mother while combating sex addiction, a budding drug problem, and the seeming inability to avoid making bad\u2026","poster":"assets/tv-californication-2007-poster.jpg","backdrop":"assets/tv-californication-2007-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0428037Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":1215,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":57,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.62,"tmdbVotes":1406}},{"id":"tv-firefly-2002","title":"Firefly","year":2002,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":8.347,"criticRating":null,"genres":["Drama","Action & Adventure","Sci-Fi & Fantasy"],"overview":"In the year 2517, the universe is a vast frontier where lawlessness reigns and adventure awaits! Join Captain Malcolm Reynolds and his ragtag crew aboard the spaceship Serenity as they navigate the fringes of\u2026","poster":"assets/tv-firefly-2002-poster.jpg","backdrop":"assets/tv-firefly-2002-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-20T11:40:08.4202369Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":1437,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":77,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.351,"tmdbVotes":2550}},{"id":"tv-fleabag-2016","title":"Fleabag","year":2016,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":8.278,"criticRating":null,"genres":["Comedy","Drama"],"overview":"A portrait into the mind of a dry-witted, sexual, angry, porn-watching, grief-riddled woman, trying to make sense of the world. As she hurls herself headlong at modern living, Fleabag is thrown roughly up against the\u2026","poster":"assets/tv-fleabag-2016-poster.jpg","backdrop":"assets/tv-fleabag-2016-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T17:42:25.4848214Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":67070,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.3,"tmdbVotes":1993}},{"id":"tv-gravity-falls-2012","title":"Gravity Falls","year":2012,"type":"tv","runtimeSeconds":1320,"seasonCount":2,"communityRating":8.619,"criticRating":null,"genres":["Action & Adventure","Animation","Comedy"],"overview":"Twin brother and sister Dipper and Mabel Pines are in for an unexpected adventure when they spend the summer helping their great uncle Stan run a tourist trap in the mysterious town of Gravity Falls, Oregon.","poster":"assets/tv-gravity-falls-2012-poster.jpg","backdrop":"assets/tv-gravity-falls-2012-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0435827Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":40075,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.624,"tmdbVotes":3647}},{"id":"tv-invincible-2021","title":"INVINCIBLE","year":2021,"type":"tv","runtimeSeconds":null,"seasonCount":4,"communityRating":8.638,"criticRating":null,"genres":["Animation","Drama","Sci-Fi & Fantasy"],"overview":"Mark Grayson is a normal teenager except for the fact that his father is the most powerful superhero on the planet. Shortly after his seventeenth birthday, Mark begins to develop powers of his own and enters into his\u2026","poster":"assets/tv-invincible-2021-poster.jpg","backdrop":"assets/tv-invincible-2021-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.040159Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":95557,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":99,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.6,"tmdbVotes":6155}},{"id":"tv-the-legend-of-korra-2012","title":"The Legend of Korra","year":2012,"type":"tv","runtimeSeconds":1380,"seasonCount":4,"communityRating":8.2,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"Avatar Korra, a headstrong, rebellious, feisty young woman who continually challenges and breaks with tradition, is on her quest to become a fully realized Avatar. In this story, the Avatar struggles to find balance\u2026","poster":"assets/tv-the-legend-of-korra-2012-poster.jpg","backdrop":"assets/tv-the-legend-of-korra-2012-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-20T00:19:23.2494945Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":33880,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":88,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.221,"tmdbVotes":2482}},{"id":"tv-love-death-robots-2019","title":"Love, Death & Robots","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":4,"communityRating":8.205,"criticRating":null,"genres":["Animation","Sci-Fi & Fantasy"],"overview":"Terrifying creatures, wicked surprises and dark comedy converge in this NSFW anthology of animated stories presented by Tim Miller and David Fincher.","poster":"assets/tv-love-death-robots-2019-poster.jpg","backdrop":"assets/tv-love-death-robots-2019-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-20T11:31:20.8818757Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":86831,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":89,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.203,"tmdbVotes":4238}},{"id":"tv-norsemen-2016","title":"Norsemen","year":2016,"type":"tv","runtimeSeconds":1800,"seasonCount":3,"communityRating":7.177,"criticRating":null,"genres":["Comedy","Drama"],"overview":"Norsemen is an epic and humorous drama series set in the Viking Age. The residents of an 8th-century Viking village experience political rivalry, social change and innovations that upend their culture and way of life.","poster":"assets/tv-norsemen-2016-poster.jpg","backdrop":"assets/tv-norsemen-2016-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.034182Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":68126,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.2,"tmdbVotes":233}},{"id":"tv-rick-and-morty-2013","title":"Rick and Morty","year":2013,"type":"tv","runtimeSeconds":null,"seasonCount":9,"communityRating":8.679,"criticRating":null,"genres":["Animation","Comedy","Sci-Fi & Fantasy"],"overview":"Follows a sociopathic genius scientist who drags his inherently timid grandson on adventures across the universe.","poster":"assets/tv-rick-and-morty-2013-poster.jpg","backdrop":"assets/tv-rick-and-morty-2013-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0419581Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":60625,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":91,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.7,"tmdbVotes":11548}},{"id":"tv-secret-level-2024","title":"Secret Level","year":2024,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":7.411,"criticRating":null,"genres":["Animation","Sci-Fi & Fantasy","Action & Adventure"],"overview":"Adult animated series of original short stories which are set within the worlds of beloved video games. Each episode serves as a gateway to a new adventure, unlocking exciting worlds from beloved gaming classics and\u2026","poster":"assets/tv-secret-level-2024-poster.jpg","backdrop":"assets/tv-secret-level-2024-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0336417Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":261579,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":65,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.392,"tmdbVotes":612}},{"id":"tv-silo-2023","title":"Silo","year":2023,"type":"tv","runtimeSeconds":null,"seasonCount":3,"communityRating":8.178,"criticRating":null,"genres":["Sci-Fi & Fantasy","Drama"],"overview":"In a ruined and toxic future, thousands live in a giant silo deep underground. After its sheriff breaks a cardinal rule and residents die mysteriously, engineer Juliette starts to uncover shocking secrets and the\u2026","poster":"assets/tv-silo-2023-poster.jpg","backdrop":"assets/tv-silo-2023-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0346526Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":125988,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":92,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.232,"tmdbVotes":2881}},{"id":"tv-south-park-1997","title":"South Park","year":1997,"type":"tv","runtimeSeconds":null,"seasonCount":29,"communityRating":8.336,"criticRating":null,"genres":["Animation","Comedy"],"overview":"Follow the misadventures of four irreverent grade-schoolers in the quiet, dysfunctional town of South Park, Colorado.","poster":"assets/tv-south-park-1997-poster.jpg","backdrop":"assets/tv-south-park-1997-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0456124Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":2190,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":80,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.332,"tmdbVotes":5250}}],"anime":[{"id":"tv-bleach-2004","title":"Bleach","year":2004,"type":"tv","runtimeSeconds":1440,"seasonCount":17,"communityRating":8.363,"criticRating":null,"genres":["Action & Adventure","Animation","Sci-Fi & Fantasy"],"overview":"For as long as he can remember, Ichigo Kurosaki has been able to see ghosts. But when he meets Rukia, a Soul Reaper who battles evil spirits known as Hollows, he finds his life is changed forever. Now, with a\u2026","poster":"assets/tv-bleach-2004-poster.jpg","backdrop":"assets/tv-bleach-2004-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0359827Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":30984,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.4,"tmdbVotes":2331}},{"id":"tv-chainsaw-man-2022","title":"Chainsaw Man","year":2022,"type":"tv","runtimeSeconds":1440,"seasonCount":1,"communityRating":8.515,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"Denji has a simple dream\u2014to live a happy and peaceful life, spending time with a girl he likes. This is a far cry from reality, however, as Denji is forced by the yakuza into killing devils in order to pay off his\u2026","poster":"assets/tv-chainsaw-man-2022-poster.jpg","backdrop":"assets/tv-chainsaw-man-2022-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-20T22:28:13.2095501Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":114410,"artwork":{"posterKind":"center_crop","backdropKind":"backdrop"},"ratings":{"rtCritics":97,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.508,"tmdbVotes":2364}},{"id":"tv-cyberpunk-edgerunners-2022","title":"Cyberpunk: Edgerunners","year":2022,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":8.466,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"In a dystopia riddled with corruption and cybernetic implants, a talented but reckless street kid strives to become a mercenary outlaw \u2014 an edgerunner.","poster":"assets/tv-cyberpunk-edgerunners-2022-poster.jpg","backdrop":"assets/tv-cyberpunk-edgerunners-2022-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-20T22:28:13.2093107Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":105248,"artwork":{"posterKind":"center_crop","backdropKind":"backdrop"},"ratings":{"rtCritics":89,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.507,"tmdbVotes":2132}},{"id":"tv-dan-da-dan-2024","title":"Dan Da Dan","year":2024,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":8.538,"criticRating":null,"genres":["Animation","Action & Adventure","Comedy"],"overview":"In a bet to prove whether ghosts or aliens exist, two high schoolers face terrifying paranormal threats, gain superpowers and maybe even fall in love?!","poster":"assets/tv-dan-da-dan-2024-poster.jpg","backdrop":"assets/tv-dan-da-dan-2024-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-22T10:31:16.2652252Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":240411,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.517,"tmdbVotes":986}},{"id":"tv-dr-stone-2019","title":"Dr. STONE","year":2019,"type":"tv","runtimeSeconds":1440,"seasonCount":4,"communityRating":8.541,"criticRating":null,"genres":["Animation","Action & Adventure","Comedy"],"overview":"One fateful day, all of humanity was petrified by a blinding flash of light. After several millennia, high schooler Taiju awakens and finds himself lost in a world of statues. However, he\u2019s not alone! His\u2026","poster":"assets/tv-dr-stone-2019-poster.jpg","backdrop":"assets/tv-dr-stone-2019-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-20T22:28:13.2091579Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":86031,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.53,"tmdbVotes":1814}},{"id":"tv-frieren-beyond-journey-s-end-2023","title":"Frieren: Beyond Journey's End","year":2023,"type":"tv","runtimeSeconds":1500,"seasonCount":2,"communityRating":8.803,"criticRating":null,"genres":["Animation","Action & Adventure","Drama"],"overview":"After the party of heroes defeated the Demon King, they restored peace to the land and returned to lives of solitude. Generations pass, and the elven mage Frieren comes face to face with humanity\u2019s mortality. She\u2026","poster":"assets/tv-frieren-beyond-journey-s-end-2023-poster.jpg","backdrop":"assets/tv-frieren-beyond-journey-s-end-2023-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-20T22:28:13.2094435Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":209867,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.826,"tmdbVotes":1016}},{"id":"tv-fullmetal-alchemist-brotherhood-2009","title":"Fullmetal Alchemist: Brotherhood","year":2009,"type":"tv","runtimeSeconds":1500,"seasonCount":1,"communityRating":8.7,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"Disregard for alchemy\u2019s laws ripped half of Edward Elric\u2019s limbs from his body and left his brother Alphonse\u2019s soul clinging to a suit of armor. To restore what was lost, the brothers seek the Philosopher\u2019s Stone.\u2026","poster":"assets/tv-fullmetal-alchemist-brotherhood-2009-poster.jpg","backdrop":"assets/tv-fullmetal-alchemist-brotherhood-2009-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-20T10:27:12.3573939Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":31911,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.7,"tmdbVotes":2633}},{"id":"tv-jujutsu-kaisen-2020","title":"JUJUTSU KAISEN","year":2020,"type":"tv","runtimeSeconds":1440,"seasonCount":3,"communityRating":8.583,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"Yuji Itadori is a boy with tremendous physical strength, though he lives a completely ordinary high school life. One day, to save a classmate who has been attacked by curses, he eats the finger of Ryomen Sukuna,\u2026","poster":"assets/tv-jujutsu-kaisen-2020-poster.jpg","backdrop":"assets/tv-jujutsu-kaisen-2020-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-20T22:28:13.207573Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":95479,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.574,"tmdbVotes":4735}},{"id":"tv-kaiju-no-8-2024","title":"Kaiju No. 8","year":2024,"type":"tv","runtimeSeconds":1440,"seasonCount":2,"communityRating":8.436,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"In a world plagued by creatures known as Kaiju, Kafka Hibino aspired to enlist in The Defense Force. He makes a promise to enlist with his childhood friend, Mina Ashiro. Soon, life takes them in separate ways. While\u2026","poster":"assets/tv-kaiju-no-8-2024-poster.jpg","backdrop":"assets/tv-kaiju-no-8-2024-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-22T10:31:16.2646566Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":207468,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.4,"tmdbVotes":836}},{"id":"tv-my-hero-academia-2016","title":"My Hero Academia","year":2016,"type":"tv","runtimeSeconds":1440,"seasonCount":8,"communityRating":8.607,"criticRating":null,"genres":["Action & Adventure","Animation","Sci-Fi & Fantasy"],"overview":"After he saves a bully from a Villain, a normal student is granted a superpower that allows him to attend a high school training academy for Heroes.","poster":"assets/tv-my-hero-academia-2016-poster.jpg","backdrop":"assets/tv-my-hero-academia-2016-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-20T22:28:13.2089315Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":65930,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.6,"tmdbVotes":5426}},{"id":"tv-neon-genesis-evangelion-1995","title":"Neon Genesis Evangelion","year":1995,"type":"tv","runtimeSeconds":1500,"seasonCount":1,"communityRating":8.568,"criticRating":null,"genres":["Sci-Fi & Fantasy","Animation","Drama"],"overview":"At the turn of the century, the Angels returned to Earth, seeking to wipe out humanity in an apocalyptic fury. Devastated, mankind's last remnants moved underground to wait for the day when the Angels would come back\u2026","poster":"assets/tv-neon-genesis-evangelion-1995-poster.jpg","backdrop":"assets/tv-neon-genesis-evangelion-1995-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0340629Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":890,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.56,"tmdbVotes":2205}},{"id":"tv-record-of-ragnarok-2021","title":"Record of Ragnarok","year":2021,"type":"tv","runtimeSeconds":null,"seasonCount":3,"communityRating":8.402,"criticRating":null,"genres":["Action & Adventure","Animation","Sci-Fi & Fantasy"],"overview":"Before eradicating humankind from the world, the gods give them one last chance to prove themselves worthy of survival. Let the Ragnarok battles begin.","poster":"assets/tv-record-of-ragnarok-2021-poster.jpg","backdrop":"assets/tv-record-of-ragnarok-2021-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-20T22:28:13.2085766Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":114868,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.403,"tmdbVotes":1929}},{"id":"tv-sakamoto-days-2025","title":"SAKAMOTO DAYS","year":2025,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":8.071,"criticRating":null,"genres":["Animation","Comedy","Action & Adventure"],"overview":"Once the greatest hitman of all, Taro Sakamoto retired in the name of love. But when his past catches up, he must fight to protect his beloved family.","poster":"assets/tv-sakamoto-days-2025-poster.jpg","backdrop":"assets/tv-sakamoto-days-2025-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-22T10:31:16.266066Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":207332,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.057,"tmdbVotes":375}},{"id":"tv-sentenced-to-be-a-hero-2025","title":"Sentenced to Be a Hero","year":2025,"type":"tv","runtimeSeconds":1440,"seasonCount":1,"communityRating":8.338,"criticRating":null,"genres":["Animation","Sci-Fi & Fantasy","Action & Adventure"],"overview":"In a world where heroism is a punishment, Xylo Forbartz, a condemned goddess killer, battles endless hordes of monstrous abominations as part of Penal Hero Unit 9004. Death is no escape, only a cycle of resurrection\u2026","poster":"assets/tv-sentenced-to-be-a-hero-2025-poster.jpg","backdrop":"assets/tv-sentenced-to-be-a-hero-2025-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-22T10:31:16.2666791Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":249907,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.244,"tmdbVotes":129}},{"id":"tv-spy-x-family-2022","title":"SPY x FAMILY","year":2022,"type":"tv","runtimeSeconds":1440,"seasonCount":3,"communityRating":8.506,"criticRating":null,"genres":["Animation","Action & Adventure","Comedy"],"overview":"A spy, an assassin and a telepath come together to pose as a family, each for their own reasons, while hiding their true identities from each other.","poster":"assets/tv-spy-x-family-2022-poster.jpg","backdrop":"assets/tv-spy-x-family-2022-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-22T10:31:16.2670364Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":120089,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.5,"tmdbVotes":2382}},{"id":"tv-the-tatami-galaxy-2010","title":"The Tatami Galaxy","year":2010,"type":"tv","runtimeSeconds":1500,"seasonCount":2,"communityRating":8.271,"criticRating":null,"genres":["Animation","Comedy","Drama"],"overview":"When a college dropout stops for a late night bite at a mysterious ramen stand, he crosses paths with a self-proclaimed deity of matrimony. This bizarre meeting sends the young man hurtling through a horrifying\u2026","poster":"assets/tv-the-tatami-galaxy-2010-poster.jpg","backdrop":"assets/tv-the-tatami-galaxy-2010-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-18T05:52:51.0023256Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":36243,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.3,"tmdbVotes":152}},{"id":"tv-vinland-saga-2019","title":"Vinland Saga","year":2019,"type":"tv","runtimeSeconds":1500,"seasonCount":2,"communityRating":8.527,"criticRating":null,"genres":["Animation","War & Politics","Action & Adventure"],"overview":"For a thousand years, the Vikings have made quite a name and reputation for themselves as the strongest families with a thirst for violence. Thorfinn, the son of one of the Vikings' greatest warriors, spends his\u2026","poster":"assets/tv-vinland-saga-2019-poster.jpg","backdrop":"assets/tv-vinland-saga-2019-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-20T22:28:13.207389Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":88803,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.509,"tmdbVotes":1064}},{"id":"tv-yu-yu-hakusho-1992","title":"Yu Yu Hakusho","year":1992,"type":"tv","runtimeSeconds":1440,"seasonCount":4,"communityRating":8.5,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"After dying to save a boy, delinquent tough guy Yusuke Urameshi is granted another chance at life by redeeming himself as a \"Spirit Detective.\"","poster":"assets/tv-yu-yu-hakusho-1992-poster.jpg","backdrop":"assets/tv-yu-yu-hakusho-1992-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-19T21:46:01.5733049Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":30669,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.475,"tmdbVotes":519}}],"discover":[{"id":"movie-the-amazing-spider-man-2012","title":"The Amazing Spider-Man","year":2012,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"A teenage Peter Parker grapples with both high school and amazing super-human crises as his alter-ego Spider-Man.","poster":"assets/movie-the-amazing-spider-man-2012-poster.jpg","backdrop":"assets/movie-the-amazing-spider-man-2012-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1930,"ratings":{"rtCritics":71,"rtCriticsLabel":"Certified Fresh","rtAudience":77,"rtAudienceLabel":"Upright","imdb":7,"imdbVotes":791938,"tmdb":6.768,"tmdbVotes":19312}},{"id":"movie-the-amazing-spider-man-2-2014","title":"The Amazing Spider-Man 2","year":2014,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"For Peter Parker, life is busy. Between taking out the bad guys as Spider-Man and spending time with the person he loves, Gwen Stacy, high school graduation cannot come quickly enough. Peter has not forgotten about\u2026","poster":"assets/movie-the-amazing-spider-man-2-2014-poster.jpg","backdrop":"assets/movie-the-amazing-spider-man-2-2014-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":102382,"ratings":{"rtCritics":51,"rtCriticsLabel":"Rotten","rtAudience":64,"rtAudienceLabel":"Upright","imdb":6.6,"imdbVotes":611981,"tmdb":6.567,"tmdbVotes":14919}},{"id":"movie-the-animatrix-2003","title":"The Animatrix","year":2003,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Science Fiction"],"overview":"Straight from the creators of the groundbreaking Matrix trilogy, this collection of short animated films from the world's leading anime directors fuses computer graphics and Japanese anime to provide the background\u2026","poster":"assets/movie-the-animatrix-2003-poster.jpg","backdrop":"assets/movie-the-animatrix-2003-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":55931,"ratings":{"rtCritics":86,"rtCriticsLabel":"Fresh","rtAudience":78,"rtAudienceLabel":"Upright","imdb":7.3,"imdbVotes":91929,"tmdb":7.221,"tmdbVotes":1872}},{"id":"movie-ant-man-and-the-wasp-quantumania-2023","title":"Ant-Man and the Wasp: Quantumania","year":2023,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"Super-Hero partners Scott Lang and Hope van Dyne, along with with Hope's parents Janet van Dyne and Hank Pym, and Scott's daughter Cassie Lang, find themselves exploring the Quantum Realm, interacting with strange\u2026","poster":"assets/movie-ant-man-and-the-wasp-quantumania-2023-poster.jpg","backdrop":"assets/movie-ant-man-and-the-wasp-quantumania-2023-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":640146,"ratings":{"rtCritics":46,"rtCriticsLabel":"Rotten","rtAudience":81,"rtAudienceLabel":"Upright","imdb":6,"imdbVotes":281738,"tmdb":6.197,"tmdbVotes":6236}},{"id":"movie-appleseed-alpha-2014","title":"Appleseed Alpha","year":2014,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Science Fiction","Action"],"overview":"The Third World War (2099\u20132126) devastated part of the Earth. Former nations are reforming while new powers emerge, and groups of humans struggle to survive in ruined cities. The story follows Deunan Knute and her\u2026","poster":"assets/movie-appleseed-alpha-2014-poster.jpg","backdrop":"assets/movie-appleseed-alpha-2014-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"center_crop","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":269650,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":59,"rtAudienceLabel":"Spilled","imdb":6.5,"imdbVotes":9689,"tmdb":6.808,"tmdbVotes":436}},{"id":"movie-aquaman-and-the-lost-kingdom-2023","title":"Aquaman and the Lost Kingdom","year":2023,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Fantasy"],"overview":"Black Manta seeks revenge on Aquaman for his father's death. Wielding the Black Trident's power, he becomes a formidable foe. To defend Atlantis, Arthur (Aquaman) forges an alliance with his imprisoned brother. They\u2026","poster":"assets/movie-aquaman-and-the-lost-kingdom-2023-poster.jpg","backdrop":"assets/movie-aquaman-and-the-lost-kingdom-2023-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":572802,"ratings":{"rtCritics":33,"rtCriticsLabel":"Rotten","rtAudience":79,"rtAudienceLabel":"Upright","imdb":5.6,"imdbVotes":122422,"tmdb":6.48,"tmdbVotes":3748}},{"id":"movie-the-avengers-2012","title":"The Avengers","year":2012,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Science Fiction","Action","Adventure"],"overview":"When an unexpected enemy emerges and threatens global safety and security, Nick Fury, director of the international peacekeeping agency known as S.H.I.E.L.D., finds himself in need of a team to pull the world back\u2026","poster":"assets/movie-the-avengers-2012-poster.jpg","backdrop":"assets/movie-the-avengers-2012-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":24428,"ratings":{"rtCritics":91,"rtCriticsLabel":"Certified Fresh","rtAudience":91,"rtAudienceLabel":"Upright","imdb":8,"imdbVotes":1590693,"tmdb":8.084,"tmdbVotes":40262}},{"id":"movie-avengers-confidential-black-widow-punisher-2014","title":"Avengers Confidential: Black Widow & Punisher","year":2014,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Science Fiction","Action"],"overview":"When the Punisher takes out a black-market weapons dealer, he stumbles upon a far-reaching terrorist plot devised by a group known as Leviathan.","poster":"assets/movie-avengers-confidential-black-widow-punisher-2014-poster.jpg","backdrop":"assets/movie-avengers-confidential-black-widow-punisher-2014-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":257346,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":55,"rtAudienceLabel":"Spilled","imdb":5.7,"imdbVotes":5166,"tmdb":6.368,"tmdbVotes":303}},{"id":"movie-avengers-age-of-ultron-2015","title":"Avengers: Age of Ultron","year":2015,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"When Tony Stark tries to jumpstart a dormant peacekeeping program, things go awry and Earth\u2019s Mightiest Heroes are put to the ultimate test as the fate of the planet hangs in the balance. As the villainous Ultron\u2026","poster":"assets/movie-avengers-age-of-ultron-2015-poster.jpg","backdrop":"assets/movie-avengers-age-of-ultron-2015-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":99861,"ratings":{"rtCritics":75,"rtCriticsLabel":"Certified Fresh","rtAudience":82,"rtAudienceLabel":"Upright","imdb":7.3,"imdbVotes":1025876,"tmdb":7.278,"tmdbVotes":25289}},{"id":"movie-avengers-infinity-war-2018","title":"Avengers: Infinity War","year":2018,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Adventure","Action","Science Fiction"],"overview":"As the Avengers and their allies have continued to protect the world from threats too large for any one hero to handle, a new danger has emerged from the cosmic shadows: Thanos. A despot of intergalactic infamy, his\u2026","poster":"assets/movie-avengers-infinity-war-2018-poster.jpg","backdrop":"assets/movie-avengers-infinity-war-2018-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":299536,"ratings":{"rtCritics":85,"rtCriticsLabel":"Certified Fresh","rtAudience":92,"rtAudienceLabel":"Upright","imdb":8.4,"imdbVotes":1421954,"tmdb":8.246,"tmdbVotes":33331}},{"id":"movie-batman-ninja-2018","title":"Batman Ninja","year":2018,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Action","Science Fiction"],"overview":"Batman, along with many of his allies and adversaries, finds himself transported to feudal Japan by Gorilla Grodd's time displacement machine.","poster":"assets/movie-batman-ninja-2018-poster.jpg","backdrop":"assets/movie-batman-ninja-2018-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":485942,"ratings":{"rtCritics":84,"rtCriticsLabel":"Fresh","rtAudience":60,"rtAudienceLabel":"Upright","imdb":5.6,"imdbVotes":24579,"tmdb":5.9,"tmdbVotes":1106}},{"id":"movie-batman-v-superman-dawn-of-justice-2016","title":"Batman v Superman: Dawn of Justice","year":2016,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Fantasy"],"overview":"Fearing the actions of a god-like Super Hero left unchecked, Gotham City\u2019s own formidable, forceful vigilante takes on Metropolis\u2019s most revered, modern-day savior, while the world wrestles with what sort of hero it\u2026","poster":"assets/movie-batman-v-superman-dawn-of-justice-2016-poster.jpg","backdrop":"assets/movie-batman-v-superman-dawn-of-justice-2016-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":209112,"ratings":{"rtCritics":28,"rtCriticsLabel":"Rotten","rtAudience":63,"rtAudienceLabel":"Upright","imdb":6.4,"imdbVotes":801382,"tmdb":6.014,"tmdbVotes":19527}},{"id":"movie-batman-the-dark-knight-returns-part-1-2012","title":"Batman: The Dark Knight Returns, Part 1","year":2012,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Science Fiction","Action","Animation"],"overview":"Batman has not been seen for ten years. A new breed of criminal ravages Gotham City, forcing 55-year-old Bruce Wayne back into the cape and cowl. But, does he still have what it takes to fight crime in a new era?","poster":"assets/movie-batman-the-dark-knight-returns-part-1-2012-poster.jpg","backdrop":"assets/movie-batman-the-dark-knight-returns-part-1-2012-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":123025,"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":93,"rtAudienceLabel":"Upright","imdb":7.9,"imdbVotes":68943,"tmdb":7.742,"tmdbVotes":1766}},{"id":"movie-black-adam-2022","title":"Black Adam","year":2022,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"Nearly 5,000 years after he was bestowed with the almighty powers of the Egyptian gods\u2014and imprisoned just as quickly\u2014Black Adam is freed from his earthly tomb, ready to unleash his unique form of justice on the\u2026","poster":"assets/movie-black-adam-2022-poster.jpg","backdrop":"assets/movie-black-adam-2022-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":436270,"ratings":{"rtCritics":39,"rtCriticsLabel":"Rotten","rtAudience":87,"rtAudienceLabel":"Upright","imdb":6.1,"imdbVotes":309624,"tmdb":6.747,"tmdbVotes":7370}},{"id":"movie-black-panther-2018","title":"Black Panther","year":2018,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"King T'Challa returns home to the reclusive, technologically advanced African nation of Wakanda to serve as his country's new leader. However, T'Challa soon finds that he is challenged for the throne by factions\u2026","poster":"assets/movie-black-panther-2018-poster.jpg","backdrop":"assets/movie-black-panther-2018-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":284054,"ratings":{"rtCritics":96,"rtCriticsLabel":"Certified Fresh","rtAudience":null,"rtAudienceLabel":"Spilled","imdb":7.3,"imdbVotes":931120,"tmdb":7.36,"tmdbVotes":24190}},{"id":"movie-black-panther-wakanda-forever-2022","title":"Black Panther: Wakanda Forever","year":2022,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"Queen Ramonda, Shuri, M\u2019Baku, Okoye and the Dora Milaje fight to protect their nation from intervening world powers in the wake of King T\u2019Challa\u2019s death. As the Wakandans strive to embrace their next chapter, the\u2026","poster":"assets/movie-black-panther-wakanda-forever-2022-poster.jpg","backdrop":"assets/movie-black-panther-wakanda-forever-2022-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":505642,"ratings":{"rtCritics":84,"rtCriticsLabel":"Certified Fresh","rtAudience":93,"rtAudienceLabel":"Upright","imdb":6.6,"imdbVotes":405088,"tmdb":6.984,"tmdbVotes":7920}},{"id":"movie-blame-2017","title":"BLAME!","year":2017,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Drama","Science Fiction"],"overview":"In the distant technological future, civilization has reached its ultimate Net-based form. An \"infection\" in the past caused the automated systems to spiral out of order, resulting in a multi-leveled city structure\u2026","poster":"assets/movie-blame-2017-poster.jpg","backdrop":"assets/movie-blame-2017-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":409421,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":61,"rtAudienceLabel":"Upright","imdb":6.6,"imdbVotes":10258,"tmdb":6.523,"tmdbVotes":370}},{"id":"movie-bleach-the-movie-fade-to-black-2008","title":"Bleach the Movie: Fade to Black","year":2008,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Animation","Fantasy"],"overview":"A strange disturbance in the World of the Living sends Ichigo and Kon to the Soul Society, where the Seireitei has been devastated by an explosion of reishi and Rukia is missing. Stranger still, none of the Soul\u2026","poster":"assets/movie-bleach-the-movie-fade-to-black-2008-poster.jpg","backdrop":"assets/movie-bleach-the-movie-fade-to-black-2008-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":17165,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":67,"rtAudienceLabel":"Upright","imdb":7.1,"imdbVotes":3693,"tmdb":7.1,"tmdbVotes":206}},{"id":"tv-90-day-fiance-before-the-90-days-2017","title":"90 Day Fianc\u00e9: Before the 90 Days","year":2017,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Reality"],"overview":"Follow couples who have an existing relationship online, but haven't met in person. We'll experience their journey as they travel to the other's foreign country for the first time in an attempt to establish an\u2026","poster":"assets/tv-90-day-fiance-before-the-90-days-2017-poster.jpg","backdrop":"assets/tv-90-day-fiance-before-the-90-days-2017-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":73319,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.5,"tmdbVotes":45}},{"id":"tv-90-day-fiance-the-other-way-2019","title":"90 Day Fianc\u00e9: The Other Way","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Reality"],"overview":"Americans move to a foreign country all in the name of love. Will uprooting their lives in the United States pay off, or will they be packing up and moving back to America brokenhearted?","poster":"assets/tv-90-day-fiance-the-other-way-2019-poster.jpg","backdrop":"assets/tv-90-day-fiance-the-other-way-2019-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":90046,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.8,"tmdbVotes":34}},{"id":"tv-the-100-2014","title":"The 100","year":2014,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Sci-Fi & Fantasy","Action & Adventure","Drama"],"overview":"100 years in the future, when the Earth has been abandoned due to radioactivity, the last surviving humans live on an ark orbiting the planet \u2014 but the ark won't last forever. So the repressive regime picks 100\u2026","poster":"assets/tv-the-100-2014-poster.jpg","backdrop":"assets/tv-the-100-2014-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":48866,"ratings":{"rtCritics":93,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.878,"tmdbVotes":8855}},{"id":"tv-the-abbott-and-costello-show-1952","title":"The Abbott and Costello Show","year":1952,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy"],"overview":"Bud and Lou are unemployed actors living in Mr. Fields\u2019 boarding house. Lou\u2019s girlfriend Hillary lives across the hall. Many situations arise leading to slapstick and puns.","poster":"assets/tv-the-abbott-and-costello-show-1952-poster.jpg","backdrop":"assets/tv-the-abbott-and-costello-show-1952-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":11821,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.2,"tmdbVotes":22}},{"id":"tv-accel-world-2012","title":"Accel World","year":2012,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Action & Adventure","Drama"],"overview":"A short, overweight student uses the Neuro Link, an evolution of the Nerve Gear, to escape himself from the reality. But his skills in the virtual world brings him to the attention of Kuroyukihime, a popular student\u2026","poster":"assets/tv-accel-world-2012-poster.jpg","backdrop":"assets/tv-accel-world-2012-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"center_crop","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":43167,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.429,"tmdbVotes":163}},{"id":"tv-ahsoka-2023","title":"Ahsoka","year":2023,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Sci-Fi & Fantasy","Action & Adventure","Drama"],"overview":"Former Jedi Knight Ahsoka Tano investigates an emerging threat to a vulnerable galaxy.","poster":"assets/tv-ahsoka-2023-poster.jpg","backdrop":"assets/tv-ahsoka-2023-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":114461,"ratings":{"rtCritics":85,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.4,"tmdbVotes":1351}},{"id":"tv-american-dad-2005","title":"American Dad!","year":2005,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Comedy"],"overview":"The series focuses on an eccentric motley crew that is the Smith family and their three housemates: Father, husband, and breadwinner Stan Smith; his better half housewife, Francine Smith; their college-aged daughter,\u2026","poster":"assets/tv-american-dad-2005-poster.jpg","backdrop":"assets/tv-american-dad-2005-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1433,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.022,"tmdbVotes":2481}},{"id":"tv-american-gods-2017","title":"American Gods","year":2017,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Mystery","Sci-Fi & Fantasy"],"overview":"An ex-con becomes the traveling partner of a conman who turns out to be one of the older gods trying to recruit troops to battle the upstart deities. Based on Neil Gaiman's fantasy novel.","poster":"assets/tv-american-gods-2017-poster.jpg","backdrop":"assets/tv-american-gods-2017-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":46639,"ratings":{"rtCritics":75,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.1,"tmdbVotes":1852}},{"id":"tv-andromeda-2000","title":"Andromeda","year":2000,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action & Adventure","Drama","Sci-Fi & Fantasy"],"overview":"Captain Dylan Hunt and his crew quest to restore a government that once presided over an extended peace and prosperity.","poster":"assets/tv-andromeda-2000-poster.jpg","backdrop":"assets/tv-andromeda-2000-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":2985,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.068,"tmdbVotes":315}},{"id":"tv-aqua-teen-hunger-force-2000","title":"Aqua Teen Hunger Force","year":2000,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Comedy"],"overview":"The surreal adventures of three anthropomorphic fast food items: Master Shake, Frylock and Meatwad, and their human nextdoor neighbor, Carl Brutananadilewski.","poster":"assets/tv-aqua-teen-hunger-force-2000-poster.jpg","backdrop":"assets/tv-aqua-teen-hunger-force-2000-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":251,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.5,"tmdbVotes":272}},{"id":"tv-arifureta-from-commonplace-to-world-s-strongest-2019","title":"Arifureta: From Commonplace to World's Strongest","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"Hajime Nagumo and his high school class are suddenly summoned to a fantastical land as heroes. But while most of his classmates have powerful stats and abilities, Hajime does not. Underappreciated and unprepared, he\u2026","poster":"assets/tv-arifureta-from-commonplace-to-world-s-strongest-2019-poster.jpg","backdrop":"assets/tv-arifureta-from-commonplace-to-world-s-strongest-2019-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":86034,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.382,"tmdbVotes":662}},{"id":"tv-arrow-2012","title":"Arrow","year":2012,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Crime","Drama","Action & Adventure"],"overview":"Spoiled billionaire playboy Oliver Queen is missing and presumed dead when his yacht is lost at sea. He returns five years later a changed man, determined to clean up the city as a hooded vigilante armed with a bow.","poster":"assets/tv-arrow-2012-poster.jpg","backdrop":"assets/tv-arrow-2012-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1412,"ratings":{"rtCritics":86,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.834,"tmdbVotes":6537}},{"id":"tv-avatar-the-last-airbender-2024","title":"Avatar: The Last Airbender","year":2024,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action & Adventure","Sci-Fi & Fantasy","Drama"],"overview":"A young boy known as the Avatar must master the four elemental powers to save a world at war \u2014 and fight a ruthless enemy bent on stopping him.","poster":"assets/tv-avatar-the-last-airbender-2024-poster.jpg","backdrop":"assets/tv-avatar-the-last-airbender-2024-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":82452,"ratings":{"rtCritics":66,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.8,"tmdbVotes":1406}},{"id":"tv-avatar-seven-havens-2026","title":"Avatar: Seven Havens","year":2026,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"In a world shattered by a devastating cataclysm, a young Earthbender discovers she's the new Avatar after Korra. But in this dangerous era, that title marks her as humanity's destroyer, not its savior. Hunted by both\u2026","poster":"assets/tv-avatar-seven-havens-2026-poster.jpg","backdrop":"assets/tv-avatar-seven-havens-2026-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":284833,"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.9,"tmdbVotes":183}},{"id":"tv-batman-the-brave-and-the-bold-2008","title":"Batman: The Brave and the Bold","year":2008,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"The Caped Crusader is teamed up with Blue Beetle, Green Arrow, Aquaman and countless others in his quest to uphold justice.","poster":"assets/tv-batman-the-brave-and-the-bold-2008-poster.jpg","backdrop":"assets/tv-batman-the-brave-and-the-bold-2008-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":15804,"ratings":{"rtCritics":96,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.6,"tmdbVotes":295}},{"id":"tv-batwoman-2019","title":"Batwoman","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Sci-Fi & Fantasy","Action & Adventure"],"overview":"Kate Kane, armed with a passion for social justice and a flair for speaking her mind, soars onto the streets of Gotham as Batwoman, an out lesbian and highly trained street fighter primed to snuff out the failing\u2026","poster":"assets/tv-batwoman-2019-poster.jpg","backdrop":"assets/tv-batwoman-2019-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":89247,"ratings":{"rtCritics":83,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.8,"tmdbVotes":1619}},{"id":"tv-big-mouth-2017","title":"Big Mouth","year":2017,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy","Animation"],"overview":"Teenage friends find their lives upended by the wonders and horrors of puberty in this edgy comedy from real-life pals Nick Kroll and Andrew Goldberg.","poster":"assets/tv-big-mouth-2017-poster.jpg","backdrop":"assets/tv-big-mouth-2017-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":74204,"ratings":{"rtCritics":95,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.591,"tmdbVotes":1274}},{"id":"tv-black-lightning-2018","title":"Black Lightning","year":2018,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action & Adventure","Sci-Fi & Fantasy","Drama"],"overview":"Jefferson Pierce is a man wrestling with a secret. As the father of two daughters and principal of a charter high school that also serves as a safe haven for young people in a New Orleans neighborhood overrun by gang\u2026","poster":"assets/tv-black-lightning-2018-poster.jpg","backdrop":"assets/tv-black-lightning-2018-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":71663,"ratings":{"rtCritics":92,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.907,"tmdbVotes":991}}]},{"key":"mindel","movies":[{"id":"movie-chicago-2002","title":"Chicago","year":2002,"type":"movie","runtimeSeconds":6808,"seasonCount":null,"communityRating":7.131,"criticRating":87,"genres":["Comedy","Crime","Drama"],"overview":"Murderesses Velma Kelly and Roxie Hart find themselves on death row together and fight for the fame that will keep them from the gallows in 1920s Chicago.","poster":"assets/movie-chicago-2002-poster.jpg","backdrop":"assets/movie-chicago-2002-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:24:53.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":1574,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":87,"rtCriticsLabel":"Certified Fresh","rtAudience":83,"rtAudienceLabel":"Upright","imdb":7.2,"imdbVotes":259272,"tmdb":7.135,"tmdbVotes":3025}},{"id":"movie-coherence-2014","title":"Coherence","year":2014,"type":"movie","runtimeSeconds":5286,"seasonCount":null,"communityRating":7.21,"criticRating":89,"genres":["Thriller","Science Fiction"],"overview":"Four couples gather for dinner the night a mysterious and powerful comet passes overhead.","poster":"assets/movie-coherence-2014-poster.jpg","backdrop":"assets/movie-coherence-2014-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2017-08-12T23:49:00.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":220289,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":89,"rtCriticsLabel":"Certified Fresh","rtAudience":81,"rtAudienceLabel":"Upright","imdb":7.1,"imdbVotes":180354,"tmdb":7.208,"tmdbVotes":3702}},{"id":"movie-the-killing-of-a-sacred-deer-2017","title":"The Killing of a Sacred Deer","year":2017,"type":"movie","runtimeSeconds":7262,"seasonCount":null,"communityRating":7.003,"criticRating":79,"genres":["Drama","Thriller","Mystery"],"overview":"Dr. Steven Murphy is a renowned cardiovascular surgeon who presides over a spotless household with his wife and two children. Lurking at the margins of his idyllic suburban existence is Martin, a fatherless teen who\u2026","poster":"assets/movie-the-killing-of-a-sacred-deer-2017-poster.jpg","backdrop":"assets/movie-the-killing-of-a-sacred-deer-2017-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-22T21:49:26.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":399057,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":79,"rtCriticsLabel":"Certified Fresh","rtAudience":63,"rtAudienceLabel":"Upright","imdb":7,"imdbVotes":219488,"tmdb":7.001,"tmdbVotes":4640}},{"id":"movie-night-is-short-walk-on-girl-2017","title":"Night Is Short, Walk On Girl","year":2017,"type":"movie","runtimeSeconds":5548,"seasonCount":null,"communityRating":7.421,"criticRating":90,"genres":["Comedy","Romance","Animation"],"overview":"As a group of university students go out for a night on the town, a sophomore known only as \"The Girl with Black Hair\" experiences a series of surreal encounters with the local nightlife \u2013 all the while unaware of\u2026","poster":"assets/movie-night-is-short-walk-on-girl-2017-poster.jpg","backdrop":"assets/movie-night-is-short-walk-on-girl-2017-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T17:39:14.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":430214,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":90,"rtCriticsLabel":"Fresh","rtAudience":84,"rtAudienceLabel":"Upright","imdb":7.5,"imdbVotes":7640,"tmdb":7.4,"tmdbVotes":267}},{"id":"movie-thelma-louise-1991","title":"Thelma & Louise","year":1991,"type":"movie","runtimeSeconds":7786,"seasonCount":null,"communityRating":7.596,"criticRating":87,"genres":["Drama","Crime","Adventure"],"overview":"Taking a break from their dreary lives, close friends Thelma and Louise embark on a short weekend trip that ends in unforeseen incriminating circumstances. As fugitives, both women rediscover the strength of their\u2026","poster":"assets/movie-thelma-louise-1991-poster.jpg","backdrop":"assets/movie-thelma-louise-1991-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:24:40.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":1541,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":87,"rtCriticsLabel":"Certified Fresh","rtAudience":82,"rtAudienceLabel":"Upright","imdb":7.6,"imdbVotes":197947,"tmdb":7.594,"tmdbVotes":4063}},{"id":"movie-vicky-cristina-barcelona-2008","title":"Vicky Cristina Barcelona","year":2008,"type":"movie","runtimeSeconds":5804,"seasonCount":null,"communityRating":6.798,"criticRating":80,"genres":["Drama","Romance"],"overview":"Two girlfriends on a summer holiday in Spain become enamored with the same painter, unaware that his ex-wife, with whom he has a tempestuous relationship, is about to re-enter the picture.","poster":"assets/movie-vicky-cristina-barcelona-2008-poster.jpg","backdrop":"assets/movie-vicky-cristina-barcelona-2008-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:25:34.0000000Z","lastPlayedAt":"2026-08-11T20:12:57.3064089Z","availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":5038,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":80,"rtCriticsLabel":"Certified Fresh","rtAudience":74,"rtAudienceLabel":"Upright","imdb":7.1,"imdbVotes":283286,"tmdb":6.797,"tmdbVotes":4164}}],"shows":[{"id":"tv-all-creatures-great-small-2020","title":"All Creatures Great & Small","year":2020,"type":"tv","runtimeSeconds":3000,"seasonCount":7,"communityRating":8.2,"criticRating":null,"genres":["Drama","Comedy"],"overview":"The heartwarming and humorous adventures of a young country vet in the Yorkshire Dales in the 1930s. A remake of the 1978 series.","poster":"assets/tv-all-creatures-great-small-2020-poster.jpg","backdrop":"assets/tv-all-creatures-great-small-2020-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-11-04T20:13:03.4266156Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":108255,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":99,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.2,"tmdbVotes":168}},{"id":"tv-back-to-life-2019","title":"Back to Life","year":2019,"type":"tv","runtimeSeconds":1500,"seasonCount":2,"communityRating":7.367,"criticRating":null,"genres":["Comedy","Drama"],"overview":"When Miri Matteson returns home after eighteen years, can she integrate back into her old life? With a terrible event from her past hanging over her, it won\u2019t be easy.","poster":"assets/tv-back-to-life-2019-poster.jpg","backdrop":"assets/tv-back-to-life-2019-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0688758Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":88510,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.4,"tmdbVotes":65}},{"id":"tv-big-boys-2022","title":"Big Boys","year":2022,"type":"tv","runtimeSeconds":1440,"seasonCount":3,"communityRating":7.6,"criticRating":null,"genres":["Comedy","Drama"],"overview":"Two boys from very different ends of the 'spectrum of masculinity' become best friends at Brent University freshers' week; in their first year of uni, they explore, experiment and try to discover themselves, helping\u2026","poster":"assets/tv-big-boys-2022-poster.jpg","backdrop":"assets/tv-big-boys-2022-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-11-04T20:25:58.2156837Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":202851,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.6,"tmdbVotes":49}},{"id":"tv-call-the-midwife-2012","title":"Call the Midwife","year":2012,"type":"tv","runtimeSeconds":3120,"seasonCount":15,"communityRating":7.5,"criticRating":null,"genres":["Drama"],"overview":"Drama following the lives of a group of midwives working in the poverty-stricken East End of London during the 1950s, based on the best-selling memoirs of Jennifer Worth.","poster":"assets/tv-call-the-midwife-2012-poster.jpg","backdrop":"assets/tv-call-the-midwife-2012-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0377216Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":39793,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.577,"tmdbVotes":267}},{"id":"tv-derry-girls-2018","title":"Derry Girls","year":2018,"type":"tv","runtimeSeconds":1380,"seasonCount":3,"communityRating":8.144,"criticRating":null,"genres":["Comedy","Drama"],"overview":"Amidst the political conflict of Northern Ireland in the 1990s, five secondary school students square off with the universal challenges of being a teenager.","poster":"assets/tv-derry-girls-2018-poster.jpg","backdrop":"assets/tv-derry-girls-2018-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-02T20:01:55.8955537Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":76148,"artwork":{"posterKind":"center_crop","backdropKind":"backdrop"},"ratings":{"rtCritics":99,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.138,"tmdbVotes":454}},{"id":"tv-desperate-housewives-2004","title":"Desperate Housewives","year":2004,"type":"tv","runtimeSeconds":2520,"seasonCount":8,"communityRating":7.896,"criticRating":null,"genres":["Mystery","Drama","Comedy"],"overview":"Looking down on her friends and family isn't a way of life for Mary Alice Young... it's a way of death. One day, in her perfect house, in the loveliest of suburbs, Mary Alice ended it all. Now she's taking us into\u2026","poster":"assets/tv-desperate-housewives-2004-poster.jpg","backdrop":"assets/tv-desperate-housewives-2004-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-29T20:56:40.3505596Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":693,"artwork":{"posterKind":"poster","backdropKind":"center_crop"},"ratings":{"rtCritics":72,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.896,"tmdbVotes":2171}},{"id":"tv-the-diplomat-2023","title":"The Diplomat","year":2023,"type":"tv","runtimeSeconds":null,"seasonCount":4,"communityRating":7.569,"criticRating":null,"genres":["Drama","War & Politics"],"overview":"Amid an international crisis, a US diplomat contends with her high-profile job as ambassador to the UK and her strained marriage to a political star.","poster":"assets/tv-the-diplomat-2023-poster.jpg","backdrop":"assets/tv-the-diplomat-2023-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0640348Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":203857,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":93,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.652,"tmdbVotes":521}},{"id":"tv-the-durrells-2016","title":"The Durrells","year":2016,"type":"tv","runtimeSeconds":2760,"seasonCount":4,"communityRating":7.402,"criticRating":null,"genres":["Drama","Comedy","Family"],"overview":"In 1935, financially strapped widow Louisa Durrell, whose life has fallen apart, decides to move from England, with her four children (three sons, one daughter), to the island of Corfu, Greece. Once there, the family\u2026","poster":"assets/tv-the-durrells-2016-poster.jpg","backdrop":"assets/tv-the-durrells-2016-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0619436Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":66134,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":94,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.4,"tmdbVotes":127}},{"id":"tv-etoile-2025","title":"\u00c9toile","year":2025,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":7.197,"criticRating":null,"genres":["Comedy","Drama"],"overview":"In an ambitious gambit to save their storied institutions, two world-renowned ballet companies in New York City and Paris swap their most talented stars.","poster":"assets/tv-etoile-2025-poster.jpg","backdrop":"assets/tv-etoile-2025-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0601383Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":225383,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":86,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.3,"tmdbVotes":40}},{"id":"tv-gilmore-girls-2000","title":"Gilmore Girls","year":2000,"type":"tv","runtimeSeconds":2640,"seasonCount":7,"communityRating":7.893,"criticRating":null,"genres":["Comedy","Drama"],"overview":"Set in the charming town of Stars Hollow, Connecticut, the series follows the captivating lives of Lorelai and Rory Gilmore, a mother/daughter pair who have a relationship most people only dream of.","poster":"assets/tv-gilmore-girls-2000-poster.jpg","backdrop":"assets/tv-gilmore-girls-2000-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0631035Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":4586,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.9,"tmdbVotes":1339}},{"id":"tv-ginny-georgia-2021","title":"Ginny & Georgia","year":2021,"type":"tv","runtimeSeconds":null,"seasonCount":3,"communityRating":8.026,"criticRating":null,"genres":["Comedy","Drama"],"overview":"Free-spirited Georgia and her two kids, Ginny and Austin, move north in search of a fresh start but find that the road to new beginnings can be bumpy.","poster":"assets/tv-ginny-georgia-2021-poster.jpg","backdrop":"assets/tv-ginny-georgia-2021-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0694828Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":117581,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":68,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8,"tmdbVotes":1840}},{"id":"tv-hellcats-2010","title":"Hellcats","year":2010,"type":"tv","runtimeSeconds":2460,"seasonCount":1,"communityRating":7.5,"criticRating":null,"genres":["Drama"],"overview":"Pre-law student Marti Perkins' world is flipped upside down when she loses her scholarship, and realizes the only way she can stay in school is by reigniting her dormant teen gymnastic skills to win a place on Lancer\u2026","poster":"assets/tv-hellcats-2010-poster.jpg","backdrop":"assets/tv-hellcats-2010-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-22T20:39:02.7719318Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":32504,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":65,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.5,"tmdbVotes":116}},{"id":"tv-high-potential-2024","title":"High Potential","year":2024,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":8.201,"criticRating":null,"genres":["Drama","Crime","Mystery"],"overview":"Morgan is a single mom with an exceptional mind, whose unconventional knack for solving crimes leads to an unusual and unstoppable partnership with a by-the-book seasoned detective.","poster":"assets/tv-high-potential-2024-poster.jpg","backdrop":"assets/tv-high-potential-2024-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0686091Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":226637,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":98,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.3,"tmdbVotes":707}},{"id":"tv-how-to-get-to-heaven-from-belfast-2026","title":"How to Get to Heaven from Belfast","year":2026,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":7.027,"criticRating":null,"genres":["Mystery","Comedy","Drama"],"overview":"Three lifelong pals embark on a chaotic quest to solve the mystery of their old friend's suspicious death and keep their own dark secret under wraps.","poster":"assets/tv-how-to-get-to-heaven-from-belfast-2026-poster.jpg","backdrop":"assets/tv-how-to-get-to-heaven-from-belfast-2026-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0683192Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":233079,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":95,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.063,"tmdbVotes":95}},{"id":"tv-the-hunting-wives-2025","title":"The Hunting Wives","year":2025,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":6.932,"criticRating":null,"genres":["Drama","Mystery"],"overview":"Sophie trades New England for East Texas and falls into a wealthy socialite's magnetic orbit \u2014 where a clique of housewives hide deadly secrets.","poster":"assets/tv-the-hunting-wives-2025-poster.jpg","backdrop":"assets/tv-the-hunting-wives-2025-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-20T19:42:46.3227892Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":244447,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":81,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.964,"tmdbVotes":112}},{"id":"tv-the-lost-flowers-of-alice-hart-2023","title":"The Lost Flowers of Alice Hart","year":2023,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":7.634,"criticRating":null,"genres":["Drama","Mystery"],"overview":"After losing her parents in a mysterious fire, nine-year-old Alice Hart is raised by her grandmother June on a flower farm where she learns there are secrets within secrets. But years on, an unearthed betrayal sees\u2026","poster":"assets/tv-the-lost-flowers-of-alice-hart-2023-poster.jpg","backdrop":"assets/tv-the-lost-flowers-of-alice-hart-2023-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0607236Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":125816,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":82,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.64,"tmdbVotes":161}},{"id":"tv-love-is-blind-2020","title":"Love Is Blind","year":2020,"type":"tv","runtimeSeconds":null,"seasonCount":11,"communityRating":6.261,"criticRating":null,"genres":["Reality"],"overview":"Nick and Vanessa Lachey host this social experiment where single men and women look for love and get engaged, all before meeting in person.","poster":"assets/tv-love-is-blind-2020-poster.jpg","backdrop":"assets/tv-love-is-blind-2020-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-22T17:11:08.2447226Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":99353,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":66,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.233,"tmdbVotes":118}},{"id":"tv-maximum-pleasure-guaranteed-2026","title":"Maximum Pleasure Guaranteed","year":2026,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":6.676,"criticRating":null,"genres":["Comedy"],"overview":"A newly divorced mom falls down a dangerous rabbit hole of blackmail, murder, and youth soccer.","poster":"assets/tv-maximum-pleasure-guaranteed-2026-poster.jpg","backdrop":"assets/tv-maximum-pleasure-guaranteed-2026-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-07T21:04:02.8277793Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":285404,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":93,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.799,"tmdbVotes":92}},{"id":"tv-minx-2022","title":"Minx","year":2022,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":6.833,"criticRating":null,"genres":["Comedy","Drama"],"overview":"An earnest young feminist joins forces with a low-rent publisher to make the world's first erotic magazine for women.","poster":"assets/tv-minx-2022-poster.jpg","backdrop":"assets/tv-minx-2022-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0653613Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":118303,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":93,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.9,"tmdbVotes":123}},{"id":"tv-offspring-2010","title":"Offspring","year":2010,"type":"tv","runtimeSeconds":3600,"seasonCount":7,"communityRating":6.9,"criticRating":null,"genres":["Drama"],"overview":"An exuberant drama set in Melbourne's Fitzroy, centering on Nina Proudman and her struggle to deal with her fabulously messy family, her hunt for a decent love life and her tendency to overthink and fly off into fantasy.","poster":"assets/tv-offspring-2010-poster.jpg","backdrop":"assets/tv-offspring-2010-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0664581Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":33155,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.9,"tmdbVotes":27}},{"id":"tv-only-murders-in-the-building-2021","title":"Only Murders in the Building","year":2021,"type":"tv","runtimeSeconds":null,"seasonCount":5,"communityRating":8.398,"criticRating":null,"genres":["Comedy","Mystery","Crime"],"overview":"Three strangers share an obsession with true crime and suddenly find themselves wrapped up in one.","poster":"assets/tv-only-murders-in-the-building-2021-poster.jpg","backdrop":"assets/tv-only-murders-in-the-building-2021-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-11-04T20:25:58.2163301Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":107113,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":95,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.398,"tmdbVotes":2333}},{"id":"tv-outlander-blood-of-my-blood-2025","title":"Outlander: Blood of My Blood","year":2025,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":8.542,"criticRating":null,"genres":["Drama"],"overview":"From the battlefields of World War I to the rugged Highlands of 18th century Scotland, two fated couples must defy the forces that seek to tear them apart, unfolding in surprising and unforeseen ways in this romantic\u2026","poster":"assets/tv-outlander-blood-of-my-blood-2025-poster.jpg","backdrop":"assets/tv-outlander-blood-of-my-blood-2025-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0691373Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":207484,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":94,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.738,"tmdbVotes":124}},{"id":"tv-rivals-2024","title":"Rivals","year":2024,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":7.44,"criticRating":null,"genres":["Drama"],"overview":"It is 1986 and Britain is booming. \"Rivals\" dives headfirst into the cutthroat world of TV where hair-dos are big and ambitions are even bigger. Deals are brokered in boardrooms, as well as bedrooms. Nobody can be\u2026","poster":"assets/tv-rivals-2024-poster.jpg","backdrop":"assets/tv-rivals-2024-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0645815Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":208921,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":96,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.4,"tmdbVotes":93}},{"id":"tv-rooster-2026","title":"Rooster","year":2026,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":7.431,"criticRating":null,"genres":["Comedy"],"overview":"On a college campus, an author navigates a complicated relationship with his daughter.","poster":"assets/tv-rooster-2026-poster.jpg","backdrop":"assets/tv-rooster-2026-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.063389Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":254953,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":88,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.423,"tmdbVotes":144}},{"id":"tv-sex-and-the-city-1998","title":"Sex and the City","year":1998,"type":"tv","runtimeSeconds":null,"seasonCount":6,"communityRating":7.365,"criticRating":null,"genres":["Drama","Comedy"],"overview":"Based on the bestselling book by Candace Bushnell, Sex and the City tells the story of four best friends, all single and in their late thirties, as they pursue their careers and talk about their sex lives, all while\u2026","poster":"assets/tv-sex-and-the-city-1998-poster.jpg","backdrop":"assets/tv-sex-and-the-city-1998-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0679324Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":105,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":70,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.351,"tmdbVotes":2220}},{"id":"tv-skymed-2022","title":"SkyMed","year":2022,"type":"tv","runtimeSeconds":2640,"seasonCount":4,"communityRating":6.665,"criticRating":null,"genres":["Drama"],"overview":"Life, death and drama at 20,000 feet. The series weaves together intense character journeys and high-stakes medical rescues, as we follow the triumphs, heartbreaks and tribulations of budding nurses and pilots flying\u2026","poster":"assets/tv-skymed-2022-poster.jpg","backdrop":"assets/tv-skymed-2022-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-22T19:44:29.2431354Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":133908,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.699,"tmdbVotes":98}},{"id":"tv-so-you-think-you-can-dance-2008","title":"So You Think You Can Dance","year":2008,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":9.8,"criticRating":null,"genres":["Family","Reality"],"overview":"So You Think You Can Dance is a joint Belgian-Dutch dance competition show broadcast on RTL 5 and vtm television stations. The first season was broadcast only in the Netherlands, whereas starting with season 2, the\u2026","poster":"assets/tv-so-you-think-you-can-dance-2008-poster.jpg","backdrop":"assets/tv-so-you-think-you-can-dance-2008-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-23T11:11:35.4124418Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":40231,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":9.8,"tmdbVotes":4}},{"id":"tv-the-white-lotus-2021","title":"The White Lotus","year":2021,"type":"tv","runtimeSeconds":null,"seasonCount":3,"communityRating":7.597,"criticRating":null,"genres":["Comedy","Drama","Mystery"],"overview":"Follow the exploits of various guests and employees at an exclusive tropical resort over the span of a week as with each passing day, a darker complexity emerges in these picture-perfect travelers, the hotel\u2019s\u2026","poster":"assets/tv-the-white-lotus-2021-poster.jpg","backdrop":"assets/tv-the-white-lotus-2021-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-20T02:45:52.8742674Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":111803,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":90,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.599,"tmdbVotes":1604}},{"id":"tv-yellowjackets-2021","title":"Yellowjackets","year":2021,"type":"tv","runtimeSeconds":null,"seasonCount":3,"communityRating":7.431,"criticRating":null,"genres":["Drama","Mystery"],"overview":"This equal parts survival epic, psychological horror story and coming-of-age drama tells the saga of a team of wildly talented high school girls soccer players who become the (un)lucky survivors of a plane crash deep\u2026","poster":"assets/tv-yellowjackets-2021-poster.jpg","backdrop":"assets/tv-yellowjackets-2021-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-11-04T20:31:47.4592756Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":117488,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":92,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.431,"tmdbVotes":1070}}],"anime":[],"discover":[{"id":"movie-across-the-hall-2009","title":"Across the Hall","year":2009,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Thriller","Mystery"],"overview":"Convinced that his fiancee is cheating on him, a man follows her to a hotel and calls his best friend to help him avoid a calamity.","poster":"assets/movie-across-the-hall-2009-poster.jpg","backdrop":"assets/movie-across-the-hall-2009-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":21469,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":39,"rtAudienceLabel":"Spilled","imdb":5.8,"imdbVotes":5130,"tmdb":6,"tmdbVotes":129}},{"id":"movie-addicted-2014","title":"Addicted","year":2014,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Thriller"],"overview":"A gallerist risks her family and flourishing career when she enters into an affair with a talented painter and slowly loses control of her life.","poster":"assets/movie-addicted-2014-poster.jpg","backdrop":"assets/movie-addicted-2014-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":235271,"ratings":{"rtCritics":7,"rtCriticsLabel":"Rotten","rtAudience":51,"rtAudienceLabel":"Spilled","imdb":5,"imdbVotes":13131,"tmdb":5.928,"tmdbVotes":466}},{"id":"movie-adulterers-2016","title":"Adulterers","year":2016,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Thriller","Drama"],"overview":"On a steamy New Orleans afternoon, Sam Deuprey decides to surprise his beautiful wife, Ashley, for their anniversary and comes home early. But Ashley is not alone in the bedroom. She and her lover, Damien are about\u2026","poster":"assets/movie-adulterers-2016-poster.jpg","backdrop":"assets/movie-adulterers-2016-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":376004,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":37,"rtAudienceLabel":"Spilled","imdb":5.1,"imdbVotes":2144,"tmdb":6.2,"tmdbVotes":116}},{"id":"movie-alone-with-her-2006","title":"Alone With Her","year":2006,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Crime","Drama","Thriller"],"overview":"The harrowing story of a disturbed young man's attempts to win the affections of an unsuspecting young woman. When Doug first sees Amy, he instantly falls for her and begins to watch her every move, going so far as\u2026","poster":"assets/movie-alone-with-her-2006-poster.jpg","backdrop":"assets/movie-alone-with-her-2006-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":18206,"ratings":{"rtCritics":70,"rtCriticsLabel":"Fresh","rtAudience":46,"rtAudienceLabel":"Spilled","imdb":6,"imdbVotes":4359,"tmdb":5.9,"tmdbVotes":94}},{"id":"movie-awake-2007","title":"Awake","year":2007,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Thriller","Crime","Mystery"],"overview":"While undergoing heart surgery, a man experiences a phenomenon called \u2018anesthetic awareness\u2019, which leaves him awake but paralyzed throughout the operation. As various obstacles present themselves, his wife must make\u2026","poster":"assets/movie-awake-2007-poster.jpg","backdrop":"assets/movie-awake-2007-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":13483,"ratings":{"rtCritics":23,"rtCriticsLabel":"Rotten","rtAudience":55,"rtAudienceLabel":"Spilled","imdb":6.5,"imdbVotes":89389,"tmdb":6.586,"tmdbVotes":1649}},{"id":"movie-black-bear-2020","title":"Black Bear","year":2020,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Thriller"],"overview":"At a remote lake house in the Adirondack Mountains, a couple entertains an out-of-town guest looking for inspiration in her filmmaking. The group quickly falls into a calculated game of desire, manipulation, and\u2026","poster":"assets/movie-black-bear-2020-poster.jpg","backdrop":"assets/movie-black-bear-2020-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":624788,"ratings":{"rtCritics":89,"rtCriticsLabel":"Certified Fresh","rtAudience":64,"rtAudienceLabel":"Upright","imdb":6.5,"imdbVotes":18408,"tmdb":6.337,"tmdbVotes":315}},{"id":"movie-butterfly-on-a-wheel-2007","title":"Butterfly on a Wheel","year":2007,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Crime","Drama","Thriller"],"overview":"A sociopathic kidnapper methodically pushes a desperate pair of parents to their absolute breaking point.","poster":"assets/movie-butterfly-on-a-wheel-2007-poster.jpg","backdrop":"assets/movie-butterfly-on-a-wheel-2007-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":13250,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":61,"rtAudienceLabel":"Upright","imdb":6.6,"imdbVotes":35409,"tmdb":6.457,"tmdbVotes":595}},{"id":"movie-careful-what-you-wish-for-2015","title":"Careful What You Wish For","year":2015,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Thriller"],"overview":"A guy gets more than he bargained for after entering into an affair with the wife of an investment banker. Soon, a suspicious death and substantial life insurance policy embroil him in a scandal.","poster":"assets/movie-careful-what-you-wish-for-2015-poster.jpg","backdrop":"assets/movie-careful-what-you-wish-for-2015-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":317744,"ratings":{"rtCritics":17,"rtCriticsLabel":"Rotten","rtAudience":61,"rtAudienceLabel":"Upright","imdb":5.6,"imdbVotes":9452,"tmdb":6.129,"tmdbVotes":446}},{"id":"movie-crime-of-passion-1956","title":"Crime of Passion","year":1956,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Crime","Thriller"],"overview":"Kathy leaves the newspaper business to marry homicide detective Bill, but is frustrated by his lack of ambition and the banality of life in the suburbs. Her drive to advance Bill's career soon takes her down a\u2026","poster":"assets/movie-crime-of-passion-1956-poster.jpg","backdrop":"assets/movie-crime-of-passion-1956-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"center_crop","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1920,"ratings":{"rtCritics":80,"rtCriticsLabel":"Fresh","rtAudience":34,"rtAudienceLabel":"Spilled","imdb":6.4,"imdbVotes":3750,"tmdb":6.1,"tmdbVotes":57}},{"id":"movie-deep-water-2022","title":"Deep Water","year":2022,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Mystery","Thriller"],"overview":"A well-to-do husband who allows his wife to have affairs in order to avoid a divorce becomes a prime suspect in the disappearance of her lovers.","poster":"assets/movie-deep-water-2022-poster.jpg","backdrop":"assets/movie-deep-water-2022-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":619979,"ratings":{"rtCritics":35,"rtCriticsLabel":"Rotten","rtAudience":25,"rtAudienceLabel":"Spilled","imdb":5.5,"imdbVotes":74098,"tmdb":5.834,"tmdbVotes":1755}},{"id":"movie-derailed-2005","title":"Derailed","year":2005,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Thriller"],"overview":"When two married business executives having an affair are blackmailed by a violent criminal, they are forced to turn the tables on him to save their families.","poster":"assets/movie-derailed-2005-poster.jpg","backdrop":"assets/movie-derailed-2005-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":8999,"ratings":{"rtCritics":20,"rtCriticsLabel":"Rotten","rtAudience":58,"rtAudienceLabel":"Spilled","imdb":6.6,"imdbVotes":79563,"tmdb":6.405,"tmdbVotes":1193}},{"id":"movie-die-my-love-2025","title":"Die My Love","year":2025,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama"],"overview":"After inheriting a remote Montana house, Jackson moves there from New York with his partner Grace, and the couple soon welcome a child. As Jackson becomes increasingly absent and rural isolation sets in, Grace\u2026","poster":"assets/movie-die-my-love-2025-poster.jpg","backdrop":"assets/movie-die-my-love-2025-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1033148,"ratings":{"rtCritics":74,"rtCriticsLabel":"Certified Fresh","rtAudience":45,"rtAudienceLabel":"Spilled","imdb":6,"imdbVotes":50664,"tmdb":6.1,"tmdbVotes":683}},{"id":"movie-dream-house-2011","title":"Dream House","year":2011,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Mystery","Drama","Thriller"],"overview":"Publisher Will Atenton quits a lucrative job in New York to relocate his wife, Libby, and their daughters to a quaint town in New England. However, as they settle into their home the Atentons discover that a woman\u2026","poster":"assets/movie-dream-house-2011-poster.jpg","backdrop":"assets/movie-dream-house-2011-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":69668,"ratings":{"rtCritics":7,"rtCriticsLabel":"Rotten","rtAudience":36,"rtAudienceLabel":"Spilled","imdb":6,"imdbVotes":71386,"tmdb":6.212,"tmdbVotes":1480}},{"id":"movie-dream-lover-1994","title":"Dream Lover","year":1994,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Mystery","Thriller"],"overview":"Not long after they cross paths at an art gallery, architect Ray Reardon and hypnotically sensual Lena are married with children. But as strange incidents occur, Ray begins to realize he may not really know the woman\u2026","poster":"assets/movie-dream-lover-1994-poster.jpg","backdrop":"assets/movie-dream-lover-1994-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":18190,"ratings":{"rtCritics":57,"rtCriticsLabel":"Rotten","rtAudience":38,"rtAudienceLabel":"Spilled","imdb":6.2,"imdbVotes":7865,"tmdb":6.844,"tmdbVotes":167}},{"id":"movie-drop-2025","title":"Drop","year":2025,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Mystery","Thriller"],"overview":"Violet, a widowed mother on her first date in years, arrives at an upscale restaurant where she is relieved that her date, Henry, is more charming and handsome than she expected. But their chemistry begins to curdle\u2026","poster":"assets/movie-drop-2025-poster.jpg","backdrop":"assets/movie-drop-2025-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1249213,"ratings":{"rtCritics":83,"rtCriticsLabel":"Certified Fresh","rtAudience":79,"rtAudienceLabel":"Upright","imdb":6.1,"imdbVotes":61018,"tmdb":6.275,"tmdbVotes":1023}},{"id":"movie-eastern-promises-2007","title":"Eastern Promises","year":2007,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Thriller","Crime","Mystery"],"overview":"A Russian teenager living in London dies during childbirth but leaves clues in her diary that could tie her child to a rape involving a violent Russian mob family.","poster":"assets/movie-eastern-promises-2007-poster.jpg","backdrop":"assets/movie-eastern-promises-2007-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":2252,"ratings":{"rtCritics":89,"rtCriticsLabel":"Certified Fresh","rtAudience":83,"rtAudienceLabel":"Upright","imdb":7.6,"imdbVotes":281015,"tmdb":7.349,"tmdbVotes":3900}},{"id":"movie-faces-1968","title":"Faces","year":1968,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama"],"overview":"Middle-aged suburban husband Richard abruptly tells his wife, Maria, that he wants a divorce. As Richard takes up with a younger woman, Maria enjoys a night on the town with her friends and meets a younger man. As\u2026","poster":"assets/movie-faces-1968-poster.jpg","backdrop":"assets/movie-faces-1968-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"center_crop","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":753,"ratings":{"rtCritics":83,"rtCriticsLabel":"Fresh","rtAudience":86,"rtAudienceLabel":"Upright","imdb":7.4,"imdbVotes":12950,"tmdb":7.093,"tmdbVotes":227}},{"id":"movie-fatale-2020","title":"Fatale","year":2020,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Thriller"],"overview":"After a wild one-night stand, successful sports agent Derrick Tyler watches his perfect life slowly disappear when he discovers the sexy and mysterious woman he risked everything for is determined police detective\u2026","poster":"assets/movie-fatale-2020-poster.jpg","backdrop":"assets/movie-fatale-2020-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":549514,"ratings":{"rtCritics":46,"rtCriticsLabel":"Rotten","rtAudience":87,"rtAudienceLabel":"Upright","imdb":5.5,"imdbVotes":16392,"tmdb":6,"tmdbVotes":401}},{"id":"tv-56-days-2026","title":"56 Days","year":2026,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Crime","Mystery"],"overview":"When an unidentified body is found in a luxury apartment linked to Oliver Kennedy and his girlfriend Ciara Wyse, Detectives Lee Reardon and Karl Connolly reconstruct the couple's deadly romance across the past 56 days.","poster":"assets/tv-56-days-2026-poster.jpg","backdrop":"assets/tv-56-days-2026-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":241372,"ratings":{"rtCritics":60,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.388,"tmdbVotes":245}},{"id":"tv-90-day-fiance-before-the-90-days-2017","title":"90 Day Fianc\u00e9: Before the 90 Days","year":2017,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Reality"],"overview":"Follow couples who have an existing relationship online, but haven't met in person. We'll experience their journey as they travel to the other's foreign country for the first time in an attempt to establish an\u2026","poster":"assets/tv-90-day-fiance-before-the-90-days-2017-poster.jpg","backdrop":"assets/tv-90-day-fiance-before-the-90-days-2017-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":73319,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.5,"tmdbVotes":45}},{"id":"tv-90-day-fiance-the-other-way-2019","title":"90 Day Fianc\u00e9: The Other Way","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Reality"],"overview":"Americans move to a foreign country all in the name of love. Will uprooting their lives in the United States pay off, or will they be packing up and moving back to America brokenhearted?","poster":"assets/tv-90-day-fiance-the-other-way-2019-poster.jpg","backdrop":"assets/tv-90-day-fiance-the-other-way-2019-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":90046,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.8,"tmdbVotes":34}},{"id":"tv-absolutely-fabulous-1992","title":"Absolutely Fabulous","year":1992,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy"],"overview":"Set in the world of fashion and PR, immature fun-loving mother Edina Monsoon and her best friend Patsy drive Eddie's sensible daughter, Saffron, up the wall with their constant drug abuse and outrageous selfishness.\u2026","poster":"assets/tv-absolutely-fabulous-1992-poster.jpg","backdrop":"assets/tv-absolutely-fabulous-1992-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":4493,"ratings":{"rtCritics":96,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.6,"tmdbVotes":198}},{"id":"tv-the-afterparty-2022","title":"The Afterparty","year":2022,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Mystery","Comedy","Crime"],"overview":"Nothing is as it seems in this hilarious murder mystery where each suspect's story is told through a different film genre.","poster":"assets/tv-the-afterparty-2022-poster.jpg","backdrop":"assets/tv-the-afterparty-2022-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":106454,"ratings":{"rtCritics":92,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.071,"tmdbVotes":245}},{"id":"tv-agatha-christie-s-marple-2004","title":"Agatha Christie's Marple","year":2004,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Crime","Mystery"],"overview":"The adventures of Miss Jane Marple, an elderly spinster living in the quiet little village of St Mary Mead. During her many visits to friends and relatives in other villages, Miss Marple often stumbles upon\u2026","poster":"assets/tv-agatha-christie-s-marple-2004-poster.jpg","backdrop":"assets/tv-agatha-christie-s-marple-2004-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":6127,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.9,"tmdbVotes":152}},{"id":"tv-all-american-homecoming-2022","title":"All American: Homecoming","year":2022,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama"],"overview":"Follow the journeys of Simone Hicks, a tennis hopeful from Beverly Hills, and elite baseball player Damon Sims from Chicago, as they navigate life at the prestigious HBCU Bringston University.","poster":"assets/tv-all-american-homecoming-2022-poster.jpg","backdrop":"assets/tv-all-american-homecoming-2022-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":153723,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.3,"tmdbVotes":70}},{"id":"tv-and-just-like-that-2021","title":"And Just Like That\u2026","year":2021,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy","Drama"],"overview":"This new chapter of \u201cSex and the City\u201d follows Carrie, Miranda and Charlotte as they navigate the journey from the complicated reality of life and friendship in their 30s to the even more complicated reality of life\u2026","poster":"assets/tv-and-just-like-that-2021-poster.jpg","backdrop":"assets/tv-and-just-like-that-2021-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":116450,"ratings":{"rtCritics":52,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.211,"tmdbVotes":556}},{"id":"tv-anne-with-an-e-2017","title":"Anne with an E","year":2017,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Family"],"overview":"A coming-of-age story about an outsider who, against all odds and numerous challenges, fights for love and acceptance and for her place in the world. The series centers on a young orphaned girl in the late 1890s,\u2026","poster":"assets/tv-anne-with-an-e-2017-poster.jpg","backdrop":"assets/tv-anne-with-an-e-2017-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":70785,"ratings":{"rtCritics":63,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.7,"tmdbVotes":5019}},{"id":"tv-awkward-2011","title":"Awkward.","year":2011,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy","Drama"],"overview":"An irreverent look at the conflict, chaos and humor that defines teenage life through the eyes of 15-year-old Jenna Hamilton whose life begins to change when a simple accident becomes an epic misunderstanding and is\u2026","poster":"assets/tv-awkward-2011-poster.jpg","backdrop":"assets/tv-awkward-2011-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":39859,"ratings":{"rtCritics":78,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.4,"tmdbVotes":427}},{"id":"tv-the-baby-sitters-club-2020","title":"The Baby-Sitters Club","year":2020,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Kids","Drama"],"overview":"In this contemporary take on the beloved book series, five best friends launch a baby-sitting business that's big on fun and adventure.","poster":"assets/tv-the-baby-sitters-club-2020-poster.jpg","backdrop":"assets/tv-the-baby-sitters-club-2020-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":100412,"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.9,"tmdbVotes":506}},{"id":"tv-ballers-2015","title":"Ballers","year":2015,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Comedy"],"overview":"Looking at the lives of former and current football players, the show follows former superstar Spencer Strasmore as he gets his life on track in retirement while mentoring other current and former players through the\u2026","poster":"assets/tv-ballers-2015-poster.jpg","backdrop":"assets/tv-ballers-2015-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":62704,"ratings":{"rtCritics":72,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.809,"tmdbVotes":820}},{"id":"tv-baretta-1975","title":"Baretta","year":1975,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Crime","Drama","Mystery"],"overview":"Baretta is an American detective television series which ran on ABC from 1975 to 1978. The show was a milder version of a successful 1973\u201374 ABC series, Toma, starring Tony Musante as chameleon-like, real-life New\u2026","poster":"assets/tv-baretta-1975-poster.jpg","backdrop":"assets/tv-baretta-1975-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":3216,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.5,"tmdbVotes":43}},{"id":"tv-based-on-a-true-story-2023","title":"Based on a True Story","year":2023,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy","Drama"],"overview":"The lives of a realtor, a plumber and a former tennis star unexpectedly collide, exposing America\u2019s obsession with true crime, murder and the slow-close toilet seat.","poster":"assets/tv-based-on-a-true-story-2023-poster.jpg","backdrop":"assets/tv-based-on-a-true-story-2023-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":197373,"ratings":{"rtCritics":79,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7,"tmdbVotes":160}},{"id":"tv-the-beast-in-me-2025","title":"The Beast in Me","year":2025,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Mystery"],"overview":"A famous author is pulled into a twisted mind game with her rich, powerful new neighbor \u2014 who might be a murderer.","poster":"assets/tv-the-beast-in-me-2025-poster.jpg","backdrop":"assets/tv-the-beast-in-me-2025-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":250504,"ratings":{"rtCritics":85,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.072,"tmdbVotes":334}},{"id":"tv-big-city-greens-2018","title":"Big City Greens","year":2018,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Family","Animation","Comedy"],"overview":"The offbeat adventures of 10-year-old Cricket Green, a mischievous and optimistic country boy who moves to the big city with his wildly out of place family \u2013 older sister Tilly, father Bill and Gramma Alice.","poster":"assets/tv-big-city-greens-2018-poster.jpg","backdrop":"assets/tv-big-city-greens-2018-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":80587,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.555,"tmdbVotes":82}},{"id":"tv-the-bold-type-2017","title":"The Bold Type","year":2017,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Comedy"],"overview":"A glimpse into the outrageous lives of Jane, Kat and Sutton, who are working at the nation's top women's magazine, Scarlet, while navigating their careers, identities and individual voices.","poster":"assets/tv-the-bold-type-2017-poster.jpg","backdrop":"assets/tv-the-bold-type-2017-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":69630,"ratings":{"rtCritics":89,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.7,"tmdbVotes":204}},{"id":"tv-brassic-2019","title":"Brassic","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy","Drama","Crime"],"overview":"A group of working-class friends finding unconventional ways to win at life in suburban northern England. These lads have dealt, scammed, bribed and conned their way through adolescence, but now, their dealing and\u2026","poster":"assets/tv-brassic-2019-poster.jpg","backdrop":"assets/tv-brassic-2019-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":92621,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.336,"tmdbVotes":263}}]},{"key":"shared","movies":[{"id":"movie-american-gangster-2007","title":"American Gangster","year":2007,"type":"movie","runtimeSeconds":10546,"seasonCount":null,"communityRating":7.595,"criticRating":81,"genres":["Drama","Crime"],"overview":"Loosely based on the criminal career of Frank Lucas, a gangster from La Grange, North Carolina, who smuggled heroin into the United States on American service planes returning from the Vietnam War, before being\u2026","poster":"assets/movie-american-gangster-2007-poster.jpg","backdrop":"assets/movie-american-gangster-2007-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-08-23T10:22:36.0000000Z","lastPlayedAt":"2026-08-30T21:05:39.7952451Z","availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":4982,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":81,"rtCriticsLabel":"Certified Fresh","rtAudience":90,"rtAudienceLabel":"Upright","imdb":7.8,"imdbVotes":495656,"tmdb":7.599,"tmdbVotes":6350}},{"id":"movie-annie-hall-1977","title":"Annie Hall","year":1977,"type":"movie","runtimeSeconds":5604,"seasonCount":null,"communityRating":7.712,"criticRating":97,"genres":["Comedy","Drama","Romance"],"overview":"New York comedian Alvy Singer falls in love with the ditsy Annie Hall.","poster":"assets/movie-annie-hall-1977-poster.jpg","backdrop":"assets/movie-annie-hall-1977-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:24:23.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":703,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":97,"rtCriticsLabel":"Certified Fresh","rtAudience":92,"rtAudienceLabel":"Upright","imdb":7.9,"imdbVotes":293349,"tmdb":7.71,"tmdbVotes":4391}},{"id":"movie-apocalypse-now-1979","title":"Apocalypse Now","year":1979,"type":"movie","runtimeSeconds":8835,"seasonCount":null,"communityRating":8.261,"criticRating":91,"genres":["Drama","War"],"overview":"At the height of the Vietnam war, Captain Benjamin Willard is sent on a dangerous mission that, officially, \"does not exist, nor will it ever exist.\" His goal is to locate - and eliminate - a mysterious Green Beret\u2026","poster":"assets/movie-apocalypse-now-1979-poster.jpg","backdrop":"assets/movie-apocalypse-now-1979-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:22:25.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":28,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":91,"rtCriticsLabel":"Certified Fresh","rtAudience":94,"rtAudienceLabel":"Upright","imdb":8.4,"imdbVotes":781424,"tmdb":8.3,"tmdbVotes":9526}},{"id":"movie-arrival-2016","title":"Arrival","year":2016,"type":"movie","runtimeSeconds":6967,"seasonCount":null,"communityRating":7.636,"criticRating":94,"genres":["Drama","Science Fiction","Mystery"],"overview":"Taking place after alien crafts land around the world, an expert linguist is recruited by the military to determine whether they come in peace or are a threat.","poster":"assets/movie-arrival-2016-poster.jpg","backdrop":"assets/movie-arrival-2016-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-14T19:54:12.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":329865,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":94,"rtCriticsLabel":"Certified Fresh","rtAudience":83,"rtAudienceLabel":"Upright","imdb":7.9,"imdbVotes":883621,"tmdb":7.638,"tmdbVotes":20125}},{"id":"movie-avatar-aang-the-last-airbender-2026","title":"Avatar Aang: The Last Airbender","year":2026,"type":"movie","runtimeSeconds":5930,"seasonCount":null,"communityRating":9.147,"criticRating":90,"genres":["Animation","Adventure","Fantasy"],"overview":"Avatar Aang, the world's last Airbender, learns of an ancient power that could save his culture from extinction. With the help of his friends, he embarks on a global quest to find it before it falls into the wrong\u2026","poster":"assets/movie-avatar-aang-the-last-airbender-2026-poster.jpg","backdrop":"assets/movie-avatar-aang-the-last-airbender-2026-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-25T09:53:09.0000000Z","lastPlayedAt":"2026-08-02T19:22:33.6155383Z","availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":980431,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":90,"rtCriticsLabel":"Certified Fresh","rtAudience":99,"rtAudienceLabel":"Upright","imdb":7.7,"imdbVotes":30792,"tmdb":9,"tmdbVotes":1417}},{"id":"movie-bohemian-rhapsody-2018","title":"Bohemian Rhapsody","year":2018,"type":"movie","runtimeSeconds":8077,"seasonCount":null,"communityRating":7.95,"criticRating":60,"genres":["Music","Drama"],"overview":"Singer Freddie Mercury, guitarist Brian May, drummer Roger Taylor and bass guitarist John Deacon take the music world by storm when they form the rock 'n' roll band Queen in 1970. Hit songs become instant classics.\u2026","poster":"assets/movie-bohemian-rhapsody-2018-poster.jpg","backdrop":"assets/movie-bohemian-rhapsody-2018-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:28:20.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":424694,"artwork":{"posterKind":"center_crop","backdropKind":"backdrop"},"ratings":{"rtCritics":60,"rtCriticsLabel":"Fresh","rtAudience":85,"rtAudienceLabel":"Upright","imdb":7.9,"imdbVotes":655894,"tmdb":7.947,"tmdbVotes":18196}},{"id":"movie-the-boy-and-the-heron-2023","title":"The Boy and the Heron","year":2023,"type":"movie","runtimeSeconds":7437,"seasonCount":null,"communityRating":7.4,"criticRating":96,"genres":["Animation","Fantasy","Drama"],"overview":"While the Second World War rages, the teenage Mahito, haunted by his mother's tragic death, is relocated from Tokyo to the serene rural home of his new stepmother Natsuko, a woman who bears a striking resemblance to\u2026","poster":"assets/movie-the-boy-and-the-heron-2023-poster.jpg","backdrop":"assets/movie-the-boy-and-the-heron-2023-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:25:15.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":508883,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":96,"rtCriticsLabel":"Certified Fresh","rtAudience":88,"rtAudienceLabel":"Upright","imdb":7.3,"imdbVotes":152169,"tmdb":7.387,"tmdbVotes":2893}},{"id":"movie-braveheart-1995","title":"Braveheart","year":1995,"type":"movie","runtimeSeconds":10665,"seasonCount":null,"communityRating":7.945,"criticRating":74,"genres":["Drama","History","War"],"overview":"Enraged at the slaughter of Murron, his new bride and childhood love, Scottish warrior William Wallace slays a platoon of the local English lord's soldiers. This leads the village to revolt and, eventually, the\u2026","poster":"assets/movie-braveheart-1995-poster.jpg","backdrop":"assets/movie-braveheart-1995-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-10T21:24:28.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":197,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":74,"rtCriticsLabel":"Certified Fresh","rtAudience":85,"rtAudienceLabel":"Upright","imdb":8.3,"imdbVotes":1174990,"tmdb":7.947,"tmdbVotes":11584}},{"id":"movie-the-breakfast-club-1985","title":"The Breakfast Club","year":1985,"type":"movie","runtimeSeconds":5833,"seasonCount":null,"communityRating":7.7,"criticRating":87,"genres":["Comedy","Drama"],"overview":"Five high school students from different walks of life endure a Saturday detention under a power-hungry principal. The disparate group includes rebel John, princess Claire, outcast Allison, brainy Brian and Andrew,\u2026","poster":"assets/movie-the-breakfast-club-1985-poster.jpg","backdrop":"assets/movie-the-breakfast-club-1985-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:25:03.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":2108,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":87,"rtCriticsLabel":"Certified Fresh","rtAudience":92,"rtAudienceLabel":"Upright","imdb":7.8,"imdbVotes":478743,"tmdb":7.713,"tmdbVotes":8815}},{"id":"movie-castle-in-the-sky-1986","title":"Castle in the Sky","year":1986,"type":"movie","runtimeSeconds":7474,"seasonCount":null,"communityRating":8,"criticRating":97,"genres":["Adventure","Fantasy","Animation"],"overview":"A young boy and a girl with a magic crystal must race against pirates and foreign agents in a search for a legendary floating castle.","poster":"assets/movie-castle-in-the-sky-1986-poster.jpg","backdrop":"assets/movie-castle-in-the-sky-1986-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:23:09.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":10515,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":96,"rtCriticsLabel":"Fresh","rtAudience":91,"rtAudienceLabel":"Upright","imdb":8,"imdbVotes":201545,"tmdb":7.972,"tmdbVotes":4868}},{"id":"movie-citizen-kane-1941","title":"Citizen Kane","year":1941,"type":"movie","runtimeSeconds":7173,"seasonCount":null,"communityRating":7.966,"criticRating":99,"genres":["Mystery","Drama"],"overview":"Newspaper magnate Charles Foster Kane is taken from his mother as a boy and made the ward of a rich industrialist. As a result, every well-meaning, tyrannical or self-destructive move he makes for the rest of his\u2026","poster":"assets/movie-citizen-kane-1941-poster.jpg","backdrop":"assets/movie-citizen-kane-1941-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:22:16.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":15,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":99,"rtCriticsLabel":"Certified Fresh","rtAudience":98,"rtAudienceLabel":"Upright","imdb":8.2,"imdbVotes":498321,"tmdb":7.962,"tmdbVotes":6324}},{"id":"movie-conclave-2024","title":"Conclave","year":2024,"type":"movie","runtimeSeconds":7230,"seasonCount":null,"communityRating":7.19,"criticRating":93,"genres":["Drama","Thriller"],"overview":"After the unexpected death of the Pope, Cardinal Lawrence is tasked with managing the covert and ancient ritual of electing a new one. Sequestered in the Vatican with the Catholic Church\u2019s most powerful leaders until\u2026","poster":"assets/movie-conclave-2024-poster.jpg","backdrop":"assets/movie-conclave-2024-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:30:41.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":974576,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":93,"rtCriticsLabel":"Certified Fresh","rtAudience":86,"rtAudienceLabel":"Upright","imdb":7.4,"imdbVotes":290498,"tmdb":7.19,"tmdbVotes":3744}},{"id":"movie-the-dry-2021","title":"The Dry","year":2021,"type":"movie","runtimeSeconds":7037,"seasonCount":null,"communityRating":6.779,"criticRating":null,"genres":["Crime","Thriller","Mystery"],"overview":"Aaron Falk returns to his drought-stricken hometown to attend a tragic funeral. But his return opens a decades-old wound - the unsolved death of a teenage girl.","poster":"assets/movie-the-dry-2021-poster.jpg","backdrop":"assets/movie-the-dry-2021-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:29:20.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":567797,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":90,"rtCriticsLabel":"Certified Fresh","rtAudience":89,"rtAudienceLabel":"Upright","imdb":6.8,"imdbVotes":41935,"tmdb":6.8,"tmdbVotes":892}},{"id":"movie-easy-a-2010","title":"Easy A","year":2010,"type":"movie","runtimeSeconds":5545,"seasonCount":null,"communityRating":6.8,"criticRating":85,"genres":["Comedy"],"overview":"Olive, an average high school student, sees her below-the-radar existence turn around overnight once she decides to use the school's gossip grapevine to advance her social standing. Now her classmates are turning\u2026","poster":"assets/movie-easy-a-2010-poster.jpg","backdrop":"assets/movie-easy-a-2010-backdrop.jpg","played":true,"playCount":1,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-17T19:59:04.0000000Z","lastPlayedAt":"2026-10-17T20:02:51.1083337Z","availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":37735,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":85,"rtCriticsLabel":"Certified Fresh","rtAudience":77,"rtAudienceLabel":"Upright","imdb":7,"imdbVotes":448780,"tmdb":6.8,"tmdbVotes":7619}},{"id":"movie-el-camino-a-breaking-bad-movie-2019","title":"El Camino: A Breaking Bad Movie","year":2019,"type":"movie","runtimeSeconds":7362,"seasonCount":null,"communityRating":7.055,"criticRating":92,"genres":["Crime","Drama","Thriller"],"overview":"In the wake of his dramatic escape from captivity, Jesse Pinkman must come to terms with his past in order to forge some kind of future.","poster":"assets/movie-el-camino-a-breaking-bad-movie-2019-poster.jpg","backdrop":"assets/movie-el-camino-a-breaking-bad-movie-2019-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-21T23:31:11.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":559969,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":92,"rtCriticsLabel":"Certified Fresh","rtAudience":81,"rtAudienceLabel":"Upright","imdb":7.3,"imdbVotes":354488,"tmdb":7.056,"tmdbVotes":5950}},{"id":"movie-emancipation-2022","title":"Emancipation","year":2022,"type":"movie","runtimeSeconds":7949,"seasonCount":null,"communityRating":7.7,"criticRating":45,"genres":["Drama","War","History"],"overview":"Inspired by the gripping true story of a man who would do anything for his family\u2014and for freedom. When Peter, an enslaved man, risks his life to escape and return to his family, he embarks on a perilous journey of\u2026","poster":"assets/movie-emancipation-2022-poster.jpg","backdrop":"assets/movie-emancipation-2022-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-10T20:37:34.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":715931,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":45,"rtCriticsLabel":"Rotten","rtAudience":58,"rtAudienceLabel":"Spilled","imdb":6.3,"imdbVotes":32079,"tmdb":7.744,"tmdbVotes":1319}},{"id":"movie-fighting-with-my-family-2019","title":"Fighting with My Family","year":2019,"type":"movie","runtimeSeconds":6509,"seasonCount":null,"communityRating":6.84,"criticRating":93,"genres":["Comedy"],"overview":"Born into a tight-knit wrestling family, Paige and her brother Zak are ecstatic when they get the once-in-a-lifetime opportunity to try out for the WWE. But when only Paige earns a spot in the competitive training\u2026","poster":"assets/movie-fighting-with-my-family-2019-poster.jpg","backdrop":"assets/movie-fighting-with-my-family-2019-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-22T22:10:59.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":445629,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":93,"rtCriticsLabel":"Certified Fresh","rtAudience":86,"rtAudienceLabel":"Upright","imdb":7,"imdbVotes":94576,"tmdb":6.837,"tmdbVotes":1952}},{"id":"movie-force-of-nature-the-dry-2-2024","title":"Force of Nature: The Dry 2","year":2024,"type":"movie","runtimeSeconds":6753,"seasonCount":null,"communityRating":6.3,"criticRating":66,"genres":["Mystery","Thriller"],"overview":"When five women take part in a corporate hiking retreat and only four come out on the other side, Federal Agents Aaron Falk and Carmen Cooper head deep into the Victorian mountain ranges to investigate in the hopes\u2026","poster":"assets/movie-force-of-nature-the-dry-2-2024-poster.jpg","backdrop":"assets/movie-force-of-nature-the-dry-2-2024-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:29:49.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":832262,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":66,"rtCriticsLabel":"Fresh","rtAudience":43,"rtAudienceLabel":"Spilled","imdb":5.9,"imdbVotes":10343,"tmdb":6.269,"tmdbVotes":305}},{"id":"movie-free-state-of-jones-2016","title":"Free State of Jones","year":2016,"type":"movie","runtimeSeconds":8376,"seasonCount":null,"communityRating":6.79,"criticRating":48,"genres":["Action","Drama","History"],"overview":"In 1863, Mississippi farmer Newt Knight serves as a medic for the Confederate Army. Opposed to slavery, Knight would rather help the wounded than fight the Union. After his nephew dies in battle, Newt returns home to\u2026","poster":"assets/movie-free-state-of-jones-2016-poster.jpg","backdrop":"assets/movie-free-state-of-jones-2016-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-11T17:56:53.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":316152,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":48,"rtCriticsLabel":"Rotten","rtAudience":64,"rtAudienceLabel":"Upright","imdb":6.9,"imdbVotes":68931,"tmdb":6.788,"tmdbVotes":1730}},{"id":"movie-from-up-on-poppy-hill-2011","title":"From Up on Poppy Hill","year":2011,"type":"movie","runtimeSeconds":5482,"seasonCount":null,"communityRating":7.5,"criticRating":87,"genres":["Animation","Drama"],"overview":"Yokohama, 1963. Japan is picking itself up from the devastation of World War II and preparing to host the 1964 Olympics\u2014and the mood is one of both optimism and conflict as the young generation struggles to throw off\u2026","poster":"assets/movie-from-up-on-poppy-hill-2011-poster.jpg","backdrop":"assets/movie-from-up-on-poppy-hill-2011-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-07T14:41:03.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":83389,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":87,"rtCriticsLabel":"Certified Fresh","rtAudience":80,"rtAudienceLabel":"Upright","imdb":7.4,"imdbVotes":60769,"tmdb":7.509,"tmdbVotes":2026}},{"id":"movie-ghost-in-the-shell-1995","title":"Ghost in the Shell","year":1995,"type":"movie","runtimeSeconds":4959,"seasonCount":null,"communityRating":7.929,"criticRating":95,"genres":["Action","Animation","Science Fiction"],"overview":"In the year 2029, the barriers of our world have been broken down by the net and by cybernetics, but this brings new vulnerability to humans in the form of brain-hacking. When a highly-wanted hacker known as 'The\u2026","poster":"assets/movie-ghost-in-the-shell-1995-poster.jpg","backdrop":"assets/movie-ghost-in-the-shell-1995-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:22:57.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":9323,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":97,"rtCriticsLabel":"Certified Fresh","rtAudience":90,"rtAudienceLabel":"Upright","imdb":7.9,"imdbVotes":178061,"tmdb":7.928,"tmdbVotes":4130}},{"id":"movie-ghost-in-the-shell-2-innocence-2004","title":"Ghost in the Shell 2: Innocence","year":2004,"type":"movie","runtimeSeconds":5950,"seasonCount":null,"communityRating":7.352,"criticRating":65,"genres":["Animation","Drama","Science Fiction"],"overview":"Cyborg detective Batou is assigned to investigate a series of murders committed by gynoids\u2014doll-like cyborgs, which all malfunctioned, killed, then self-destructed afterwards. The brains of the gynoids initialize in\u2026","poster":"assets/movie-ghost-in-the-shell-2-innocence-2004-poster.jpg","backdrop":"assets/movie-ghost-in-the-shell-2-innocence-2004-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:23:38.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":12140,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":65,"rtCriticsLabel":"Fresh","rtAudience":80,"rtAudienceLabel":"Upright","imdb":7.4,"imdbVotes":43280,"tmdb":7.356,"tmdbVotes":1049}},{"id":"movie-the-godfather-1972","title":"The Godfather","year":1972,"type":"movie","runtimeSeconds":10603,"seasonCount":null,"communityRating":8.687,"criticRating":97,"genres":["Drama","Crime"],"overview":"Spanning the years 1945 to 1955, a chronicle of the fictional Italian-American Corleone crime family. When organized crime family patriarch, Vito Corleone barely survives an attempt on his life, his youngest son,\u2026","poster":"assets/movie-the-godfather-1972-poster.jpg","backdrop":"assets/movie-the-godfather-1972-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:24:12.0000000Z","lastPlayedAt":"2026-09-18T19:24:44.9855867Z","availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":238,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":97,"rtCriticsLabel":"Certified Fresh","rtAudience":98,"rtAudienceLabel":"Upright","imdb":9.2,"imdbVotes":2262024,"tmdb":8.688,"tmdbVotes":23907}},{"id":"movie-the-godfather-part-ii-1974","title":"The Godfather Part II","year":1974,"type":"movie","runtimeSeconds":12031,"seasonCount":null,"communityRating":8.573,"criticRating":96,"genres":["Drama","Crime"],"overview":"In the continuing saga of the Corleone crime family, a young Vito Corleone grows up in Sicily and in 1910s New York. In the 1950s, Michael Corleone attempts to expand the family business into Las Vegas, Hollywood and\u2026","poster":"assets/movie-the-godfather-part-ii-1974-poster.jpg","backdrop":"assets/movie-the-godfather-part-ii-1974-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:24:18.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":240,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":96,"rtCriticsLabel":"Certified Fresh","rtAudience":97,"rtAudienceLabel":"Upright","imdb":9,"imdbVotes":1521308,"tmdb":8.571,"tmdbVotes":14559}},{"id":"movie-the-godfather-part-iii-1990","title":"The Godfather Part III","year":1990,"type":"movie","runtimeSeconds":9476,"seasonCount":null,"communityRating":7.416,"criticRating":67,"genres":["Crime","Drama","Thriller"],"overview":"In the midst of trying to legitimize his business dealings in 1979 New York and Italy, aging mafia don, Michael Corleone seeks forgiveness for his sins while taking a young protege under his wing.","poster":"assets/movie-the-godfather-part-iii-1990-poster.jpg","backdrop":"assets/movie-the-godfather-part-iii-1990-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:26:29.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":242,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":68,"rtCriticsLabel":"Fresh","rtAudience":68,"rtAudienceLabel":"Upright","imdb":7.5,"imdbVotes":462448,"tmdb":7.413,"tmdbVotes":7159}},{"id":"movie-gosford-park-2001","title":"Gosford Park","year":2001,"type":"movie","runtimeSeconds":8247,"seasonCount":null,"communityRating":6.815,"criticRating":87,"genres":["Drama","Mystery","Thriller"],"overview":"In 1930s England, a group of pretentious rich and famous gather together for a weekend of relaxation at a hunting resort. But when a murder occurs, each one of these interesting characters becomes a suspect.","poster":"assets/movie-gosford-park-2001-poster.jpg","backdrop":"assets/movie-gosford-park-2001-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:25:49.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":5279,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":87,"rtCriticsLabel":"Certified Fresh","rtAudience":78,"rtAudienceLabel":"Upright","imdb":7.2,"imdbVotes":103883,"tmdb":6.822,"tmdbVotes":1317}},{"id":"movie-grave-of-the-fireflies-1988","title":"Grave of the Fireflies","year":1988,"type":"movie","runtimeSeconds":5313,"seasonCount":null,"communityRating":8.45,"criticRating":100,"genres":["Animation","Drama","War"],"overview":"In the final months of World War II, 14-year-old Seita and his sister Setsuko are orphaned when their mother is killed during an air raid in Kobe, Japan. After a falling out with their aunt, they move into an\u2026","poster":"assets/movie-grave-of-the-fireflies-1988-poster.jpg","backdrop":"assets/movie-grave-of-the-fireflies-1988-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:24:14.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":12477,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Certified Fresh","rtAudience":95,"rtAudienceLabel":"Upright","imdb":8.5,"imdbVotes":399802,"tmdb":8.45,"tmdbVotes":6938}},{"id":"movie-the-great-gatsby-2013","title":"The Great Gatsby","year":2013,"type":"movie","runtimeSeconds":8525,"seasonCount":null,"communityRating":7.346,"criticRating":49,"genres":["Drama","Romance"],"overview":"Nick Carraway arrives in New York in 1922, an era of loose morals, glittering jazz and bootleg kings. Chasing his own American Dream, Nick encounters the mysterious millionaire Gatsby and his bewitching cousin Daisy.\u2026","poster":"assets/movie-the-great-gatsby-2013-poster.jpg","backdrop":"assets/movie-the-great-gatsby-2013-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:26:50.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":64682,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":48,"rtCriticsLabel":"Rotten","rtAudience":67,"rtAudienceLabel":"Upright","imdb":7.2,"imdbVotes":651882,"tmdb":7.346,"tmdbVotes":13290}},{"id":"movie-the-hours-2002","title":"The Hours","year":2002,"type":"movie","runtimeSeconds":6887,"seasonCount":null,"communityRating":7.25,"criticRating":79,"genres":["Drama"],"overview":"The story of three women searching for more potent, meaningful lives. Each is alive at a different time and place, all are linked by their yearnings and their fears. Their stories intertwine, and finally come\u2026","poster":"assets/movie-the-hours-2002-poster.jpg","backdrop":"assets/movie-the-hours-2002-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:23:27.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":590,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":79,"rtCriticsLabel":"Certified Fresh","rtAudience":84,"rtAudienceLabel":"Upright","imdb":7.5,"imdbVotes":148367,"tmdb":7.249,"tmdbVotes":1931}},{"id":"movie-howl-s-moving-castle-2004","title":"Howl's Moving Castle","year":2004,"type":"movie","runtimeSeconds":7149,"seasonCount":null,"communityRating":8.4,"criticRating":88,"genres":["Fantasy","Animation","Adventure"],"overview":"Sophie, a young milliner, is turned into an elderly woman by a witch who enters her shop and curses her. She encounters a wizard named Howl and gets caught up in his resistance to fighting for the king.","poster":"assets/movie-howl-s-moving-castle-2004-poster.jpg","backdrop":"assets/movie-howl-s-moving-castle-2004-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:22:47.0000000Z","lastPlayedAt":"2026-05-21T18:46:08.0000000Z","availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":4935,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":87,"rtCriticsLabel":"Certified Fresh","rtAudience":93,"rtAudienceLabel":"Upright","imdb":8.2,"imdbVotes":524520,"tmdb":8.391,"tmdbVotes":11642}},{"id":"movie-in-the-heights-2021","title":"In the Heights","year":2021,"type":"movie","runtimeSeconds":8579,"seasonCount":null,"communityRating":7.111,"criticRating":null,"genres":["Drama","Romance"],"overview":"The story of Usnavi, a bodega owner who has mixed feelings about closing his store and retiring to the Dominican Republic or staying in Washington Heights.","poster":"assets/movie-in-the-heights-2021-poster.jpg","backdrop":"assets/movie-in-the-heights-2021-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:29:11.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":467909,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":94,"rtCriticsLabel":"Certified Fresh","rtAudience":94,"rtAudienceLabel":"Upright","imdb":7.2,"imdbVotes":56513,"tmdb":7.104,"tmdbVotes":826}},{"id":"movie-jennifer-s-body-2009","title":"Jennifer's Body","year":2009,"type":"movie","runtimeSeconds":6450,"seasonCount":null,"communityRating":6.012,"criticRating":47,"genres":["Horror","Comedy"],"overview":"Jennifer, a gorgeous, seductive cheerleader takes evil to a whole new level after she's possessed by a sinister demon. Now it's up to her best friend to stop Jennifer's reign of terror before it's too late.","poster":"assets/movie-jennifer-s-body-2009-poster.jpg","backdrop":"assets/movie-jennifer-s-body-2009-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-30T03:37:04.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":19994,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":47,"rtCriticsLabel":"Rotten","rtAudience":36,"rtAudienceLabel":"Spilled","imdb":5.6,"imdbVotes":179710,"tmdb":6.013,"tmdbVotes":4481}},{"id":"movie-kiki-s-delivery-service-1989","title":"Kiki's Delivery Service","year":1989,"type":"movie","runtimeSeconds":6183,"seasonCount":null,"communityRating":7.839,"criticRating":null,"genres":["Animation","Family","Fantasy"],"overview":"A young witch, on her mandatory year of independent life, finds fitting into a new community difficult while she supports herself by running an air courier service.","poster":"assets/movie-kiki-s-delivery-service-1989-poster.jpg","backdrop":"assets/movie-kiki-s-delivery-service-1989-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:24:20.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":16859,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":98,"rtCriticsLabel":"Certified Fresh","rtAudience":89,"rtAudienceLabel":"Upright","imdb":7.8,"imdbVotes":192477,"tmdb":7.839,"tmdbVotes":4811}},{"id":"movie-the-last-of-the-mohicans-1992","title":"The Last of the Mohicans","year":1992,"type":"movie","runtimeSeconds":6874,"seasonCount":null,"communityRating":7.388,"criticRating":88,"genres":["History","War","Drama"],"overview":"In war-torn colonial America, in the midst of a bloody battle between British, the French and Native American allies, the aristocratic daughter of a British Colonel and her party are captured by a group of Huron\u2026","poster":"assets/movie-the-last-of-the-mohicans-1992-poster.jpg","backdrop":"assets/movie-the-last-of-the-mohicans-1992-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-10T20:59:22.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":9361,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":88,"rtCriticsLabel":"Certified Fresh","rtAudience":88,"rtAudienceLabel":"Upright","imdb":7.6,"imdbVotes":210791,"tmdb":7.39,"tmdbVotes":3593}},{"id":"movie-the-last-samurai-2003","title":"The Last Samurai","year":2003,"type":"movie","runtimeSeconds":9251,"seasonCount":null,"communityRating":7.61,"criticRating":65,"genres":["Drama","Action","War"],"overview":"Nathan Algren is an American hired to instruct the Japanese army in the ways of modern warfare, which finds him learning to respect the samurai and the honorable principles that rule them. Pressed to destroy the\u2026","poster":"assets/movie-the-last-samurai-2003-poster.jpg","backdrop":"assets/movie-the-last-samurai-2003-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-26T05:25:10.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":616,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":66,"rtCriticsLabel":"Fresh","rtAudience":83,"rtAudienceLabel":"Upright","imdb":7.8,"imdbVotes":512982,"tmdb":7.614,"tmdbVotes":7887}},{"id":"movie-lemony-snicket-s-a-series-of-unfortunate-events-2004","title":"Lemony Snicket's A Series of Unfortunate Events","year":2004,"type":"movie","runtimeSeconds":6479,"seasonCount":null,"communityRating":6.8,"criticRating":72,"genres":["Adventure","Comedy","Family"],"overview":"Three wealthy children's parents are killed in a fire. When they are sent to a distant relative, they find out that he is plotting to kill them and seize their fortune.","poster":"assets/movie-lemony-snicket-s-a-series-of-unfortunate-events-2004-poster.jpg","backdrop":"assets/movie-lemony-snicket-s-a-series-of-unfortunate-events-2004-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:26:09.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":11774,"artwork":{"posterKind":"center_crop","backdropKind":"backdrop"},"ratings":{"rtCritics":72,"rtCriticsLabel":"Fresh","rtAudience":63,"rtAudienceLabel":"Upright","imdb":6.8,"imdbVotes":233636,"tmdb":6.82,"tmdbVotes":5447}},{"id":"movie-the-lighthouse-2019","title":"The Lighthouse","year":2019,"type":"movie","runtimeSeconds":6549,"seasonCount":null,"communityRating":7.463,"criticRating":90,"genres":["Drama","Fantasy","Thriller"],"overview":"Two lighthouse keepers try to maintain their sanity while living on a remote and mysterious New England island in the 1890s.","poster":"assets/movie-the-lighthouse-2019-poster.jpg","backdrop":"assets/movie-the-lighthouse-2019-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:29:01.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":503919,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":90,"rtCriticsLabel":"Certified Fresh","rtAudience":72,"rtAudienceLabel":"Upright","imdb":7.3,"imdbVotes":312344,"tmdb":7.46,"tmdbVotes":5895}},{"id":"movie-locke-2014","title":"Locke","year":2014,"type":"movie","runtimeSeconds":5090,"seasonCount":null,"communityRating":6.888,"criticRating":91,"genres":["Drama","Thriller"],"overview":"Ivan Locke has worked hard to craft a good life for himself. Tonight, that life will collapse around him. On the eve of the biggest challenge of his career, Ivan receives a phone call that sets in motion a series of\u2026","poster":"assets/movie-locke-2014-poster.jpg","backdrop":"assets/movie-locke-2014-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T17:38:48.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":210479,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":90,"rtCriticsLabel":"Certified Fresh","rtAudience":72,"rtAudienceLabel":"Upright","imdb":7.1,"imdbVotes":171265,"tmdb":6.889,"tmdbVotes":3088}},{"id":"movie-the-matrix-1999","title":"The Matrix","year":1999,"type":"movie","runtimeSeconds":8179,"seasonCount":null,"communityRating":8.259,"criticRating":83,"genres":["Action","Science Fiction"],"overview":"Set in the 22nd century, The Matrix tells the story of a computer hacker who joins a group of underground insurgents fighting the vast and powerful computers who now rule the earth.","poster":"assets/movie-the-matrix-1999-poster.jpg","backdrop":"assets/movie-the-matrix-1999-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:18:12.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":603,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":83,"rtCriticsLabel":"Certified Fresh","rtAudience":85,"rtAudienceLabel":"Upright","imdb":8.7,"imdbVotes":2289808,"tmdb":8.262,"tmdbVotes":29153}},{"id":"movie-the-matrix-reloaded-2003","title":"The Matrix Reloaded","year":2003,"type":"movie","runtimeSeconds":8298,"seasonCount":null,"communityRating":7.085,"criticRating":74,"genres":["Adventure","Action","Thriller"],"overview":"The Resistance builds in numbers as humans are freed from the Matrix and brought to the city of Zion. Neo discovers his superpowers, including the ability to see the code inside the Matrix. With machine sentinels\u2026","poster":"assets/movie-the-matrix-reloaded-2003-poster.jpg","backdrop":"assets/movie-the-matrix-reloaded-2003-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:24:03.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":604,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":73,"rtCriticsLabel":"Certified Fresh","rtAudience":72,"rtAudienceLabel":"Upright","imdb":7.2,"imdbVotes":678013,"tmdb":7.087,"tmdbVotes":12504}},{"id":"movie-the-matrix-resurrections-2021","title":"The Matrix Resurrections","year":2021,"type":"movie","runtimeSeconds":8875,"seasonCount":null,"communityRating":6.303,"criticRating":63,"genres":["Science Fiction","Action","Adventure"],"overview":"Plagued by strange memories, Neo's life takes an unexpected turn when he finds himself back inside the Matrix.","poster":"assets/movie-the-matrix-resurrections-2021-poster.jpg","backdrop":"assets/movie-the-matrix-resurrections-2021-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:31:22.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":624860,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":63,"rtCriticsLabel":"Fresh","rtAudience":63,"rtAudienceLabel":"Upright","imdb":5.6,"imdbVotes":307780,"tmdb":6.294,"tmdbVotes":6842}},{"id":"movie-the-matrix-revolutions-2003","title":"The Matrix Revolutions","year":2003,"type":"movie","runtimeSeconds":7756,"seasonCount":null,"communityRating":6.758,"criticRating":33,"genres":["Adventure","Action","Thriller"],"overview":"The human city of Zion defends itself against the massive invasion of the machines as Neo fights to end the war at another front while also opposing the rogue Agent Smith.","poster":"assets/movie-the-matrix-revolutions-2003-poster.jpg","backdrop":"assets/movie-the-matrix-revolutions-2003-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:25:47.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":605,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":34,"rtCriticsLabel":"Rotten","rtAudience":60,"rtAudienceLabel":"Upright","imdb":6.8,"imdbVotes":581553,"tmdb":6.762,"tmdbVotes":11292}},{"id":"movie-mercy-2026","title":"Mercy","year":2026,"type":"movie","runtimeSeconds":5968,"seasonCount":null,"communityRating":7.077,"criticRating":null,"genres":["Science Fiction","Thriller","Crime"],"overview":"In the near future, a detective stands on trial accused of murdering his wife. He has ninety minutes to prove his innocence to the advanced AI Judge he once championed, before it determines his fate.","poster":"assets/movie-mercy-2026-poster.jpg","backdrop":"assets/movie-mercy-2026-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:31:40.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":1236153,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":24,"rtCriticsLabel":"Rotten","rtAudience":81,"rtAudienceLabel":"Upright","imdb":6.2,"imdbVotes":83878,"tmdb":7.054,"tmdbVotes":1812}},{"id":"movie-normal-2026","title":"Normal","year":2026,"type":"movie","runtimeSeconds":5514,"seasonCount":null,"communityRating":7.267,"criticRating":77,"genres":["Action","Crime","Thriller"],"overview":"An unassuming substitute sheriff with a troubled past responds to a bank robbery in a small, sleepy town and unknowingly uncovers something far more explosive.","poster":"assets/movie-normal-2026-poster.jpg","backdrop":"assets/movie-normal-2026-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-08-21T08:33:18.0000000Z","lastPlayedAt":"2026-09-24T23:07:52.1161581Z","availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":1242332,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":78,"rtCriticsLabel":"Certified Fresh","rtAudience":75,"rtAudienceLabel":"Upright","imdb":6.3,"imdbVotes":37501,"tmdb":7.241,"tmdbVotes":786}},{"id":"movie-outlaw-king-2018","title":"Outlaw King","year":2018,"type":"movie","runtimeSeconds":7297,"seasonCount":null,"communityRating":6.829,"criticRating":63,"genres":["Action","History","War"],"overview":"Forced into exile by the English after being crowned King of Scotland, legendary warrior Robert the Bruce fights to reclaim the throne.","poster":"assets/movie-outlaw-king-2018-poster.jpg","backdrop":"assets/movie-outlaw-king-2018-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:28:32.0000000Z","lastPlayedAt":"2026-07-26T22:35:35.0000000Z","availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":454227,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":63,"rtCriticsLabel":"Fresh","rtAudience":69,"rtAudienceLabel":"Upright","imdb":6.9,"imdbVotes":89876,"tmdb":6.844,"tmdbVotes":1780}},{"id":"movie-panic-room-2002","title":"Panic Room","year":2002,"type":"movie","runtimeSeconds":6717,"seasonCount":null,"communityRating":6.794,"criticRating":76,"genres":["Crime","Drama","Thriller"],"overview":"Trapped in their New York brownstone's panic room, a hidden chamber built as a sanctuary in the event of break-ins, newly divorced Meg Altman and her young daughter Sarah play a deadly game of cat-and-mouse with\u2026","poster":"assets/movie-panic-room-2002-poster.jpg","backdrop":"assets/movie-panic-room-2002-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-19T20:50:01.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":4547,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":76,"rtCriticsLabel":"Certified Fresh","rtAudience":64,"rtAudienceLabel":"Upright","imdb":6.8,"imdbVotes":317468,"tmdb":6.796,"tmdbVotes":5653}},{"id":"movie-the-patriot-2000","title":"The Patriot","year":2000,"type":"movie","runtimeSeconds":9887,"seasonCount":null,"communityRating":7.214,"criticRating":61,"genres":["Drama","History","War"],"overview":"After proving himself on the field of battle in the French and Indian War, Benjamin Martin wants nothing more to do with such things, preferring the simple life of a farmer. But when his son Gabriel enlists in the\u2026","poster":"assets/movie-the-patriot-2000-poster.jpg","backdrop":"assets/movie-the-patriot-2000-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-10T20:50:00.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":2024,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":61,"rtCriticsLabel":"Fresh","rtAudience":81,"rtAudienceLabel":"Upright","imdb":7.2,"imdbVotes":317639,"tmdb":7.215,"tmdbVotes":4535}},{"id":"movie-peaky-blinders-the-immortal-man-2026","title":"Peaky Blinders: The Immortal Man","year":2026,"type":"movie","runtimeSeconds":6844,"seasonCount":null,"communityRating":7.187,"criticRating":90,"genres":["Crime","Drama"],"overview":"After his estranged son gets embroiled in a Nazi plot, self-exiled gangster Tommy Shelby must return to Birmingham to save his family \u2014 and his nation.","poster":"assets/movie-peaky-blinders-the-immortal-man-2026-poster.jpg","backdrop":"assets/movie-peaky-blinders-the-immortal-man-2026-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:30:01.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":875828,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":90,"rtCriticsLabel":"Certified Fresh","rtAudience":87,"rtAudienceLabel":"Upright","imdb":6.5,"imdbVotes":92130,"tmdb":7.189,"tmdbVotes":1304}},{"id":"movie-ponyo-2008","title":"Ponyo","year":2008,"type":"movie","runtimeSeconds":6530,"seasonCount":null,"communityRating":7.763,"criticRating":91,"genres":["Animation","Fantasy","Family"],"overview":"When Sosuke, a young boy who lives on a clifftop overlooking the sea, rescues a stranded goldfish named Ponyo, he discovers more than he bargained for. Ponyo is a curious, energetic young creature who yearns to be\u2026","poster":"assets/movie-ponyo-2008-poster.jpg","backdrop":"assets/movie-ponyo-2008-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:23:53.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":12429,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":91,"rtCriticsLabel":"Certified Fresh","rtAudience":84,"rtAudienceLabel":"Upright","imdb":7.6,"imdbVotes":190294,"tmdb":7.759,"tmdbVotes":5050}},{"id":"movie-porco-rosso-1992","title":"Porco Rosso","year":1992,"type":"movie","runtimeSeconds":5600,"seasonCount":null,"communityRating":7.794,"criticRating":96,"genres":["Animation","Adventure","Fantasy"],"overview":"In Italy in the 1930s, sky pirates in biplanes terrorize wealthy cruise ships as they sail the Adriatic Sea. The only pilot brave enough to stop the scourge is the mysterious Porco Rosso, a former World War I flying\u2026","poster":"assets/movie-porco-rosso-1992-poster.jpg","backdrop":"assets/movie-porco-rosso-1992-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:23:22.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":11621,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":96,"rtCriticsLabel":"Fresh","rtAudience":87,"rtAudienceLabel":"Upright","imdb":7.7,"imdbVotes":119396,"tmdb":7.789,"tmdbVotes":3879}},{"id":"movie-princess-mononoke-1997","title":"Princess Mononoke","year":1997,"type":"movie","runtimeSeconds":8003,"seasonCount":null,"communityRating":8.321,"criticRating":93,"genres":["Adventure","Fantasy","Animation"],"overview":"Ashitaka, a prince of the disappearing Emishi people, is cursed by a demonized boar god and must journey to the west to find a cure. Along the way, he encounters San, a young human woman fighting to protect the\u2026","poster":"assets/movie-princess-mononoke-1997-poster.jpg","backdrop":"assets/movie-princess-mononoke-1997-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:22:28.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":128,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":94,"rtCriticsLabel":"Certified Fresh","rtAudience":99,"rtAudienceLabel":"Upright","imdb":8.3,"imdbVotes":493735,"tmdb":8.321,"tmdbVotes":9438}},{"id":"movie-prisoners-2013","title":"Prisoners","year":2013,"type":"movie","runtimeSeconds":9192,"seasonCount":null,"communityRating":8.106,"criticRating":81,"genres":["Drama","Thriller","Crime"],"overview":"After his six-year-old daughter is abducted, a desperate father takes justice into his own hands when he loses faith in the detective leading the investigation, setting both men on a collision course as the search\u2026","poster":"assets/movie-prisoners-2013-poster.jpg","backdrop":"assets/movie-prisoners-2013-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:27:33.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":146233,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":82,"rtCriticsLabel":"Certified Fresh","rtAudience":87,"rtAudienceLabel":"Upright","imdb":8.2,"imdbVotes":963062,"tmdb":8.105,"tmdbVotes":13722}},{"id":"movie-racing-stripes-2005","title":"Racing Stripes","year":2005,"type":"movie","runtimeSeconds":6117,"seasonCount":null,"communityRating":5.945,"criticRating":35,"genres":["Comedy","Family"],"overview":"Shattered illusions are hard to repair -- especially for a good-hearted zebra named Stripes who's spent his life on a Kentucky farm amidst the sorely mistaken notion that he's a debonair thoroughbred. Once he faces\u2026","poster":"assets/movie-racing-stripes-2005-poster.jpg","backdrop":"assets/movie-racing-stripes-2005-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:26:02.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":6439,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":35,"rtCriticsLabel":"Rotten","rtAudience":42,"rtAudienceLabel":"Spilled","imdb":5.3,"imdbVotes":19569,"tmdb":5.962,"tmdbVotes":705}},{"id":"movie-requiem-for-a-dream-2000","title":"Requiem for a Dream","year":2000,"type":"movie","runtimeSeconds":6086,"seasonCount":null,"communityRating":8.005,"criticRating":80,"genres":["Crime","Drama"],"overview":"The drug-induced utopias of four Coney Island residents are shattered when their addictions run deep.","poster":"assets/movie-requiem-for-a-dream-2000-poster.jpg","backdrop":"assets/movie-requiem-for-a-dream-2000-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:24:15.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":641,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":81,"rtCriticsLabel":"Certified Fresh","rtAudience":93,"rtAudienceLabel":"Upright","imdb":8.3,"imdbVotes":989090,"tmdb":8,"tmdbVotes":11454}},{"id":"movie-rogue-one-a-star-wars-story-2016","title":"Rogue One: A Star Wars Story","year":2016,"type":"movie","runtimeSeconds":8038,"seasonCount":null,"communityRating":7.51,"criticRating":84,"genres":["Action","Adventure","Science Fiction"],"overview":"A rogue band of resistance fighters unite for a mission to steal the Death Star plans and bring a new hope to the galaxy.","poster":"assets/movie-rogue-one-a-star-wars-story-2016-poster.jpg","backdrop":"assets/movie-rogue-one-a-star-wars-story-2016-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:28:00.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":330459,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":84,"rtCriticsLabel":"Certified Fresh","rtAudience":87,"rtAudienceLabel":"Upright","imdb":7.8,"imdbVotes":768365,"tmdb":7.512,"tmdbVotes":16937}},{"id":"movie-secondhand-lions-2003","title":"Secondhand Lions","year":2003,"type":"movie","runtimeSeconds":6547,"seasonCount":null,"communityRating":7.237,"criticRating":60,"genres":["Family","Comedy","Drama"],"overview":"The comedic adventures of an introverted boy left on the doorstep of a pair of reluctant, eccentric great-uncles, whose exotic remembrances stir the boy's spirit and re-ignite the men's lives.","poster":"assets/movie-secondhand-lions-2003-poster.jpg","backdrop":"assets/movie-secondhand-lions-2003-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-12T07:16:13.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":13156,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":59,"rtCriticsLabel":"Rotten","rtAudience":84,"rtAudienceLabel":"Upright","imdb":7.5,"imdbVotes":66911,"tmdb":7.242,"tmdbVotes":872}},{"id":"movie-the-secret-life-of-pets-2-2019","title":"The Secret Life of Pets 2","year":2019,"type":"movie","runtimeSeconds":5164,"seasonCount":null,"communityRating":6.95,"criticRating":60,"genres":["Animation","Comedy","Family"],"overview":"Max the terrier must cope with some major life changes when his owner gets married and has a baby. When the family takes a trip to the countryside, nervous Max has numerous run-ins with canine-intolerant cows,\u2026","poster":"assets/movie-the-secret-life-of-pets-2-2019-poster.jpg","backdrop":"assets/movie-the-secret-life-of-pets-2-2019-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-05T07:00:53.0000000Z","lastPlayedAt":"2026-09-17T18:07:00.7024231Z","availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":412117,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":60,"rtCriticsLabel":"Fresh","rtAudience":90,"rtAudienceLabel":"Upright","imdb":6.4,"imdbVotes":80464,"tmdb":6.948,"tmdbVotes":3450}},{"id":"movie-self-reliance-2024","title":"Self Reliance","year":2024,"type":"movie","runtimeSeconds":5461,"seasonCount":null,"communityRating":5.888,"criticRating":73,"genres":["Comedy","Thriller"],"overview":"When a man is offered a million dollars to play a game in which hunters try to kill him, he thinks he has found the perfect loophole: they can only attack when he\u2019s alone. His only problem is that none of his friends\u2026","poster":"assets/movie-self-reliance-2024-poster.jpg","backdrop":"assets/movie-self-reliance-2024-backdrop.jpg","played":false,"playCount":1,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:31:00.0000000Z","lastPlayedAt":"2026-10-02T19:59:16.9286868Z","availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":1072876,"artwork":{"posterKind":"center_crop","backdropKind":"backdrop"},"ratings":{"rtCritics":73,"rtCriticsLabel":"Certified Fresh","rtAudience":56,"rtAudienceLabel":"Spilled","imdb":6,"imdbVotes":23771,"tmdb":5.866,"tmdbVotes":346}},{"id":"movie-serpico-1973","title":"Serpico","year":1973,"type":"movie","runtimeSeconds":7805,"seasonCount":null,"communityRating":7.5,"criticRating":93,"genres":["Crime","Drama","History"],"overview":"New York cop Frank Serpico blows the whistle on the rampant corruption in the force only to have his comrades turn against him.","poster":"assets/movie-serpico-1973-poster.jpg","backdrop":"assets/movie-serpico-1973-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-10T21:45:02.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":9040,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":93,"rtCriticsLabel":"Certified Fresh","rtAudience":88,"rtAudienceLabel":"Upright","imdb":7.7,"imdbVotes":149750,"tmdb":7.525,"tmdbVotes":2323}},{"id":"movie-shaft-2000","title":"Shaft","year":2000,"type":"movie","runtimeSeconds":5960,"seasonCount":null,"communityRating":6.026,"criticRating":67,"genres":["Action","Adventure","Crime"],"overview":"New York police detective John Shaft arrests Walter Wade Jr. for a racially motivated slaying. But the only eyewitness disappears, and Wade jumps bail for Switzerland. Two years later Wade returns to face trial,\u2026","poster":"assets/movie-shaft-2000-poster.jpg","backdrop":"assets/movie-shaft-2000-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-10T21:30:40.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":479,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":68,"rtCriticsLabel":"Fresh","rtAudience":40,"rtAudienceLabel":"Spilled","imdb":6,"imdbVotes":86257,"tmdb":6.024,"tmdbVotes":1531}},{"id":"movie-a-silent-voice-the-movie-2016","title":"A Silent Voice: The Movie","year":2016,"type":"movie","runtimeSeconds":7804,"seasonCount":null,"communityRating":8.398,"criticRating":null,"genres":["Animation","Drama","Romance"],"overview":"Shouya Ishida starts bullying the new girl in class, Shouko Nishimiya, because she is deaf. But as the teasing continues, the rest of the class starts to turn on Shouya for his lack of compassion. When they leave\u2026","poster":"assets/movie-a-silent-voice-the-movie-2016-poster.jpg","backdrop":"assets/movie-a-silent-voice-the-movie-2016-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T17:39:46.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":378064,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":95,"rtCriticsLabel":"Fresh","rtAudience":94,"rtAudienceLabel":"Upright","imdb":8.2,"imdbVotes":151926,"tmdb":8.396,"tmdbVotes":4764}},{"id":"movie-sinbad-legend-of-the-seven-seas-2003","title":"Sinbad: Legend of the Seven Seas","year":2003,"type":"movie","runtimeSeconds":5143,"seasonCount":null,"communityRating":7.067,"criticRating":44,"genres":["Action","Adventure","Animation"],"overview":"The sailor of legend is framed by the goddess Eris for the theft of the Book of Peace, and must travel to her realm at the end of the world to retrieve it and save the life of his childhood friend Prince Proteus.","poster":"assets/movie-sinbad-legend-of-the-seven-seas-2003-poster.jpg","backdrop":"assets/movie-sinbad-legend-of-the-seven-seas-2003-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:26:25.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":14411,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":46,"rtCriticsLabel":"Rotten","rtAudience":57,"rtAudienceLabel":"Spilled","imdb":6.8,"imdbVotes":65298,"tmdb":7.071,"tmdbVotes":2323}},{"id":"movie-sleeping-with-other-people-2015","title":"Sleeping with Other People","year":2015,"type":"movie","runtimeSeconds":6076,"seasonCount":null,"communityRating":6.274,"criticRating":64,"genres":["Comedy","Romance"],"overview":"Can two serial cheaters get a second chance at love? After a one-night stand in college, New Yorkers Lainey and Jake meet by chance twelve years later and discover they each have the same problem: because of their\u2026","poster":"assets/movie-sleeping-with-other-people-2015-poster.jpg","backdrop":"assets/movie-sleeping-with-other-people-2015-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:27:42.0000000Z","lastPlayedAt":"2026-07-17T17:50:44.0000000Z","availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":288036,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":64,"rtCriticsLabel":"Fresh","rtAudience":56,"rtAudienceLabel":"Spilled","imdb":6.5,"imdbVotes":52275,"tmdb":6.275,"tmdbVotes":1020}},{"id":"movie-snowpiercer-2013","title":"Snowpiercer","year":2013,"type":"movie","runtimeSeconds":7573,"seasonCount":null,"communityRating":6.909,"criticRating":94,"genres":["Action","Science Fiction","Drama"],"overview":"In a future where a failed global-warming experiment kills off most life on the planet, a class system evolves aboard the Snowpiercer; a train that travels around the globe via a perpetual-motion engine.","poster":"assets/movie-snowpiercer-2013-poster.jpg","backdrop":"assets/movie-snowpiercer-2013-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:27:07.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":110415,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":94,"rtCriticsLabel":"Certified Fresh","rtAudience":72,"rtAudienceLabel":"Upright","imdb":7.1,"imdbVotes":426976,"tmdb":6.9,"tmdbVotes":10807}},{"id":"movie-spider-man-brand-new-day-2026","title":"Spider-Man: Brand New Day","year":2026,"type":"movie","runtimeSeconds":8701,"seasonCount":null,"communityRating":8.374,"criticRating":90,"genres":["Science Fiction","Action","Adventure"],"overview":"Fighting crime full-time as Spider-Man in a world that doesn't remember him\u2014and the pressure of seeing his old friends move on without him\u2014sparks a change in Peter Parker he may not have the power to control. But\u2026","poster":"assets/movie-spider-man-brand-new-day-2026-poster.jpg","backdrop":"assets/movie-spider-man-brand-new-day-2026-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-10T14:14:27.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":969681,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":90,"rtCriticsLabel":"Certified Fresh","rtAudience":97,"rtAudienceLabel":"Upright","imdb":7.9,"imdbVotes":366886,"tmdb":8.5,"tmdbVotes":6537}},{"id":"movie-spider-man-far-from-home-2019","title":"Spider-Man: Far From Home","year":2019,"type":"movie","runtimeSeconds":7762,"seasonCount":null,"communityRating":7.389,"criticRating":91,"genres":["Action","Adventure","Science Fiction"],"overview":"Peter Parker and his friends go on a summer trip to Europe. However, they will hardly be able to rest - Peter will have to agree to help Nick Fury uncover the mystery of creatures that cause natural disasters and\u2026","poster":"assets/movie-spider-man-far-from-home-2019-poster.jpg","backdrop":"assets/movie-spider-man-far-from-home-2019-backdrop.jpg","played":true,"playCount":1,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-10T14:25:47.0000000Z","lastPlayedAt":"2026-10-10T17:50:35.6193119Z","availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":429617,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":91,"rtCriticsLabel":"Certified Fresh","rtAudience":95,"rtAudienceLabel":"Upright","imdb":7.3,"imdbVotes":682887,"tmdb":7.387,"tmdbVotes":17847}},{"id":"movie-spider-man-homecoming-2017","title":"Spider-Man: Homecoming","year":2017,"type":"movie","runtimeSeconds":8008,"seasonCount":null,"communityRating":7.333,"criticRating":92,"genres":["Action","Adventure","Science Fiction"],"overview":"Following the events of Captain America: Civil War, Peter Parker, with the help of his mentor Tony Stark, tries to balance his life as an ordinary high school student in Queens, New York City, with fighting crime as\u2026","poster":"assets/movie-spider-man-homecoming-2017-poster.jpg","backdrop":"assets/movie-spider-man-homecoming-2017-backdrop.jpg","played":true,"playCount":1,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-10T14:33:13.0000000Z","lastPlayedAt":"2026-10-10T20:31:23.4444213Z","availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":315635,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":92,"rtCriticsLabel":"Certified Fresh","rtAudience":87,"rtAudienceLabel":"Upright","imdb":7.4,"imdbVotes":840974,"tmdb":7.332,"tmdbVotes":24183}},{"id":"movie-spider-man-no-way-home-2021","title":"Spider-Man: No Way Home","year":2021,"type":"movie","runtimeSeconds":8890,"seasonCount":null,"communityRating":7.947,"criticRating":93,"genres":["Action","Adventure","Science Fiction"],"overview":"Peter Parker is unmasked and no longer able to separate his normal life from the high-stakes of being a super-hero. When he asks for help from Doctor Strange the stakes become even more dangerous, forcing him to\u2026","poster":"assets/movie-spider-man-no-way-home-2021-poster.jpg","backdrop":"assets/movie-spider-man-no-way-home-2021-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-10T14:21:05.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":634649,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":93,"rtCriticsLabel":"Certified Fresh","rtAudience":97,"rtAudienceLabel":"Upright","imdb":8.1,"imdbVotes":1082660,"tmdb":7.947,"tmdbVotes":23505}},{"id":"movie-spirited-away-2001","title":"Spirited Away","year":2001,"type":"movie","runtimeSeconds":7472,"seasonCount":null,"communityRating":8.535,"criticRating":96,"genres":["Animation","Family","Fantasy"],"overview":"A young girl, Chihiro, becomes trapped in a strange new world of spirits. When her parents undergo a mysterious transformation, she must call upon the courage she never knew she had to free her family.","poster":"assets/movie-spirited-away-2001-poster.jpg","backdrop":"assets/movie-spirited-away-2001-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:22:42.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":129,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":96,"rtCriticsLabel":"Certified Fresh","rtAudience":99,"rtAudienceLabel":"Upright","imdb":8.6,"imdbVotes":987658,"tmdb":8.536,"tmdbVotes":19176}},{"id":"movie-the-substance-2024","title":"The Substance","year":2024,"type":"movie","runtimeSeconds":8531,"seasonCount":null,"communityRating":7.135,"criticRating":89,"genres":["Horror","Science Fiction"],"overview":"A fading celebrity decides to use a black market drug, a cell-replicating substance that temporarily creates a younger, better version of herself.","poster":"assets/movie-the-substance-2024-poster.jpg","backdrop":"assets/movie-the-substance-2024-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:30:22.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":933260,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":89,"rtCriticsLabel":"Certified Fresh","rtAudience":76,"rtAudienceLabel":"Upright","imdb":7.2,"imdbVotes":466542,"tmdb":7.13,"tmdbVotes":6746}},{"id":"movie-the-tale-of-the-princess-kaguya-2013","title":"The Tale of The Princess Kaguya","year":2013,"type":"movie","runtimeSeconds":8218,"seasonCount":null,"communityRating":8.1,"criticRating":100,"genres":["Animation","Drama","Fantasy"],"overview":"Found inside a shining stalk of bamboo by an old bamboo cutter and his wife, a tiny girl grows rapidly into an exquisite young lady. The mysterious young princess enthrals all who encounter her. But, ultimately, she\u2026","poster":"assets/movie-the-tale-of-the-princess-kaguya-2013-poster.jpg","backdrop":"assets/movie-the-tale-of-the-princess-kaguya-2013-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-07T13:40:15.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":149871,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Certified Fresh","rtAudience":90,"rtAudienceLabel":"Upright","imdb":8,"imdbVotes":63574,"tmdb":8.083,"tmdbVotes":2079}},{"id":"movie-taxi-driver-1976","title":"Taxi Driver","year":1976,"type":"movie","runtimeSeconds":6831,"seasonCount":null,"communityRating":8.121,"criticRating":89,"genres":["Crime","Drama"],"overview":"Suffering from insomnia, disturbed loner Travis Bickle takes a job as a New York City cabbie, haunting the streets nightly, growing increasingly detached from reality as he dreams of cleaning up the filthy city.","poster":"assets/movie-taxi-driver-1976-poster.jpg","backdrop":"assets/movie-taxi-driver-1976-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:23:04.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":103,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":89,"rtCriticsLabel":"Certified Fresh","rtAudience":93,"rtAudienceLabel":"Upright","imdb":8.2,"imdbVotes":1046700,"tmdb":8.116,"tmdbVotes":13973}},{"id":"movie-triangle-of-sadness-2022","title":"Triangle of Sadness","year":2022,"type":"movie","runtimeSeconds":8833,"seasonCount":null,"communityRating":7.005,"criticRating":71,"genres":["Comedy","Drama"],"overview":"A celebrity model couple are invited on a luxury cruise for the uber-rich, helmed by an unhinged, alcoholic captain. What first appears Instagrammable ends catastrophically, leaving the survivors stranded on a desert\u2026","poster":"assets/movie-triangle-of-sadness-2022-poster.jpg","backdrop":"assets/movie-triangle-of-sadness-2022-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:29:00.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":497828,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":72,"rtCriticsLabel":"Fresh","rtAudience":80,"rtAudienceLabel":"Upright","imdb":7.2,"imdbVotes":221069,"tmdb":7,"tmdbVotes":3104}},{"id":"movie-tsotsi-2005","title":"Tsotsi","year":2005,"type":"movie","runtimeSeconds":5663,"seasonCount":null,"communityRating":6.937,"criticRating":82,"genres":["Crime","Drama"],"overview":"A young South African boy from the Johannesburg ghetto named Tsotsi, meaning Gangster, leaves home as a child to get away from his helpless parents. Now a teenage thug, Tsotsi finds a baby in the back seat of a car\u2026","poster":"assets/movie-tsotsi-2005-poster.jpg","backdrop":"assets/movie-tsotsi-2005-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:24:58.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":868,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":82,"rtCriticsLabel":"Certified Fresh","rtAudience":86,"rtAudienceLabel":"Upright","imdb":7.2,"imdbVotes":32526,"tmdb":6.941,"tmdbVotes":372}},{"id":"movie-unknown-number-the-high-school-catfish-2025","title":"Unknown Number: The High School Catfish","year":2025,"type":"movie","runtimeSeconds":5691,"seasonCount":null,"communityRating":6.746,"criticRating":85,"genres":["Documentary"],"overview":"Vulgar, taunting texts blow up the phones of a teen and her boyfriend. Who's sending them \u2014 and why? This twisty documentary reveals the shocking answer.","poster":"assets/movie-unknown-number-the-high-school-catfish-2025-poster.jpg","backdrop":"assets/movie-unknown-number-the-high-school-catfish-2025-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:32:10.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":1517772,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":85,"rtCriticsLabel":"Fresh","rtAudience":69,"rtAudienceLabel":"Upright","imdb":6.7,"imdbVotes":23039,"tmdb":6.737,"tmdbVotes":257}},{"id":"movie-the-uprising-2026","title":"The Uprising","year":2026,"type":"movie","runtimeSeconds":7684,"seasonCount":null,"communityRating":7.846,"criticRating":55,"genres":["Action","Drama","History"],"overview":"As war and plague devastate 14th-century England, a humble peasant ignites a rebellion, uniting an army of commoners to defy the King\u2019s might in a desperate fight for justice and survival.","poster":"assets/movie-the-uprising-2026-poster.jpg","backdrop":"assets/movie-the-uprising-2026-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-11-02T16:37:03.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":977942,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":57,"rtCriticsLabel":"Rotten","rtAudience":65,"rtAudienceLabel":"Upright","imdb":6.2,"imdbVotes":6622,"tmdb":7.8,"tmdbVotes":404}},{"id":"movie-vice-2018","title":"Vice","year":2018,"type":"movie","runtimeSeconds":7948,"seasonCount":null,"communityRating":7.013,"criticRating":64,"genres":["Drama","Comedy","History"],"overview":"George W. Bush picks Dick Cheney, the CEO of Halliburton Co., to be his Republican running mate in the 2000 presidential election. No stranger to politics, Cheney's impressive r\u00e9sum\u00e9 includes stints as White House\u2026","poster":"assets/movie-vice-2018-poster.jpg","backdrop":"assets/movie-vice-2018-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:28:30.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":429197,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":64,"rtCriticsLabel":"Fresh","rtAudience":61,"rtAudienceLabel":"Upright","imdb":7.2,"imdbVotes":177299,"tmdb":7.014,"tmdbVotes":3723}},{"id":"movie-warriors-of-the-wind-1984","title":"Warriors of the Wind","year":1984,"type":"movie","runtimeSeconds":7022,"seasonCount":null,"communityRating":7.941,"criticRating":87,"genres":["Adventure","Animation","Fantasy"],"overview":"After a global war, the seaside kingdom known as the Valley of the Wind remains one of the last strongholds on Earth untouched by a poisonous jungle and the powerful insects that guard it. Led by the courageous\u2026","poster":"assets/movie-warriors-of-the-wind-1984-poster.jpg","backdrop":"assets/movie-warriors-of-the-wind-1984-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:22:20.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":81,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":87,"rtCriticsLabel":"Fresh","rtAudience":91,"rtAudienceLabel":"Upright","imdb":8,"imdbVotes":200154,"tmdb":7.94,"tmdbVotes":4260}},{"id":"movie-we-bury-the-dead-2026","title":"We Bury the Dead","year":2026,"type":"movie","runtimeSeconds":5693,"seasonCount":null,"communityRating":6.153,"criticRating":87,"genres":["Horror","Thriller"],"overview":"After a catastrophic military disaster reanimates the dead, Ava searches for her missing husband amidst an increasingly hostile world.","poster":"assets/movie-we-bury-the-dead-2026-poster.jpg","backdrop":"assets/movie-we-bury-the-dead-2026-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-08-26T05:36:00.4272328Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":1198984,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":87,"rtCriticsLabel":"Certified Fresh","rtAudience":45,"rtAudienceLabel":"Spilled","imdb":5.6,"imdbVotes":20693,"tmdb":6.137,"tmdbVotes":433}},{"id":"movie-white-hot-the-rise-fall-of-abercrombie-fitch-2022","title":"White Hot: The Rise & Fall of Abercrombie & Fitch","year":2022,"type":"movie","runtimeSeconds":5187,"seasonCount":null,"communityRating":5.663,"criticRating":66,"genres":["Documentary"],"overview":"All the cool kids were wearing it. This documentary explores A&F's pop culture reign in the late '90s and early 2000s and how it thrived on exclusion.","poster":"assets/movie-white-hot-the-rise-fall-of-abercrombie-fitch-2022-poster.jpg","backdrop":"assets/movie-white-hot-the-rise-fall-of-abercrombie-fitch-2022-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:30:34.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":953371,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":66,"rtCriticsLabel":"Fresh","rtAudience":29,"rtAudienceLabel":"Spilled","imdb":5.8,"imdbVotes":5655,"tmdb":5.7,"tmdbVotes":102}},{"id":"movie-the-wild-robot-2024","title":"The Wild Robot","year":2024,"type":"movie","runtimeSeconds":6101,"seasonCount":null,"communityRating":8.308,"criticRating":97,"genres":["Family","Animation","Science Fiction"],"overview":"After a shipwreck, an intelligent robot called Roz is stranded on an uninhabited island. To survive the harsh environment, Roz bonds with the island's animals and cares for an orphaned baby goose.","poster":"assets/movie-the-wild-robot-2024-poster.jpg","backdrop":"assets/movie-the-wild-robot-2024-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:31:49.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":1184918,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":97,"rtCriticsLabel":"Certified Fresh","rtAudience":98,"rtAudienceLabel":"Upright","imdb":8.1,"imdbVotes":241134,"tmdb":8.309,"tmdbVotes":6819}},{"id":"movie-the-wind-rises-2013","title":"The Wind Rises","year":2013,"type":"movie","runtimeSeconds":8031,"seasonCount":null,"communityRating":7.784,"criticRating":88,"genres":["Animation","Drama","History"],"overview":"A lifelong love of flight inspires Japanese aviation engineer Jiro Horikoshi, whose storied career includes the creation of the A-6M World War II fighter plane.","poster":"assets/movie-the-wind-rises-2013-poster.jpg","backdrop":"assets/movie-the-wind-rises-2013-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:24:38.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":149870,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":89,"rtCriticsLabel":"Certified Fresh","rtAudience":85,"rtAudienceLabel":"Upright","imdb":7.8,"imdbVotes":115756,"tmdb":7.783,"tmdbVotes":3536}},{"id":"movie-the-witcher-nightmare-of-the-wolf-2021","title":"The Witcher: Nightmare of the Wolf","year":2021,"type":"movie","runtimeSeconds":5015,"seasonCount":null,"communityRating":7.422,"criticRating":100,"genres":["Animation","Action","Fantasy"],"overview":"Escaping from poverty to become a witcher, Vesemir slays monsters for coin and glory, but when a new menace rises, he must face the demons of his past.","poster":"assets/movie-the-witcher-nightmare-of-the-wolf-2021-poster.jpg","backdrop":"assets/movie-the-witcher-nightmare-of-the-wolf-2021-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-26T04:42:03.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":666243,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":83,"rtAudienceLabel":"Upright","imdb":7.2,"imdbVotes":55759,"tmdb":7.407,"tmdbVotes":1159}},{"id":"movie-the-witcher-sirens-of-the-deep-2025","title":"The Witcher: Sirens of the Deep","year":2025,"type":"movie","runtimeSeconds":5517,"seasonCount":null,"communityRating":6.8,"criticRating":60,"genres":["Animation","Fantasy","Action"],"overview":"When human sailors are attacked by mysterious creatures of the deep, only one person can stop the war between land and sea: the Witcher, Geralt of Rivia.","poster":"assets/movie-the-witcher-sirens-of-the-deep-2025-poster.jpg","backdrop":"assets/movie-the-witcher-sirens-of-the-deep-2025-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-26T05:03:26.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":1203329,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":60,"rtCriticsLabel":"Fresh","rtAudience":37,"rtAudienceLabel":"Spilled","imdb":6.1,"imdbVotes":11799,"tmdb":6.741,"tmdbVotes":303}}],"shows":[{"id":"tv-adults-2025","title":"Adults","year":2025,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":6.495,"criticRating":null,"genres":["Comedy"],"overview":"A group of twenty-somethings in New York trying to be good people, despite being neither \"good\" nor \"people\" yet.","poster":"assets/tv-adults-2025-poster.jpg","backdrop":"assets/tv-adults-2025-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-23T21:01:41.1814765Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":260458,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":88,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.5,"tmdbVotes":102}},{"id":"tv-american-crime-story-2016","title":"American Crime Story","year":2016,"type":"tv","runtimeSeconds":null,"seasonCount":3,"communityRating":7.573,"criticRating":null,"genres":["Crime","Drama"],"overview":"An anthology series centered around some of history's most famous criminal investigations.","poster":"assets/tv-american-crime-story-2016-poster.jpg","backdrop":"assets/tv-american-crime-story-2016-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0490488Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":64513,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":84,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.585,"tmdbVotes":1094}},{"id":"tv-american-primeval-2025","title":"American Primeval","year":2025,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":7.691,"criticRating":null,"genres":["Western","Drama","Action & Adventure"],"overview":"A mother and son fleeing from their past form a found family while confronting a harsh landscape of freedom and cruelty in the American West.","poster":"assets/tv-american-primeval-2025-poster.jpg","backdrop":"assets/tv-american-primeval-2025-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0573221Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":215866,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":71,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.741,"tmdbVotes":538}},{"id":"tv-arrested-development-2003","title":"Arrested Development","year":2003,"type":"tv","runtimeSeconds":null,"seasonCount":5,"communityRating":7.925,"criticRating":null,"genres":["Comedy"],"overview":"The story of a wealthy family that lost everything, and the one son who had no choice but to keep them all together.","poster":"assets/tv-arrested-development-2003-poster.jpg","backdrop":"assets/tv-arrested-development-2003-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0513048Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":4589,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":75,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.906,"tmdbVotes":1793}},{"id":"tv-avatar-the-last-airbender-2005","title":"Avatar: The Last Airbender","year":2005,"type":"tv","runtimeSeconds":1440,"seasonCount":3,"communityRating":8.78,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"In a war-torn world of elemental magic, a young boy reawakens to undertake a dangerous mystic quest to fulfill his destiny as the Avatar, and bring peace to the world.","poster":"assets/tv-avatar-the-last-airbender-2005-poster.jpg","backdrop":"assets/tv-avatar-the-last-airbender-2005-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0504536Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":246,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.787,"tmdbVotes":5215}},{"id":"tv-b-b-vol-liefde-2021","title":"B&B Vol Liefde","year":2021,"type":"tv","runtimeSeconds":3720,"seasonCount":1,"communityRating":7.2,"criticRating":null,"genres":["Reality"],"overview":"B&B Vol Liefde is a heartwarming adventure, full of romance, excitement, and unforgettable moments. Adventurous Dutch B&B owners abroad throw their doors wide open and let their hearts speak, determined to find that\u2026","poster":"assets/tv-b-b-vol-liefde-2021-poster.jpg","backdrop":"assets/tv-b-b-vol-liefde-2021-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-31T22:30:11.129657Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":124428,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.2,"tmdbVotes":10}},{"id":"tv-the-bear-2022","title":"The Bear","year":2022,"type":"tv","runtimeSeconds":null,"seasonCount":5,"communityRating":8.139,"criticRating":null,"genres":["Drama","Comedy"],"overview":"Carmy, a young fine-dining chef, comes home to Chicago to run his family sandwich shop. As he fights to transform the shop and himself, he works alongside a rough-around-the-edges crew that ultimately reveal\u2026","poster":"assets/tv-the-bear-2022-poster.jpg","backdrop":"assets/tv-the-bear-2022-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0467371Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":136315,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":93,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.158,"tmdbVotes":2025}},{"id":"tv-blue-planet-ii-2017","title":"Blue Planet II","year":2017,"type":"tv","runtimeSeconds":3600,"seasonCount":1,"communityRating":8.64,"criticRating":null,"genres":["Documentary","Family"],"overview":"There is nowhere more powerful and unforgiving yet more beautiful and compelling than the ocean. Join us and explore the greatest yet least known parts of our planet.","poster":"assets/tv-blue-planet-ii-2017-poster.jpg","backdrop":"assets/tv-blue-planet-ii-2017-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0634849Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":74313,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":97,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.6,"tmdbVotes":380}},{"id":"tv-breeders-2020","title":"Breeders","year":2020,"type":"tv","runtimeSeconds":1500,"seasonCount":4,"communityRating":6.8,"criticRating":null,"genres":["Comedy"],"overview":"Exposing the parental-paradox that it is possible, in the very same moment, to love your child to the horizon of the universe, while being apoplectically angry enough to want to send them there.","poster":"assets/tv-breeders-2020-poster.jpg","backdrop":"assets/tv-breeders-2020-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-28T18:54:21.8885435Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":93290,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":92,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.8,"tmdbVotes":104}},{"id":"tv-chernobyl-2019","title":"Chernobyl","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":8.718,"criticRating":null,"genres":["Drama"],"overview":"The true story of one of the worst man-made catastrophes in history: the catastrophic nuclear accident at Chernobyl. A tale of the brave men and women who sacrificed to save Europe from unimaginable disaster.","poster":"assets/tv-chernobyl-2019-poster.jpg","backdrop":"assets/tv-chernobyl-2019-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0469903Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":87108,"artwork":{"posterKind":"poster","backdropKind":"center_crop"},"ratings":{"rtCritics":95,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.731,"tmdbVotes":8496}},{"id":"tv-community-2009","title":"Community","year":2009,"type":"tv","runtimeSeconds":null,"seasonCount":6,"communityRating":7.997,"criticRating":null,"genres":["Comedy"],"overview":"Follow the lives of a group of students at what is possibly the world\u2019s worst community college in the fictional locale of Greendale, Colorado.","poster":"assets/tv-community-2009-poster.jpg","backdrop":"assets/tv-community-2009-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0531416Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":18347,"artwork":{"posterKind":"center_crop","backdropKind":"backdrop"},"ratings":{"rtCritics":88,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.994,"tmdbVotes":2226}},{"id":"tv-dead-end-job-2026","title":"Dead-End Job","year":2026,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":7.7,"criticRating":null,"genres":["Mystery"],"overview":"Drowning in debt, a young man takes lucrative part-time jobs from a mysterious agency \u2014 only to find his hustle for more money turning nightmarish.","poster":"assets/tv-dead-end-job-2026-poster.jpg","backdrop":"assets/tv-dead-end-job-2026-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-11-04T18:58:01.8352857Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":289517,"artwork":{"posterKind":"center_crop","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.7,"tmdbVotes":38}},{"id":"tv-dopesick-2021","title":"Dopesick","year":2021,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":8.015,"criticRating":null,"genres":["Crime","Drama"],"overview":"The story of how one company triggered the worst drug epidemic in American history. Look into the epicenter of America's struggle with opioid addiction, from a distressed Virginia mining community, to the hallways of\u2026","poster":"assets/tv-dopesick-2021-poster.jpg","backdrop":"assets/tv-dopesick-2021-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0580168Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":110695,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":89,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.035,"tmdbVotes":565}},{"id":"tv-dune-prophecy-2024","title":"Dune: Prophecy","year":2024,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":7.213,"criticRating":null,"genres":["Sci-Fi & Fantasy","Drama","Action & Adventure"],"overview":"Ten thousand years before the ascension of Paul Atreides, sisters Valya and Tula Harkonnen establish the fabled sect and female order that would become known as the Bene Gesserit to control the future of humankind.","poster":"assets/tv-dune-prophecy-2024-poster.jpg","backdrop":"assets/tv-dune-prophecy-2024-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-11-04T18:23:01.2908568Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":90228,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":64,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.213,"tmdbVotes":677}},{"id":"tv-east-of-eden-2026","title":"East of Eden","year":2026,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":7.931,"criticRating":null,"genres":["Drama","Crime"],"overview":"In the early 1900s, a fiercely independent woman drives a rift between two brothers, igniting a saga that unfolds across two generations.","poster":"assets/tv-east-of-eden-2026-poster.jpg","backdrop":"assets/tv-east-of-eden-2026-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-23T18:07:11.3965096Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":258165,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":88,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.982,"tmdbVotes":139}},{"id":"tv-fallout-2024","title":"Fallout","year":2024,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":8.124,"criticRating":null,"genres":["Action & Adventure","Sci-Fi & Fantasy","Drama"],"overview":"The story of haves and have-nots in a world in which there's almost nothing left to have. 200 years after the apocalypse, the gentle denizens of luxury fallout shelters are forced to return to the irradiated\u2026","poster":"assets/tv-fallout-2024-poster.jpg","backdrop":"assets/tv-fallout-2024-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0669262Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":106379,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":94,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.106,"tmdbVotes":3233}},{"id":"tv-fawlty-towers-1975","title":"Fawlty Towers","year":1975,"type":"tv","runtimeSeconds":1800,"seasonCount":2,"communityRating":8.295,"criticRating":null,"genres":["Comedy"],"overview":"Owner Basil Fawlty, his wife Sybil, a chambermaid Polly, and Spanish waiter Manuel attempt to run their hotel amidst farcical situations and an array of demanding guests.","poster":"assets/tv-fawlty-towers-1975-poster.jpg","backdrop":"assets/tv-fawlty-towers-1975-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-19T23:26:39.7658344Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":2207,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.296,"tmdbVotes":867}},{"id":"tv-the-final-problem-2026","title":"The Final Problem","year":2026,"type":"tv","runtimeSeconds":3420,"seasonCount":1,"communityRating":7.041,"criticRating":null,"genres":["Crime","Mystery"],"overview":"In the spring of 1959, a retired actor, who previously played Sherlock Holmes, must investigate a murder at a small hotel on a tiny island near Mallorca.","poster":"assets/tv-the-final-problem-2026-poster.jpg","backdrop":"assets/tv-the-final-problem-2026-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-11-04T19:16:12.4822791Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":290720,"artwork":{"posterKind":"center_crop","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.041,"tmdbVotes":49}},{"id":"tv-the-four-seasons-2025","title":"The Four Seasons","year":2025,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":6.879,"criticRating":null,"genres":["Comedy"],"overview":"The decades-long friendship between three married couples is tested when one divorces, complicating their tradition of quarterly weekend getaways.","poster":"assets/tv-the-four-seasons-2025-poster.jpg","backdrop":"assets/tv-the-four-seasons-2025-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-28T18:36:42.5326384Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":243316,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":81,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.892,"tmdbVotes":204}},{"id":"tv-the-get-down-2016","title":"The Get Down","year":2016,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":7.3,"criticRating":null,"genres":["Drama"],"overview":"In 1977 New York City, the talented and soulful youth of the South Bronx chase dreams and breakneck beats to transform music history.","poster":"assets/tv-the-get-down-2016-poster.jpg","backdrop":"assets/tv-the-get-down-2016-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0497737Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":65345,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":81,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.3,"tmdbVotes":196}},{"id":"tv-how-to-change-your-mind-2022","title":"How to Change Your Mind","year":2022,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":7.76,"criticRating":null,"genres":["Documentary","Mystery"],"overview":"Author Michael Pollan leads the way in this docuseries exploring the history and uses of psychedelics, including LSD, psilocybin, MDMA and mescaline.","poster":"assets/tv-how-to-change-your-mind-2022-poster.jpg","backdrop":"assets/tv-how-to-change-your-mind-2022-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0601399Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":204304,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.8,"tmdbVotes":53}},{"id":"tv-interrogation-2020","title":"Interrogation","year":2020,"type":"tv","runtimeSeconds":2700,"seasonCount":1,"communityRating":6.788,"criticRating":null,"genres":["Drama","Crime"],"overview":"Based on a true story that spanned more than 30 years in which a young man was charged and convicted of brutally murdering his mother. Each episode is structured around an interrogation taken directly from the real\u2026","poster":"assets/tv-interrogation-2020-poster.jpg","backdrop":"assets/tv-interrogation-2020-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-26T05:52:06.1068207Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":96488,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":57,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.9,"tmdbVotes":54}},{"id":"tv-it-s-always-sunny-in-philadelphia-2005","title":"It's Always Sunny in Philadelphia","year":2005,"type":"tv","runtimeSeconds":null,"seasonCount":18,"communityRating":8.2,"criticRating":null,"genres":["Comedy"],"overview":"Four egocentric friends run a neighborhood Irish pub in Philadelphia and try to find their way through the adult world of work and relationships. Unfortunately, their warped views and precarious judgments often lead\u2026","poster":"assets/tv-it-s-always-sunny-in-philadelphia-2005-poster.jpg","backdrop":"assets/tv-it-s-always-sunny-in-philadelphia-2005-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0485774Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":2710,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":94,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.253,"tmdbVotes":1457}},{"id":"tv-a-knight-of-the-seven-kingdoms-2026","title":"A Knight of the Seven Kingdoms","year":2026,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":8.431,"criticRating":null,"genres":["Drama","Sci-Fi & Fantasy","Action & Adventure"],"overview":"A century before the events of Game of Thrones, two unlikely heroes wandered Westeros: a young, naive but courageous knight, Ser Duncan the Tall, and his diminutive squire, Egg. Set in an age when the Targaryen line\u2026","poster":"assets/tv-a-knight-of-the-seven-kingdoms-2026-poster.jpg","backdrop":"assets/tv-a-knight-of-the-seven-kingdoms-2026-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0493344Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":224372,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":94,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.4,"tmdbVotes":1266}},{"id":"tv-landman-2024","title":"Landman","year":2024,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":8.194,"criticRating":null,"genres":["Drama"],"overview":"Set in the proverbial boomtowns of West-Texas and a modern-day tale of fortune-seeking in the world of oil rigs, the series is an upstairs/downstairs story of roughnecks and wildcat billionaires that are fueling a\u2026","poster":"assets/tv-landman-2024-poster.jpg","backdrop":"assets/tv-landman-2024-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-22T21:38:18.0973875Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":157741,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":80,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.209,"tmdbVotes":668}},{"id":"tv-the-last-of-us-2023","title":"The Last of Us","year":2023,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":8.419,"criticRating":null,"genres":["Drama"],"overview":"Twenty years after modern civilization has been destroyed, Joel, a hardened survivor, is hired to smuggle Ellie, a 14-year-old girl, out of an oppressive quarantine zone. What starts as a small job soon becomes a\u2026","poster":"assets/tv-the-last-of-us-2023-poster.jpg","backdrop":"assets/tv-the-last-of-us-2023-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0640955Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":100088,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":94,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.4,"tmdbVotes":7485}},{"id":"tv-last-samurai-standing-2025","title":"Last Samurai Standing","year":2025,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":7.805,"criticRating":null,"genres":["Action & Adventure","Drama"],"overview":"In the early Meiji era, Shujiro, once known as an undefeated samurai, decides to participate in a deadly survival game to save his family and villagers.","poster":"assets/tv-last-samurai-standing-2025-poster.jpg","backdrop":"assets/tv-last-samurai-standing-2025-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0622526Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":252193,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.812,"tmdbVotes":271}},{"id":"tv-lord-of-the-flies-2026","title":"Lord of the Flies","year":2026,"type":"tv","runtimeSeconds":3480,"seasonCount":1,"communityRating":7.571,"criticRating":null,"genres":["Drama","Action & Adventure"],"overview":"After a plane crash, a group of schoolboys find themselves stranded on a tropical island without adults. Ralph is elected leader and, with the help of the intelligent Piggy, strives to maintain order and\u2026","poster":"assets/tv-lord-of-the-flies-2026-poster.jpg","backdrop":"assets/tv-lord-of-the-flies-2026-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0645648Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":270572,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":91,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.58,"tmdbVotes":138}},{"id":"tv-the-lord-of-the-rings-the-rings-of-power-2022","title":"The Lord of the Rings: The Rings of Power","year":2022,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":7.233,"criticRating":null,"genres":["Action & Adventure","Sci-Fi & Fantasy","Drama"],"overview":"Beginning in a time of relative peace, we follow an ensemble cast of characters as they confront the re-emergence of evil to Middle-earth. From the darkest depths of the Misty Mountains, to the majestic forests of\u2026","poster":"assets/tv-the-lord-of-the-rings-the-rings-of-power-2022-poster.jpg","backdrop":"assets/tv-the-lord-of-the-rings-the-rings-of-power-2022-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0618904Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":84773,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":84,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.211,"tmdbVotes":4003}},{"id":"tv-love-death-robots-2019","title":"Love, Death & Robots","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":4,"communityRating":8.21,"criticRating":null,"genres":["Animation","Sci-Fi & Fantasy"],"overview":"Terrifying creatures, wicked surprises and dark comedy converge in this NSFW anthology of animated stories presented by Tim Miller and David Fincher.","poster":"assets/tv-love-death-robots-2019-poster.jpg","backdrop":"assets/tv-love-death-robots-2019-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0460964Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":86831,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":89,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.203,"tmdbVotes":4238}},{"id":"tv-maniac-2018","title":"Maniac","year":2018,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":7.338,"criticRating":null,"genres":["Comedy","Drama","Sci-Fi & Fantasy"],"overview":"Two strangers are drawn to a mysterious pharmaceutical trial that will, they're assured, with no complications or side-effects whatsoever, solve all of their problems, permanently. Things do not go as planned.","poster":"assets/tv-maniac-2018-poster.jpg","backdrop":"assets/tv-maniac-2018-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-20T19:42:30.955548Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":73411,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":84,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.323,"tmdbVotes":1073}},{"id":"tv-mussolini-son-of-the-century-2024","title":"Mussolini: Son of the Century","year":2024,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":8.135,"criticRating":null,"genres":["Drama","War & Politics"],"overview":"The rise of Benito Mussolini and the birth of fascism in Italy, chronicling a country\u2019s surrender to dictatorship and the relentless ascent of a man who rose from his ashes time and again.","poster":"assets/tv-mussolini-son-of-the-century-2024-poster.jpg","backdrop":"assets/tv-mussolini-son-of-the-century-2024-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0586588Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":212333,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":96,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.1,"tmdbVotes":179}},{"id":"tv-the-night-manager-2016","title":"The Night Manager","year":2016,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":7.74,"criticRating":null,"genres":["Drama","Mystery","Crime"],"overview":"Former British soldier Jonathan Pine navigates the shadowy recesses of Whitehall and Washington where an unholy alliance operates between the intelligence community and the secret arms trade. To infiltrate the inner\u2026","poster":"assets/tv-the-night-manager-2016-poster.jpg","backdrop":"assets/tv-the-night-manager-2016-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0663672Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":61859,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":88,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.7,"tmdbVotes":1422}},{"id":"tv-one-piece-2023","title":"ONE PIECE","year":2023,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":8.118,"criticRating":null,"genres":["Action & Adventure","Sci-Fi & Fantasy"],"overview":"With his straw hat and ragtag crew, young pirate Monkey D. Luffy goes on an epic voyage for treasure.","poster":"assets/tv-one-piece-2023-poster.jpg","backdrop":"assets/tv-one-piece-2023-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0439378Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":111110,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":93,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.104,"tmdbVotes":1988}},{"id":"tv-only-murders-in-the-building-2021","title":"Only Murders in the Building","year":2021,"type":"tv","runtimeSeconds":null,"seasonCount":5,"communityRating":8.438,"criticRating":null,"genres":["Comedy","Mystery","Crime"],"overview":"Three strangers share an obsession with true crime and suddenly find themselves wrapped up in one.","poster":"assets/tv-only-murders-in-the-building-2021-poster.jpg","backdrop":"assets/tv-only-murders-in-the-building-2021-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0594614Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":107113,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":95,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.398,"tmdbVotes":2333}},{"id":"tv-over-the-garden-wall-2014","title":"Over the Garden Wall","year":2014,"type":"tv","runtimeSeconds":720,"seasonCount":1,"communityRating":8.6,"criticRating":null,"genres":["Mystery","Sci-Fi & Fantasy","Animation"],"overview":"Two brothers, Wirt and Greg, find themselves lost in the Unknown; a strange forest adrift in time. With the help of a wise old Woodsman and a foul-tempered bluebird named Beatrice, Wirt and Greg must travel across\u2026","poster":"assets/tv-over-the-garden-wall-2014-poster.jpg","backdrop":"assets/tv-over-the-garden-wall-2014-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0455757Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":61617,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.6,"tmdbVotes":1854}},{"id":"tv-peaky-blinders-2013","title":"Peaky Blinders","year":2013,"type":"tv","runtimeSeconds":null,"seasonCount":6,"communityRating":8.5,"criticRating":null,"genres":["Drama","Crime"],"overview":"A gangster family epic set in 1919 Birmingham, England and centered on a gang who sew razor blades in the peaks of their caps, and their fierce boss Tommy Shelby, who means to move up in the world.","poster":"assets/tv-peaky-blinders-2013-poster.jpg","backdrop":"assets/tv-peaky-blinders-2013-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0539185Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":60574,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":93,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.5,"tmdbVotes":11506}},{"id":"tv-the-pitt-2025","title":"The Pitt","year":2025,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":8.729,"criticRating":null,"genres":["Drama"],"overview":"The staff of Pittsburgh's Trauma Medical Center work around the clock to save lives in an overcrowded and underfunded emergency department.","poster":"assets/tv-the-pitt-2025-poster.jpg","backdrop":"assets/tv-the-pitt-2025-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0582942Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":250307,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":96,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.731,"tmdbVotes":1046}},{"id":"tv-pluribus-2025","title":"Pluribus","year":2025,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":7.936,"criticRating":null,"genres":["Drama","Sci-Fi & Fantasy"],"overview":"The most miserable person on Earth must save the world from happiness.","poster":"assets/tv-pluribus-2025-poster.jpg","backdrop":"assets/tv-pluribus-2025-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0674462Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":225171,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":99,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.921,"tmdbVotes":1191}},{"id":"tv-ripley-2024","title":"RIPLEY","year":2024,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":7.911,"criticRating":null,"genres":["Drama"],"overview":"A grifter in 1960s New York is hired to convince a wealthy man's son to return home from Italy and begins a life of deceit, fraud and murder.","poster":"assets/tv-ripley-2024-poster.jpg","backdrop":"assets/tv-ripley-2024-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0658942Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":94028,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":86,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.909,"tmdbVotes":453}},{"id":"tv-say-nothing-2024","title":"Say Nothing","year":2024,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":7.462,"criticRating":null,"genres":["Drama","Crime"],"overview":"Through the eyes of various Irish Republican Army (IRA) members, explore the extremes some people will go to in the name of their beliefs, the way a deeply divided society can suddenly tip over into armed conflict,\u2026","poster":"assets/tv-say-nothing-2024-poster.jpg","backdrop":"assets/tv-say-nothing-2024-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0499752Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":245256,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":94,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.475,"tmdbVotes":122}},{"id":"tv-severance-2022","title":"Severance","year":2022,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":8.396,"criticRating":null,"genres":["Drama","Mystery","Sci-Fi & Fantasy"],"overview":"Mark leads a team of office workers whose memories have been surgically divided between their work and personal lives. When a mysterious colleague appears outside of work, it begins a journey to discover the truth\u2026","poster":"assets/tv-severance-2022-poster.jpg","backdrop":"assets/tv-severance-2022-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0598478Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":95396,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":95,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.389,"tmdbVotes":3095}},{"id":"tv-six-feet-under-2001","title":"Six Feet Under","year":2001,"type":"tv","runtimeSeconds":null,"seasonCount":5,"communityRating":8.115,"criticRating":null,"genres":["Drama"],"overview":"When death is your business, what is your life? For the Fisher family, the world outside of their family-owned funeral home continues to be at least as challenging as\u2014and far less predictable than\u2014the one inside.","poster":"assets/tv-six-feet-under-2001-poster.jpg","backdrop":"assets/tv-six-feet-under-2001-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-26T04:04:05.108787Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":1274,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":81,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.1,"tmdbVotes":1192}},{"id":"tv-undercover-2019","title":"Undercover","year":2019,"type":"tv","runtimeSeconds":3000,"seasonCount":3,"communityRating":7.5,"criticRating":null,"genres":["Crime","Drama"],"overview":"Undercover agents infiltrate a drug kingpin's operation by posing as a couple at the campground where he spends his weekends. Inspired by real events.","poster":"assets/tv-undercover-2019-poster.jpg","backdrop":"assets/tv-undercover-2019-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0570153Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":86942,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.5,"tmdbVotes":186}},{"id":"tv-upload-2020","title":"Upload","year":2020,"type":"tv","runtimeSeconds":null,"seasonCount":4,"communityRating":7.781,"criticRating":null,"genres":["Comedy","Sci-Fi & Fantasy","Drama"],"overview":"In 2033, people who are near death can be \u201cuploaded\u201d into virtual reality hotels run by 6 tech firms. Cash-strapped Nora lives in Brooklyn and works customer service for the luxurious \u201cLakeview\u201d digital afterlife.\u2026","poster":"assets/tv-upload-2020-poster.jpg","backdrop":"assets/tv-upload-2020-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0566967Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":86248,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":87,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.757,"tmdbVotes":1511}},{"id":"tv-the-walk-in-2022","title":"The Walk-In","year":2022,"type":"tv","runtimeSeconds":2760,"seasonCount":1,"communityRating":6.9,"criticRating":null,"genres":["Drama","Crime"],"overview":"Forced to flee the UK and go into hiding in the 1990s, when he became a mole from within the BNP, Matthew Collins returned to Britain to make a new life for himself, working with young white men in the fight against\u2026","poster":"assets/tv-the-walk-in-2022-poster.jpg","backdrop":"assets/tv-the-walk-in-2022-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0654569Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":210664,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":80,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7,"tmdbVotes":50}},{"id":"tv-the-white-lotus-2021","title":"The White Lotus","year":2021,"type":"tv","runtimeSeconds":null,"seasonCount":3,"communityRating":7.596,"criticRating":null,"genres":["Comedy","Drama","Mystery"],"overview":"Follow the exploits of various guests and employees at an exclusive tropical resort over the span of a week as with each passing day, a darker complexity emerges in these picture-perfect travelers, the hotel\u2019s\u2026","poster":"assets/tv-the-white-lotus-2021-poster.jpg","backdrop":"assets/tv-the-white-lotus-2021-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0546438Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":111803,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":90,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.599,"tmdbVotes":1604}},{"id":"tv-widow-s-bay-2026","title":"Widow's Bay","year":2026,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":8.172,"criticRating":null,"genres":["Drama","Comedy","Mystery"],"overview":"The mayor of a New England town resolves to turn it into the next tourist hot spot, despite local warnings that it's cursed.","poster":"assets/tv-widow-s-bay-2026-poster.jpg","backdrop":"assets/tv-widow-s-bay-2026-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-20T10:27:12.7003979Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":270476,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":98,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8,"tmdbVotes":585}},{"id":"tv-the-witcher-2019","title":"The Witcher","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":4,"communityRating":7.905,"criticRating":null,"genres":["Drama","Action & Adventure"],"overview":"Geralt of Rivia, a mutated monster-hunter for hire, journeys toward his destiny in a turbulent world where people often prove more wicked than beasts.","poster":"assets/tv-the-witcher-2019-poster.jpg","backdrop":"assets/tv-the-witcher-2019-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0552369Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":71912,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":75,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.88,"tmdbVotes":6997}},{"id":"tv-yellowjackets-2021","title":"Yellowjackets","year":2021,"type":"tv","runtimeSeconds":null,"seasonCount":3,"communityRating":7.449,"criticRating":null,"genres":["Drama","Mystery"],"overview":"This equal parts survival epic, psychological horror story and coming-of-age drama tells the saga of a team of wildly talented high school girls soccer players who become the (un)lucky survivors of a plane crash deep\u2026","poster":"assets/tv-yellowjackets-2021-poster.jpg","backdrop":"assets/tv-yellowjackets-2021-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0577612Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":117488,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":92,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.431,"tmdbVotes":1070}}],"anime":[],"discover":[{"id":"movie-12-years-a-slave-2013","title":"12 Years a Slave","year":2013,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","History"],"overview":"In the pre-Civil War United States, Solomon Northup, a free black man from upstate New York, is abducted and sold into slavery. Facing cruelty as well as unexpected kindnesses Solomon struggles not only to stay\u2026","poster":"assets/movie-12-years-a-slave-2013-poster.jpg","backdrop":"assets/movie-12-years-a-slave-2013-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":76203,"ratings":{"rtCritics":95,"rtCriticsLabel":"Certified Fresh","rtAudience":90,"rtAudienceLabel":"Upright","imdb":8.1,"imdbVotes":796313,"tmdb":7.927,"tmdbVotes":12335}},{"id":"movie-101-dalmatians-ii-patch-s-london-adventure-2003","title":"101 Dalmatians II: Patch's London Adventure","year":2003,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Family","Animation","Adventure"],"overview":"Being one of 101 takes its toll on Patch, who doesn't feel unique. When he's accidentally left behind on moving day, he meets his idol, Thunderbolt, who enlists him on a publicity campaign.","poster":"assets/movie-101-dalmatians-ii-patch-s-london-adventure-2003-poster.jpg","backdrop":"assets/movie-101-dalmatians-ii-patch-s-london-adventure-2003-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":13654,"ratings":{"rtCritics":67,"rtCriticsLabel":"Fresh","rtAudience":41,"rtAudienceLabel":"Spilled","imdb":5.7,"imdbVotes":12343,"tmdb":6.025,"tmdbVotes":1274}},{"id":"movie-absolution-2024","title":"Absolution","year":2024,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Crime","Thriller"],"overview":"An aging ex-boxer gangster working as muscle for a Boston crime boss receives an upsetting diagnosis. Despite a faltering memory, he attempts to rectify the sins of his past and reconnect with his estranged\u2026","poster":"assets/movie-absolution-2024-poster.jpg","backdrop":"assets/movie-absolution-2024-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":974453,"ratings":{"rtCritics":56,"rtCriticsLabel":"Rotten","rtAudience":32,"rtAudienceLabel":"Spilled","imdb":5.2,"imdbVotes":11413,"tmdb":5.906,"tmdbVotes":564}},{"id":"movie-addicted-2014","title":"Addicted","year":2014,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Thriller"],"overview":"A gallerist risks her family and flourishing career when she enters into an affair with a talented painter and slowly loses control of her life.","poster":"assets/movie-addicted-2014-poster.jpg","backdrop":"assets/movie-addicted-2014-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":235271,"ratings":{"rtCritics":7,"rtCriticsLabel":"Rotten","rtAudience":51,"rtAudienceLabel":"Spilled","imdb":5,"imdbVotes":13131,"tmdb":5.928,"tmdbVotes":466}},{"id":"movie-all-the-money-in-the-world-2017","title":"All the Money in the World","year":2017,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Crime","History","Thriller"],"overview":"The story of the kidnapping of 16-year-old John Paul Getty III and the desperate attempt by his devoted mother to convince his billionaire grandfather Jean Paul Getty to pay the ransom.","poster":"assets/movie-all-the-money-in-the-world-2017-poster.jpg","backdrop":"assets/movie-all-the-money-in-the-world-2017-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":446791,"ratings":{"rtCritics":79,"rtCriticsLabel":"Certified Fresh","rtAudience":66,"rtAudienceLabel":"Upright","imdb":6.8,"imdbVotes":97448,"tmdb":6.493,"tmdbVotes":2493}},{"id":"movie-the-alto-knights-2025","title":"The Alto Knights","year":2025,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Crime","Drama"],"overview":"Two of New York's most notorious organized crime bosses, Frank Costello and Vito Genovese, vie for control of the city's streets. Once the best of friends, petty jealousies and a series of betrayals place them on a\u2026","poster":"assets/movie-the-alto-knights-2025-poster.jpg","backdrop":"assets/movie-the-alto-knights-2025-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1013601,"ratings":{"rtCritics":39,"rtCriticsLabel":"Rotten","rtAudience":71,"rtAudienceLabel":"Upright","imdb":5.9,"imdbVotes":23017,"tmdb":6.223,"tmdbVotes":485}},{"id":"movie-the-amazing-spider-man-2-2014","title":"The Amazing Spider-Man 2","year":2014,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"For Peter Parker, life is busy. Between taking out the bad guys as Spider-Man and spending time with the person he loves, Gwen Stacy, high school graduation cannot come quickly enough. Peter has not forgotten about\u2026","poster":"assets/movie-the-amazing-spider-man-2-2014-poster.jpg","backdrop":"assets/movie-the-amazing-spider-man-2-2014-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":102382,"ratings":{"rtCritics":51,"rtCriticsLabel":"Rotten","rtAudience":64,"rtAudienceLabel":"Upright","imdb":6.6,"imdbVotes":611981,"tmdb":6.567,"tmdbVotes":14919}},{"id":"movie-ant-man-and-the-wasp-quantumania-2023","title":"Ant-Man and the Wasp: Quantumania","year":2023,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"Super-Hero partners Scott Lang and Hope van Dyne, along with with Hope's parents Janet van Dyne and Hank Pym, and Scott's daughter Cassie Lang, find themselves exploring the Quantum Realm, interacting with strange\u2026","poster":"assets/movie-ant-man-and-the-wasp-quantumania-2023-poster.jpg","backdrop":"assets/movie-ant-man-and-the-wasp-quantumania-2023-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":640146,"ratings":{"rtCritics":46,"rtCriticsLabel":"Rotten","rtAudience":81,"rtAudienceLabel":"Upright","imdb":6,"imdbVotes":281738,"tmdb":6.197,"tmdbVotes":6236}},{"id":"movie-arctic-dogs-2019","title":"Arctic Dogs","year":2019,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Adventure","Comedy"],"overview":"Animals band together to save the day when the evil Otto Von Walrus hatches a sinister scheme to accelerate global warming and melt the Arctic Circle.","poster":"assets/movie-arctic-dogs-2019-poster.jpg","backdrop":"assets/movie-arctic-dogs-2019-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":416153,"ratings":{"rtCritics":13,"rtCriticsLabel":"Rotten","rtAudience":60,"rtAudienceLabel":"Upright","imdb":4.9,"imdbVotes":2580,"tmdb":5.9,"tmdbVotes":148}},{"id":"movie-the-avengers-2012","title":"The Avengers","year":2012,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Science Fiction","Action","Adventure"],"overview":"When an unexpected enemy emerges and threatens global safety and security, Nick Fury, director of the international peacekeeping agency known as S.H.I.E.L.D., finds himself in need of a team to pull the world back\u2026","poster":"assets/movie-the-avengers-2012-poster.jpg","backdrop":"assets/movie-the-avengers-2012-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":24428,"ratings":{"rtCritics":91,"rtCriticsLabel":"Certified Fresh","rtAudience":91,"rtAudienceLabel":"Upright","imdb":8,"imdbVotes":1590693,"tmdb":8.084,"tmdbVotes":40262}},{"id":"movie-black-bear-2020","title":"Black Bear","year":2020,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Thriller"],"overview":"At a remote lake house in the Adirondack Mountains, a couple entertains an out-of-town guest looking for inspiration in her filmmaking. The group quickly falls into a calculated game of desire, manipulation, and\u2026","poster":"assets/movie-black-bear-2020-poster.jpg","backdrop":"assets/movie-black-bear-2020-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":624788,"ratings":{"rtCritics":89,"rtCriticsLabel":"Certified Fresh","rtAudience":64,"rtAudienceLabel":"Upright","imdb":6.5,"imdbVotes":18408,"tmdb":6.337,"tmdbVotes":315}},{"id":"movie-black-panther-2018","title":"Black Panther","year":2018,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"King T'Challa returns home to the reclusive, technologically advanced African nation of Wakanda to serve as his country's new leader. However, T'Challa soon finds that he is challenged for the throne by factions\u2026","poster":"assets/movie-black-panther-2018-poster.jpg","backdrop":"assets/movie-black-panther-2018-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":284054,"ratings":{"rtCritics":96,"rtCriticsLabel":"Certified Fresh","rtAudience":null,"rtAudienceLabel":"Spilled","imdb":7.3,"imdbVotes":931120,"tmdb":7.36,"tmdbVotes":24190}},{"id":"movie-a-bronx-tale-1993","title":"A Bronx Tale","year":1993,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Crime"],"overview":"Set in the Bronx during the tumultuous 1960s, an adolescent boy is torn between his honest, working-class father and a violent yet charismatic crime boss. Complicating matters is the youngster's growing attraction -\u2026","poster":"assets/movie-a-bronx-tale-1993-poster.jpg","backdrop":"assets/movie-a-bronx-tale-1993-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1607,"ratings":{"rtCritics":97,"rtCriticsLabel":"Fresh","rtAudience":92,"rtAudienceLabel":"Upright","imdb":7.8,"imdbVotes":191930,"tmdb":7.913,"tmdbVotes":3075}},{"id":"movie-by-any-means-2026","title":"By Any Means","year":2026,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Thriller","History","Crime"],"overview":"In 1960s Mississippi, a young Black FBI agent is forced to partner with a notorious mafia hitman to investigate a wave of brutal civil rights murders.","poster":"assets/movie-by-any-means-2026-poster.jpg","backdrop":"assets/movie-by-any-means-2026-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1380417,"ratings":{"rtCritics":49,"rtCriticsLabel":"Rotten","rtAudience":88,"rtAudienceLabel":"Upright","imdb":6.8,"imdbVotes":3534,"tmdb":6.6,"tmdbVotes":92}},{"id":"movie-captain-america-civil-war-2016","title":"Captain America: Civil War","year":2016,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Adventure","Action","Science Fiction"],"overview":"Following the events of Age of Ultron, the collective governments of the world pass an act designed to regulate all superhuman activity. This polarizes opinion amongst the Avengers, causing two factions to side with\u2026","poster":"assets/movie-captain-america-civil-war-2016-poster.jpg","backdrop":"assets/movie-captain-america-civil-war-2016-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":271110,"ratings":{"rtCritics":90,"rtCriticsLabel":"Certified Fresh","rtAudience":89,"rtAudienceLabel":"Upright","imdb":7.8,"imdbVotes":954943,"tmdb":7.455,"tmdbVotes":24808}},{"id":"movie-captain-america-the-first-avenger-2011","title":"Captain America: The First Avenger","year":2011,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"During World War II, Steve Rogers is a sickly man from Brooklyn who's transformed into super-soldier Captain America to aid in the war effort. Rogers must stop the Red Skull \u2013 Adolf Hitler's ruthless head of\u2026","poster":"assets/movie-captain-america-the-first-avenger-2011-poster.jpg","backdrop":"assets/movie-captain-america-the-first-avenger-2011-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1771,"ratings":{"rtCritics":80,"rtCriticsLabel":"Certified Fresh","rtAudience":75,"rtAudienceLabel":"Upright","imdb":6.9,"imdbVotes":993453,"tmdb":7.012,"tmdbVotes":23473}},{"id":"movie-captain-america-the-winter-soldier-2014","title":"Captain America: The Winter Soldier","year":2014,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"After the cataclysmic events in New York with The Avengers, Steve Rogers, aka Captain America is living quietly in Washington, D.C. and trying to adjust to the modern world. But when a S.H.I.E.L.D. colleague comes\u2026","poster":"assets/movie-captain-america-the-winter-soldier-2014-poster.jpg","backdrop":"assets/movie-captain-america-the-winter-soldier-2014-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":100402,"ratings":{"rtCritics":90,"rtCriticsLabel":"Certified Fresh","rtAudience":92,"rtAudienceLabel":"Upright","imdb":7.7,"imdbVotes":995514,"tmdb":7.654,"tmdbVotes":20688}},{"id":"movie-careful-what-you-wish-for-2015","title":"Careful What You Wish For","year":2015,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Thriller"],"overview":"A guy gets more than he bargained for after entering into an affair with the wife of an investment banker. Soon, a suspicious death and substantial life insurance policy embroil him in a scandal.","poster":"assets/movie-careful-what-you-wish-for-2015-poster.jpg","backdrop":"assets/movie-careful-what-you-wish-for-2015-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":317744,"ratings":{"rtCritics":17,"rtCriticsLabel":"Rotten","rtAudience":61,"rtAudienceLabel":"Upright","imdb":5.6,"imdbVotes":9452,"tmdb":6.129,"tmdbVotes":446}},{"id":"tv-12-monkeys-2015","title":"12 Monkeys","year":2015,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Sci-Fi & Fantasy","Drama"],"overview":"The provocative story of Cole, a time traveler from a decimated future in a high-stakes race against the clock. Utilizing a dangerous and untested method of time travel, he journeys from 2043 to the present day on a\u2026","poster":"assets/tv-12-monkeys-2015-poster.jpg","backdrop":"assets/tv-12-monkeys-2015-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":60948,"ratings":{"rtCritics":88,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.441,"tmdbVotes":1245}},{"id":"tv-90-day-fiance-before-the-90-days-2017","title":"90 Day Fianc\u00e9: Before the 90 Days","year":2017,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Reality"],"overview":"Follow couples who have an existing relationship online, but haven't met in person. We'll experience their journey as they travel to the other's foreign country for the first time in an attempt to establish an\u2026","poster":"assets/tv-90-day-fiance-before-the-90-days-2017-poster.jpg","backdrop":"assets/tv-90-day-fiance-before-the-90-days-2017-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":73319,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.5,"tmdbVotes":45}},{"id":"tv-90-day-fiance-the-other-way-2019","title":"90 Day Fianc\u00e9: The Other Way","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Reality"],"overview":"Americans move to a foreign country all in the name of love. Will uprooting their lives in the United States pay off, or will they be packing up and moving back to America brokenhearted?","poster":"assets/tv-90-day-fiance-the-other-way-2019-poster.jpg","backdrop":"assets/tv-90-day-fiance-the-other-way-2019-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":90046,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.8,"tmdbVotes":34}},{"id":"tv-the-100-2014","title":"The 100","year":2014,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Sci-Fi & Fantasy","Action & Adventure","Drama"],"overview":"100 years in the future, when the Earth has been abandoned due to radioactivity, the last surviving humans live on an ark orbiting the planet \u2014 but the ark won't last forever. So the repressive regime picks 100\u2026","poster":"assets/tv-the-100-2014-poster.jpg","backdrop":"assets/tv-the-100-2014-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":48866,"ratings":{"rtCritics":93,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.878,"tmdbVotes":8855}},{"id":"tv-accused-2023","title":"Accused","year":2023,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Crime","Drama"],"overview":"In this crime anthology series, viewers discover how an ordinary person got caught up in an extraordinary situation, ultimately revealing how one wrong turn leads to another, until it\u2019s too late to turn back. Told\u2026","poster":"assets/tv-accused-2023-poster.jpg","backdrop":"assets/tv-accused-2023-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":202097,"ratings":{"rtCritics":61,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.851,"tmdbVotes":87}},{"id":"tv-after-life-2019","title":"After Life","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy","Drama"],"overview":"Tony had a perfect life. But after his wife Lisa suddenly dies, Tony changes. After contemplating taking his own life, he decides instead to live long enough to punish the world by saying and doing whatever he likes\u2026","poster":"assets/tv-after-life-2019-poster.jpg","backdrop":"assets/tv-after-life-2019-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":79410,"ratings":{"rtCritics":72,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.902,"tmdbVotes":1169}},{"id":"tv-all-creatures-great-and-small-1978","title":"All Creatures Great and Small","year":1978,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy","Drama"],"overview":"The trials and misadventures of the staff at a country veterinary office in Yorkshire. James Herriot, a young animal surgeon, moves to a small Yorkshire town to begin his first job.","poster":"assets/tv-all-creatures-great-and-small-1978-poster.jpg","backdrop":"assets/tv-all-creatures-great-and-small-1978-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"center_crop","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":7406,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.8,"tmdbVotes":50}},{"id":"tv-american-housewife-2016","title":"American Housewife","year":2016,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy"],"overview":"A family comedy narrated by Katie, a strong-willed mother, raising her flawed family in a wealthy town filled with perfect wives and their perfect offspring.","poster":"assets/tv-american-housewife-2016-poster.jpg","backdrop":"assets/tv-american-housewife-2016-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":67117,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.7,"tmdbVotes":187}},{"id":"tv-atlantis-2013","title":"Atlantis","year":2013,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action & Adventure","Sci-Fi & Fantasy"],"overview":"A fantasy drama set in a world of legendary heroes and mythical creatures. Far from home and desperate for answers, Jason washes up on the shores of an ancient land. A mysterious place; a world of bull leaping, of\u2026","poster":"assets/tv-atlantis-2013-poster.jpg","backdrop":"assets/tv-atlantis-2013-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":47054,"ratings":{"rtCritics":62,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.4,"tmdbVotes":155}},{"id":"tv-avatar-the-last-airbender-2024","title":"Avatar: The Last Airbender","year":2024,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action & Adventure","Sci-Fi & Fantasy","Drama"],"overview":"A young boy known as the Avatar must master the four elemental powers to save a world at war \u2014 and fight a ruthless enemy bent on stopping him.","poster":"assets/tv-avatar-the-last-airbender-2024-poster.jpg","backdrop":"assets/tv-avatar-the-last-airbender-2024-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":82452,"ratings":{"rtCritics":66,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.8,"tmdbVotes":1406}},{"id":"tv-avatar-seven-havens-2026","title":"Avatar: Seven Havens","year":2026,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"In a world shattered by a devastating cataclysm, a young Earthbender discovers she's the new Avatar after Korra. But in this dangerous era, that title marks her as humanity's destroyer, not its savior. Hunted by both\u2026","poster":"assets/tv-avatar-seven-havens-2026-poster.jpg","backdrop":"assets/tv-avatar-seven-havens-2026-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":284833,"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.9,"tmdbVotes":183}},{"id":"tv-batman-the-brave-and-the-bold-2008","title":"Batman: The Brave and the Bold","year":2008,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"The Caped Crusader is teamed up with Blue Beetle, Green Arrow, Aquaman and countless others in his quest to uphold justice.","poster":"assets/tv-batman-the-brave-and-the-bold-2008-poster.jpg","backdrop":"assets/tv-batman-the-brave-and-the-bold-2008-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":15804,"ratings":{"rtCritics":96,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.6,"tmdbVotes":295}},{"id":"tv-beat-bobby-flay-2013","title":"Beat Bobby Flay","year":2013,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Reality"],"overview":"Two talented chefs go head-to-head for the chance to Beat Bobby Flay. To get to Bobby the chefs must first face off against each other, creating a spectacular dish with a secret ingredient of Bobby's choice. Judges\u2026","poster":"assets/tv-beat-bobby-flay-2013-poster.jpg","backdrop":"assets/tv-beat-bobby-flay-2013-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":62481,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.5,"tmdbVotes":31}},{"id":"tv-benson-1979","title":"Benson","year":1979,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy"],"overview":"A butler deals with life at the governor's mansion.","poster":"assets/tv-benson-1979-poster.jpg","backdrop":"assets/tv-benson-1979-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1849,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7,"tmdbVotes":46}},{"id":"tv-black-rabbit-2025","title":"Black Rabbit","year":2025,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Crime"],"overview":"A rising-star restaurateur is forced into New York's criminal underworld when his chaotic brother returns to town with loan sharks on his trail.","poster":"assets/tv-black-rabbit-2025-poster.jpg","backdrop":"assets/tv-black-rabbit-2025-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":249039,"ratings":{"rtCritics":66,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.983,"tmdbVotes":240}},{"id":"tv-black-ish-2014","title":"black-ish","year":2014,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy"],"overview":"A family man struggles to gain a sense of cultural identity while raising his kids in a predominantly white, upper-middle-class neighborhood.","poster":"assets/tv-black-ish-2014-poster.jpg","backdrop":"assets/tv-black-ish-2014-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":61381,"ratings":{"rtCritics":92,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.1,"tmdbVotes":352}},{"id":"tv-breaking-bad-2008","title":"Breaking Bad","year":2008,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Crime"],"overview":"Walter White, a New Mexico chemistry teacher, is diagnosed with Stage III cancer and given a prognosis of only two years left to live. He becomes filled with a sense of fearlessness and an unrelenting desire to\u2026","poster":"assets/tv-breaking-bad-2008-poster.jpg","backdrop":"assets/tv-breaking-bad-2008-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"center_crop","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1396,"ratings":{"rtCritics":96,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.959,"tmdbVotes":19030}},{"id":"tv-the-capture-2019","title":"The Capture","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Crime","Drama","Mystery"],"overview":"When soldier Shaun Emery's conviction for a murder in Afghanistan is overturned due to flawed video evidence, he returns to life as a free man with his young daughter. But when damning CCTV footage from a night out\u2026","poster":"assets/tv-the-capture-2019-poster.jpg","backdrop":"assets/tv-the-capture-2019-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":93166,"ratings":{"rtCritics":97,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.634,"tmdbVotes":361}}]}],"seeAll":{"trending":[{"id":"tv-american-gods-2017","title":"American Gods","year":2017,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Mystery","Sci-Fi & Fantasy"],"overview":"An ex-con becomes the traveling partner of a conman who turns out to be one of the older gods trying to recruit troops to battle the upstart deities. Based on Neil Gaiman's fantasy novel.","poster":"assets/tv-american-gods-2017-poster.jpg","backdrop":"assets/tv-american-gods-2017-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":46639,"ratings":{"rtCritics":75,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.1,"tmdbVotes":1852}},{"id":"tv-avatar-seven-havens-2026","title":"Avatar: Seven Havens","year":2026,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"In a world shattered by a devastating cataclysm, a young Earthbender discovers she's the new Avatar after Korra. But in this dangerous era, that title marks her as humanity's destroyer, not its savior. Hunted by both\u2026","poster":"assets/tv-avatar-seven-havens-2026-poster.jpg","backdrop":"assets/tv-avatar-seven-havens-2026-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":284833,"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.9,"tmdbVotes":183}},{"id":"tv-batman-the-brave-and-the-bold-2008","title":"Batman: The Brave and the Bold","year":2008,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"The Caped Crusader is teamed up with Blue Beetle, Green Arrow, Aquaman and countless others in his quest to uphold justice.","poster":"assets/tv-batman-the-brave-and-the-bold-2008-poster.jpg","backdrop":"assets/tv-batman-the-brave-and-the-bold-2008-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":15804,"ratings":{"rtCritics":96,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.6,"tmdbVotes":295}},{"id":"tv-batwoman-2019","title":"Batwoman","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Sci-Fi & Fantasy","Action & Adventure"],"overview":"Kate Kane, armed with a passion for social justice and a flair for speaking her mind, soars onto the streets of Gotham as Batwoman, an out lesbian and highly trained street fighter primed to snuff out the failing\u2026","poster":"assets/tv-batwoman-2019-poster.jpg","backdrop":"assets/tv-batwoman-2019-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":89247,"ratings":{"rtCritics":83,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.8,"tmdbVotes":1619}},{"id":"tv-big-mouth-2017","title":"Big Mouth","year":2017,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy","Animation"],"overview":"Teenage friends find their lives upended by the wonders and horrors of puberty in this edgy comedy from real-life pals Nick Kroll and Andrew Goldberg.","poster":"assets/tv-big-mouth-2017-poster.jpg","backdrop":"assets/tv-big-mouth-2017-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":74204,"ratings":{"rtCritics":95,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.591,"tmdbVotes":1274}},{"id":"tv-black-lightning-2018","title":"Black Lightning","year":2018,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action & Adventure","Sci-Fi & Fantasy","Drama"],"overview":"Jefferson Pierce is a man wrestling with a secret. As the father of two daughters and principal of a charter high school that also serves as a safe haven for young people in a New Orleans neighborhood overrun by gang\u2026","poster":"assets/tv-black-lightning-2018-poster.jpg","backdrop":"assets/tv-black-lightning-2018-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":71663,"ratings":{"rtCritics":92,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.907,"tmdbVotes":991}},{"id":"movie-across-the-hall-2009","title":"Across the Hall","year":2009,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Thriller","Mystery"],"overview":"Convinced that his fiancee is cheating on him, a man follows her to a hotel and calls his best friend to help him avoid a calamity.","poster":"assets/movie-across-the-hall-2009-poster.jpg","backdrop":"assets/movie-across-the-hall-2009-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":21469,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":39,"rtAudienceLabel":"Spilled","imdb":5.8,"imdbVotes":5130,"tmdb":6,"tmdbVotes":129}},{"id":"movie-addicted-2014","title":"Addicted","year":2014,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Thriller"],"overview":"A gallerist risks her family and flourishing career when she enters into an affair with a talented painter and slowly loses control of her life.","poster":"assets/movie-addicted-2014-poster.jpg","backdrop":"assets/movie-addicted-2014-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":235271,"ratings":{"rtCritics":7,"rtCriticsLabel":"Rotten","rtAudience":51,"rtAudienceLabel":"Spilled","imdb":5,"imdbVotes":13131,"tmdb":5.928,"tmdbVotes":466}},{"id":"movie-adulterers-2016","title":"Adulterers","year":2016,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Thriller","Drama"],"overview":"On a steamy New Orleans afternoon, Sam Deuprey decides to surprise his beautiful wife, Ashley, for their anniversary and comes home early. But Ashley is not alone in the bedroom. She and her lover, Damien are about\u2026","poster":"assets/movie-adulterers-2016-poster.jpg","backdrop":"assets/movie-adulterers-2016-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":376004,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":37,"rtAudienceLabel":"Spilled","imdb":5.1,"imdbVotes":2144,"tmdb":6.2,"tmdbVotes":116}},{"id":"movie-alone-with-her-2006","title":"Alone With Her","year":2006,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Crime","Drama","Thriller"],"overview":"The harrowing story of a disturbed young man's attempts to win the affections of an unsuspecting young woman. When Doug first sees Amy, he instantly falls for her and begins to watch her every move, going so far as\u2026","poster":"assets/movie-alone-with-her-2006-poster.jpg","backdrop":"assets/movie-alone-with-her-2006-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":18206,"ratings":{"rtCritics":70,"rtCriticsLabel":"Fresh","rtAudience":46,"rtAudienceLabel":"Spilled","imdb":6,"imdbVotes":4359,"tmdb":5.9,"tmdbVotes":94}},{"id":"movie-awake-2007","title":"Awake","year":2007,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Thriller","Crime","Mystery"],"overview":"While undergoing heart surgery, a man experiences a phenomenon called \u2018anesthetic awareness\u2019, which leaves him awake but paralyzed throughout the operation. As various obstacles present themselves, his wife must make\u2026","poster":"assets/movie-awake-2007-poster.jpg","backdrop":"assets/movie-awake-2007-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":13483,"ratings":{"rtCritics":23,"rtCriticsLabel":"Rotten","rtAudience":55,"rtAudienceLabel":"Spilled","imdb":6.5,"imdbVotes":89389,"tmdb":6.586,"tmdbVotes":1649}},{"id":"movie-black-bear-2020","title":"Black Bear","year":2020,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Thriller"],"overview":"At a remote lake house in the Adirondack Mountains, a couple entertains an out-of-town guest looking for inspiration in her filmmaking. The group quickly falls into a calculated game of desire, manipulation, and\u2026","poster":"assets/movie-black-bear-2020-poster.jpg","backdrop":"assets/movie-black-bear-2020-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":624788,"ratings":{"rtCritics":89,"rtCriticsLabel":"Certified Fresh","rtAudience":64,"rtAudienceLabel":"Upright","imdb":6.5,"imdbVotes":18408,"tmdb":6.337,"tmdbVotes":315}},{"id":"movie-butterfly-on-a-wheel-2007","title":"Butterfly on a Wheel","year":2007,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Crime","Drama","Thriller"],"overview":"A sociopathic kidnapper methodically pushes a desperate pair of parents to their absolute breaking point.","poster":"assets/movie-butterfly-on-a-wheel-2007-poster.jpg","backdrop":"assets/movie-butterfly-on-a-wheel-2007-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":13250,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":61,"rtAudienceLabel":"Upright","imdb":6.6,"imdbVotes":35409,"tmdb":6.457,"tmdbVotes":595}},{"id":"movie-careful-what-you-wish-for-2015","title":"Careful What You Wish For","year":2015,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Thriller"],"overview":"A guy gets more than he bargained for after entering into an affair with the wife of an investment banker. Soon, a suspicious death and substantial life insurance policy embroil him in a scandal.","poster":"assets/movie-careful-what-you-wish-for-2015-poster.jpg","backdrop":"assets/movie-careful-what-you-wish-for-2015-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":317744,"ratings":{"rtCritics":17,"rtCriticsLabel":"Rotten","rtAudience":61,"rtAudienceLabel":"Upright","imdb":5.6,"imdbVotes":9452,"tmdb":6.129,"tmdbVotes":446}},{"id":"movie-crime-of-passion-1956","title":"Crime of Passion","year":1956,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Crime","Thriller"],"overview":"Kathy leaves the newspaper business to marry homicide detective Bill, but is frustrated by his lack of ambition and the banality of life in the suburbs. Her drive to advance Bill's career soon takes her down a\u2026","poster":"assets/movie-crime-of-passion-1956-poster.jpg","backdrop":"assets/movie-crime-of-passion-1956-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"center_crop","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1920,"ratings":{"rtCritics":80,"rtCriticsLabel":"Fresh","rtAudience":34,"rtAudienceLabel":"Spilled","imdb":6.4,"imdbVotes":3750,"tmdb":6.1,"tmdbVotes":57}},{"id":"movie-deep-water-2022","title":"Deep Water","year":2022,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Mystery","Thriller"],"overview":"A well-to-do husband who allows his wife to have affairs in order to avoid a divorce becomes a prime suspect in the disappearance of her lovers.","poster":"assets/movie-deep-water-2022-poster.jpg","backdrop":"assets/movie-deep-water-2022-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":619979,"ratings":{"rtCritics":35,"rtCriticsLabel":"Rotten","rtAudience":25,"rtAudienceLabel":"Spilled","imdb":5.5,"imdbVotes":74098,"tmdb":5.834,"tmdbVotes":1755}},{"id":"movie-derailed-2005","title":"Derailed","year":2005,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Thriller"],"overview":"When two married business executives having an affair are blackmailed by a violent criminal, they are forced to turn the tables on him to save their families.","poster":"assets/movie-derailed-2005-poster.jpg","backdrop":"assets/movie-derailed-2005-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":8999,"ratings":{"rtCritics":20,"rtCriticsLabel":"Rotten","rtAudience":58,"rtAudienceLabel":"Spilled","imdb":6.6,"imdbVotes":79563,"tmdb":6.405,"tmdbVotes":1193}},{"id":"movie-die-my-love-2025","title":"Die My Love","year":2025,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama"],"overview":"After inheriting a remote Montana house, Jackson moves there from New York with his partner Grace, and the couple soon welcome a child. As Jackson becomes increasingly absent and rural isolation sets in, Grace\u2026","poster":"assets/movie-die-my-love-2025-poster.jpg","backdrop":"assets/movie-die-my-love-2025-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1033148,"ratings":{"rtCritics":74,"rtCriticsLabel":"Certified Fresh","rtAudience":45,"rtAudienceLabel":"Spilled","imdb":6,"imdbVotes":50664,"tmdb":6.1,"tmdbVotes":683}},{"id":"movie-dream-house-2011","title":"Dream House","year":2011,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Mystery","Drama","Thriller"],"overview":"Publisher Will Atenton quits a lucrative job in New York to relocate his wife, Libby, and their daughters to a quaint town in New England. However, as they settle into their home the Atentons discover that a woman\u2026","poster":"assets/movie-dream-house-2011-poster.jpg","backdrop":"assets/movie-dream-house-2011-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":69668,"ratings":{"rtCritics":7,"rtCriticsLabel":"Rotten","rtAudience":36,"rtAudienceLabel":"Spilled","imdb":6,"imdbVotes":71386,"tmdb":6.212,"tmdbVotes":1480}},{"id":"movie-dream-lover-1994","title":"Dream Lover","year":1994,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Mystery","Thriller"],"overview":"Not long after they cross paths at an art gallery, architect Ray Reardon and hypnotically sensual Lena are married with children. But as strange incidents occur, Ray begins to realize he may not really know the woman\u2026","poster":"assets/movie-dream-lover-1994-poster.jpg","backdrop":"assets/movie-dream-lover-1994-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":18190,"ratings":{"rtCritics":57,"rtCriticsLabel":"Rotten","rtAudience":38,"rtAudienceLabel":"Spilled","imdb":6.2,"imdbVotes":7865,"tmdb":6.844,"tmdbVotes":167}},{"id":"movie-drop-2025","title":"Drop","year":2025,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Mystery","Thriller"],"overview":"Violet, a widowed mother on her first date in years, arrives at an upscale restaurant where she is relieved that her date, Henry, is more charming and handsome than she expected. But their chemistry begins to curdle\u2026","poster":"assets/movie-drop-2025-poster.jpg","backdrop":"assets/movie-drop-2025-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1249213,"ratings":{"rtCritics":83,"rtCriticsLabel":"Certified Fresh","rtAudience":79,"rtAudienceLabel":"Upright","imdb":6.1,"imdbVotes":61018,"tmdb":6.275,"tmdbVotes":1023}},{"id":"movie-eastern-promises-2007","title":"Eastern Promises","year":2007,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Thriller","Crime","Mystery"],"overview":"A Russian teenager living in London dies during childbirth but leaves clues in her diary that could tie her child to a rape involving a violent Russian mob family.","poster":"assets/movie-eastern-promises-2007-poster.jpg","backdrop":"assets/movie-eastern-promises-2007-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":2252,"ratings":{"rtCritics":89,"rtCriticsLabel":"Certified Fresh","rtAudience":83,"rtAudienceLabel":"Upright","imdb":7.6,"imdbVotes":281015,"tmdb":7.349,"tmdbVotes":3900}},{"id":"movie-faces-1968","title":"Faces","year":1968,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama"],"overview":"Middle-aged suburban husband Richard abruptly tells his wife, Maria, that he wants a divorce. As Richard takes up with a younger woman, Maria enjoys a night on the town with her friends and meets a younger man. As\u2026","poster":"assets/movie-faces-1968-poster.jpg","backdrop":"assets/movie-faces-1968-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"center_crop","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":753,"ratings":{"rtCritics":83,"rtCriticsLabel":"Fresh","rtAudience":86,"rtAudienceLabel":"Upright","imdb":7.4,"imdbVotes":12950,"tmdb":7.093,"tmdbVotes":227}},{"id":"movie-fatale-2020","title":"Fatale","year":2020,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Thriller"],"overview":"After a wild one-night stand, successful sports agent Derrick Tyler watches his perfect life slowly disappear when he discovers the sexy and mysterious woman he risked everything for is determined police detective\u2026","poster":"assets/movie-fatale-2020-poster.jpg","backdrop":"assets/movie-fatale-2020-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":549514,"ratings":{"rtCritics":46,"rtCriticsLabel":"Rotten","rtAudience":87,"rtAudienceLabel":"Upright","imdb":5.5,"imdbVotes":16392,"tmdb":6,"tmdbVotes":401}},{"id":"tv-56-days-2026","title":"56 Days","year":2026,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Crime","Mystery"],"overview":"When an unidentified body is found in a luxury apartment linked to Oliver Kennedy and his girlfriend Ciara Wyse, Detectives Lee Reardon and Karl Connolly reconstruct the couple's deadly romance across the past 56 days.","poster":"assets/tv-56-days-2026-poster.jpg","backdrop":"assets/tv-56-days-2026-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":241372,"ratings":{"rtCritics":60,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.388,"tmdbVotes":245}},{"id":"tv-absolutely-fabulous-1992","title":"Absolutely Fabulous","year":1992,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy"],"overview":"Set in the world of fashion and PR, immature fun-loving mother Edina Monsoon and her best friend Patsy drive Eddie's sensible daughter, Saffron, up the wall with their constant drug abuse and outrageous selfishness.\u2026","poster":"assets/tv-absolutely-fabulous-1992-poster.jpg","backdrop":"assets/tv-absolutely-fabulous-1992-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":4493,"ratings":{"rtCritics":96,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.6,"tmdbVotes":198}},{"id":"tv-the-afterparty-2022","title":"The Afterparty","year":2022,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Mystery","Comedy","Crime"],"overview":"Nothing is as it seems in this hilarious murder mystery where each suspect's story is told through a different film genre.","poster":"assets/tv-the-afterparty-2022-poster.jpg","backdrop":"assets/tv-the-afterparty-2022-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":106454,"ratings":{"rtCritics":92,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.071,"tmdbVotes":245}},{"id":"tv-agatha-christie-s-marple-2004","title":"Agatha Christie's Marple","year":2004,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Crime","Mystery"],"overview":"The adventures of Miss Jane Marple, an elderly spinster living in the quiet little village of St Mary Mead. During her many visits to friends and relatives in other villages, Miss Marple often stumbles upon\u2026","poster":"assets/tv-agatha-christie-s-marple-2004-poster.jpg","backdrop":"assets/tv-agatha-christie-s-marple-2004-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":6127,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.9,"tmdbVotes":152}},{"id":"tv-all-american-homecoming-2022","title":"All American: Homecoming","year":2022,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama"],"overview":"Follow the journeys of Simone Hicks, a tennis hopeful from Beverly Hills, and elite baseball player Damon Sims from Chicago, as they navigate life at the prestigious HBCU Bringston University.","poster":"assets/tv-all-american-homecoming-2022-poster.jpg","backdrop":"assets/tv-all-american-homecoming-2022-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":153723,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.3,"tmdbVotes":70}},{"id":"tv-and-just-like-that-2021","title":"And Just Like That\u2026","year":2021,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy","Drama"],"overview":"This new chapter of \u201cSex and the City\u201d follows Carrie, Miranda and Charlotte as they navigate the journey from the complicated reality of life and friendship in their 30s to the even more complicated reality of life\u2026","poster":"assets/tv-and-just-like-that-2021-poster.jpg","backdrop":"assets/tv-and-just-like-that-2021-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":116450,"ratings":{"rtCritics":52,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.211,"tmdbVotes":556}},{"id":"tv-anne-with-an-e-2017","title":"Anne with an E","year":2017,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Family"],"overview":"A coming-of-age story about an outsider who, against all odds and numerous challenges, fights for love and acceptance and for her place in the world. The series centers on a young orphaned girl in the late 1890s,\u2026","poster":"assets/tv-anne-with-an-e-2017-poster.jpg","backdrop":"assets/tv-anne-with-an-e-2017-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":70785,"ratings":{"rtCritics":63,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.7,"tmdbVotes":5019}},{"id":"tv-awkward-2011","title":"Awkward.","year":2011,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy","Drama"],"overview":"An irreverent look at the conflict, chaos and humor that defines teenage life through the eyes of 15-year-old Jenna Hamilton whose life begins to change when a simple accident becomes an epic misunderstanding and is\u2026","poster":"assets/tv-awkward-2011-poster.jpg","backdrop":"assets/tv-awkward-2011-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":39859,"ratings":{"rtCritics":78,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.4,"tmdbVotes":427}},{"id":"tv-the-baby-sitters-club-2020","title":"The Baby-Sitters Club","year":2020,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Kids","Drama"],"overview":"In this contemporary take on the beloved book series, five best friends launch a baby-sitting business that's big on fun and adventure.","poster":"assets/tv-the-baby-sitters-club-2020-poster.jpg","backdrop":"assets/tv-the-baby-sitters-club-2020-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":100412,"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.9,"tmdbVotes":506}},{"id":"tv-ballers-2015","title":"Ballers","year":2015,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Comedy"],"overview":"Looking at the lives of former and current football players, the show follows former superstar Spencer Strasmore as he gets his life on track in retirement while mentoring other current and former players through the\u2026","poster":"assets/tv-ballers-2015-poster.jpg","backdrop":"assets/tv-ballers-2015-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":62704,"ratings":{"rtCritics":72,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.809,"tmdbVotes":820}},{"id":"tv-baretta-1975","title":"Baretta","year":1975,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Crime","Drama","Mystery"],"overview":"Baretta is an American detective television series which ran on ABC from 1975 to 1978. The show was a milder version of a successful 1973\u201374 ABC series, Toma, starring Tony Musante as chameleon-like, real-life New\u2026","poster":"assets/tv-baretta-1975-poster.jpg","backdrop":"assets/tv-baretta-1975-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":3216,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.5,"tmdbVotes":43}},{"id":"tv-based-on-a-true-story-2023","title":"Based on a True Story","year":2023,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy","Drama"],"overview":"The lives of a realtor, a plumber and a former tennis star unexpectedly collide, exposing America\u2019s obsession with true crime, murder and the slow-close toilet seat.","poster":"assets/tv-based-on-a-true-story-2023-poster.jpg","backdrop":"assets/tv-based-on-a-true-story-2023-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":197373,"ratings":{"rtCritics":79,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7,"tmdbVotes":160}},{"id":"tv-the-beast-in-me-2025","title":"The Beast in Me","year":2025,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Mystery"],"overview":"A famous author is pulled into a twisted mind game with her rich, powerful new neighbor \u2014 who might be a murderer.","poster":"assets/tv-the-beast-in-me-2025-poster.jpg","backdrop":"assets/tv-the-beast-in-me-2025-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":250504,"ratings":{"rtCritics":85,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.072,"tmdbVotes":334}},{"id":"tv-big-city-greens-2018","title":"Big City Greens","year":2018,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Family","Animation","Comedy"],"overview":"The offbeat adventures of 10-year-old Cricket Green, a mischievous and optimistic country boy who moves to the big city with his wildly out of place family \u2013 older sister Tilly, father Bill and Gramma Alice.","poster":"assets/tv-big-city-greens-2018-poster.jpg","backdrop":"assets/tv-big-city-greens-2018-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":80587,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.555,"tmdbVotes":82}},{"id":"tv-the-bold-type-2017","title":"The Bold Type","year":2017,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Comedy"],"overview":"A glimpse into the outrageous lives of Jane, Kat and Sutton, who are working at the nation's top women's magazine, Scarlet, while navigating their careers, identities and individual voices.","poster":"assets/tv-the-bold-type-2017-poster.jpg","backdrop":"assets/tv-the-bold-type-2017-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":69630,"ratings":{"rtCritics":89,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.7,"tmdbVotes":204}},{"id":"tv-brassic-2019","title":"Brassic","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy","Drama","Crime"],"overview":"A group of working-class friends finding unconventional ways to win at life in suburban northern England. These lads have dealt, scammed, bribed and conned their way through adolescence, but now, their dealing and\u2026","poster":"assets/tv-brassic-2019-poster.jpg","backdrop":"assets/tv-brassic-2019-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":92621,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.336,"tmdbVotes":263}},{"id":"movie-12-years-a-slave-2013","title":"12 Years a Slave","year":2013,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","History"],"overview":"In the pre-Civil War United States, Solomon Northup, a free black man from upstate New York, is abducted and sold into slavery. Facing cruelty as well as unexpected kindnesses Solomon struggles not only to stay\u2026","poster":"assets/movie-12-years-a-slave-2013-poster.jpg","backdrop":"assets/movie-12-years-a-slave-2013-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":76203,"ratings":{"rtCritics":95,"rtCriticsLabel":"Certified Fresh","rtAudience":90,"rtAudienceLabel":"Upright","imdb":8.1,"imdbVotes":796313,"tmdb":7.927,"tmdbVotes":12335}},{"id":"movie-101-dalmatians-ii-patch-s-london-adventure-2003","title":"101 Dalmatians II: Patch's London Adventure","year":2003,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Family","Animation","Adventure"],"overview":"Being one of 101 takes its toll on Patch, who doesn't feel unique. When he's accidentally left behind on moving day, he meets his idol, Thunderbolt, who enlists him on a publicity campaign.","poster":"assets/movie-101-dalmatians-ii-patch-s-london-adventure-2003-poster.jpg","backdrop":"assets/movie-101-dalmatians-ii-patch-s-london-adventure-2003-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":13654,"ratings":{"rtCritics":67,"rtCriticsLabel":"Fresh","rtAudience":41,"rtAudienceLabel":"Spilled","imdb":5.7,"imdbVotes":12343,"tmdb":6.025,"tmdbVotes":1274}},{"id":"movie-absolution-2024","title":"Absolution","year":2024,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Crime","Thriller"],"overview":"An aging ex-boxer gangster working as muscle for a Boston crime boss receives an upsetting diagnosis. Despite a faltering memory, he attempts to rectify the sins of his past and reconnect with his estranged\u2026","poster":"assets/movie-absolution-2024-poster.jpg","backdrop":"assets/movie-absolution-2024-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":974453,"ratings":{"rtCritics":56,"rtCriticsLabel":"Rotten","rtAudience":32,"rtAudienceLabel":"Spilled","imdb":5.2,"imdbVotes":11413,"tmdb":5.906,"tmdbVotes":564}},{"id":"movie-all-the-money-in-the-world-2017","title":"All the Money in the World","year":2017,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Crime","History","Thriller"],"overview":"The story of the kidnapping of 16-year-old John Paul Getty III and the desperate attempt by his devoted mother to convince his billionaire grandfather Jean Paul Getty to pay the ransom.","poster":"assets/movie-all-the-money-in-the-world-2017-poster.jpg","backdrop":"assets/movie-all-the-money-in-the-world-2017-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":446791,"ratings":{"rtCritics":79,"rtCriticsLabel":"Certified Fresh","rtAudience":66,"rtAudienceLabel":"Upright","imdb":6.8,"imdbVotes":97448,"tmdb":6.493,"tmdbVotes":2493}},{"id":"movie-the-alto-knights-2025","title":"The Alto Knights","year":2025,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Crime","Drama"],"overview":"Two of New York's most notorious organized crime bosses, Frank Costello and Vito Genovese, vie for control of the city's streets. Once the best of friends, petty jealousies and a series of betrayals place them on a\u2026","poster":"assets/movie-the-alto-knights-2025-poster.jpg","backdrop":"assets/movie-the-alto-knights-2025-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1013601,"ratings":{"rtCritics":39,"rtCriticsLabel":"Rotten","rtAudience":71,"rtAudienceLabel":"Upright","imdb":5.9,"imdbVotes":23017,"tmdb":6.223,"tmdbVotes":485}},{"id":"movie-arctic-dogs-2019","title":"Arctic Dogs","year":2019,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Adventure","Comedy"],"overview":"Animals band together to save the day when the evil Otto Von Walrus hatches a sinister scheme to accelerate global warming and melt the Arctic Circle.","poster":"assets/movie-arctic-dogs-2019-poster.jpg","backdrop":"assets/movie-arctic-dogs-2019-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":416153,"ratings":{"rtCritics":13,"rtCriticsLabel":"Rotten","rtAudience":60,"rtAudienceLabel":"Upright","imdb":4.9,"imdbVotes":2580,"tmdb":5.9,"tmdbVotes":148}},{"id":"movie-a-bronx-tale-1993","title":"A Bronx Tale","year":1993,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Crime"],"overview":"Set in the Bronx during the tumultuous 1960s, an adolescent boy is torn between his honest, working-class father and a violent yet charismatic crime boss. Complicating matters is the youngster's growing attraction -\u2026","poster":"assets/movie-a-bronx-tale-1993-poster.jpg","backdrop":"assets/movie-a-bronx-tale-1993-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1607,"ratings":{"rtCritics":97,"rtCriticsLabel":"Fresh","rtAudience":92,"rtAudienceLabel":"Upright","imdb":7.8,"imdbVotes":191930,"tmdb":7.913,"tmdbVotes":3075}},{"id":"movie-by-any-means-2026","title":"By Any Means","year":2026,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Thriller","History","Crime"],"overview":"In 1960s Mississippi, a young Black FBI agent is forced to partner with a notorious mafia hitman to investigate a wave of brutal civil rights murders.","poster":"assets/movie-by-any-means-2026-poster.jpg","backdrop":"assets/movie-by-any-means-2026-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1380417,"ratings":{"rtCritics":49,"rtCriticsLabel":"Rotten","rtAudience":88,"rtAudienceLabel":"Upright","imdb":6.8,"imdbVotes":3534,"tmdb":6.6,"tmdbVotes":92}},{"id":"movie-captain-america-civil-war-2016","title":"Captain America: Civil War","year":2016,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Adventure","Action","Science Fiction"],"overview":"Following the events of Age of Ultron, the collective governments of the world pass an act designed to regulate all superhuman activity. This polarizes opinion amongst the Avengers, causing two factions to side with\u2026","poster":"assets/movie-captain-america-civil-war-2016-poster.jpg","backdrop":"assets/movie-captain-america-civil-war-2016-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":271110,"ratings":{"rtCritics":90,"rtCriticsLabel":"Certified Fresh","rtAudience":89,"rtAudienceLabel":"Upright","imdb":7.8,"imdbVotes":954943,"tmdb":7.455,"tmdbVotes":24808}},{"id":"movie-captain-america-the-first-avenger-2011","title":"Captain America: The First Avenger","year":2011,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"During World War II, Steve Rogers is a sickly man from Brooklyn who's transformed into super-soldier Captain America to aid in the war effort. Rogers must stop the Red Skull \u2013 Adolf Hitler's ruthless head of\u2026","poster":"assets/movie-captain-america-the-first-avenger-2011-poster.jpg","backdrop":"assets/movie-captain-america-the-first-avenger-2011-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1771,"ratings":{"rtCritics":80,"rtCriticsLabel":"Certified Fresh","rtAudience":75,"rtAudienceLabel":"Upright","imdb":6.9,"imdbVotes":993453,"tmdb":7.012,"tmdbVotes":23473}},{"id":"movie-captain-america-the-winter-soldier-2014","title":"Captain America: The Winter Soldier","year":2014,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"After the cataclysmic events in New York with The Avengers, Steve Rogers, aka Captain America is living quietly in Washington, D.C. and trying to adjust to the modern world. But when a S.H.I.E.L.D. colleague comes\u2026","poster":"assets/movie-captain-america-the-winter-soldier-2014-poster.jpg","backdrop":"assets/movie-captain-america-the-winter-soldier-2014-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":100402,"ratings":{"rtCritics":90,"rtCriticsLabel":"Certified Fresh","rtAudience":92,"rtAudienceLabel":"Upright","imdb":7.7,"imdbVotes":995514,"tmdb":7.654,"tmdbVotes":20688}},{"id":"tv-12-monkeys-2015","title":"12 Monkeys","year":2015,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Sci-Fi & Fantasy","Drama"],"overview":"The provocative story of Cole, a time traveler from a decimated future in a high-stakes race against the clock. Utilizing a dangerous and untested method of time travel, he journeys from 2043 to the present day on a\u2026","poster":"assets/tv-12-monkeys-2015-poster.jpg","backdrop":"assets/tv-12-monkeys-2015-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":60948,"ratings":{"rtCritics":88,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.441,"tmdbVotes":1245}},{"id":"tv-accused-2023","title":"Accused","year":2023,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Crime","Drama"],"overview":"In this crime anthology series, viewers discover how an ordinary person got caught up in an extraordinary situation, ultimately revealing how one wrong turn leads to another, until it\u2019s too late to turn back. Told\u2026","poster":"assets/tv-accused-2023-poster.jpg","backdrop":"assets/tv-accused-2023-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":202097,"ratings":{"rtCritics":61,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.851,"tmdbVotes":87}},{"id":"tv-after-life-2019","title":"After Life","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy","Drama"],"overview":"Tony had a perfect life. But after his wife Lisa suddenly dies, Tony changes. After contemplating taking his own life, he decides instead to live long enough to punish the world by saying and doing whatever he likes\u2026","poster":"assets/tv-after-life-2019-poster.jpg","backdrop":"assets/tv-after-life-2019-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":79410,"ratings":{"rtCritics":72,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.902,"tmdbVotes":1169}},{"id":"tv-all-creatures-great-and-small-1978","title":"All Creatures Great and Small","year":1978,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy","Drama"],"overview":"The trials and misadventures of the staff at a country veterinary office in Yorkshire. James Herriot, a young animal surgeon, moves to a small Yorkshire town to begin his first job.","poster":"assets/tv-all-creatures-great-and-small-1978-poster.jpg","backdrop":"assets/tv-all-creatures-great-and-small-1978-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"center_crop","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":7406,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.8,"tmdbVotes":50}},{"id":"tv-american-housewife-2016","title":"American Housewife","year":2016,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy"],"overview":"A family comedy narrated by Katie, a strong-willed mother, raising her flawed family in a wealthy town filled with perfect wives and their perfect offspring.","poster":"assets/tv-american-housewife-2016-poster.jpg","backdrop":"assets/tv-american-housewife-2016-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":67117,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.7,"tmdbVotes":187}},{"id":"tv-atlantis-2013","title":"Atlantis","year":2013,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action & Adventure","Sci-Fi & Fantasy"],"overview":"A fantasy drama set in a world of legendary heroes and mythical creatures. Far from home and desperate for answers, Jason washes up on the shores of an ancient land. A mysterious place; a world of bull leaping, of\u2026","poster":"assets/tv-atlantis-2013-poster.jpg","backdrop":"assets/tv-atlantis-2013-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":47054,"ratings":{"rtCritics":62,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.4,"tmdbVotes":155}},{"id":"tv-beat-bobby-flay-2013","title":"Beat Bobby Flay","year":2013,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Reality"],"overview":"Two talented chefs go head-to-head for the chance to Beat Bobby Flay. To get to Bobby the chefs must first face off against each other, creating a spectacular dish with a secret ingredient of Bobby's choice. Judges\u2026","poster":"assets/tv-beat-bobby-flay-2013-poster.jpg","backdrop":"assets/tv-beat-bobby-flay-2013-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":62481,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.5,"tmdbVotes":31}},{"id":"tv-benson-1979","title":"Benson","year":1979,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy"],"overview":"A butler deals with life at the governor's mansion.","poster":"assets/tv-benson-1979-poster.jpg","backdrop":"assets/tv-benson-1979-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1849,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7,"tmdbVotes":46}},{"id":"tv-black-rabbit-2025","title":"Black Rabbit","year":2025,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Crime"],"overview":"A rising-star restaurateur is forced into New York's criminal underworld when his chaotic brother returns to town with loan sharks on his trail.","poster":"assets/tv-black-rabbit-2025-poster.jpg","backdrop":"assets/tv-black-rabbit-2025-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":249039,"ratings":{"rtCritics":66,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.983,"tmdbVotes":240}},{"id":"tv-black-ish-2014","title":"black-ish","year":2014,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy"],"overview":"A family man struggles to gain a sense of cultural identity while raising his kids in a predominantly white, upper-middle-class neighborhood.","poster":"assets/tv-black-ish-2014-poster.jpg","backdrop":"assets/tv-black-ish-2014-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":61381,"ratings":{"rtCritics":92,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.1,"tmdbVotes":352}},{"id":"tv-breaking-bad-2008","title":"Breaking Bad","year":2008,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Crime"],"overview":"Walter White, a New Mexico chemistry teacher, is diagnosed with Stage III cancer and given a prognosis of only two years left to live. He becomes filled with a sense of fearlessness and an unrelenting desire to\u2026","poster":"assets/tv-breaking-bad-2008-poster.jpg","backdrop":"assets/tv-breaking-bad-2008-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"center_crop","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1396,"ratings":{"rtCritics":96,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.959,"tmdbVotes":19030}},{"id":"tv-the-capture-2019","title":"The Capture","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Crime","Drama","Mystery"],"overview":"When soldier Shaun Emery's conviction for a murder in Afghanistan is overturned due to flawed video evidence, he returns to life as a free man with his young daughter. But when damning CCTV footage from a night out\u2026","poster":"assets/tv-the-capture-2019-poster.jpg","backdrop":"assets/tv-the-capture-2019-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":93166,"ratings":{"rtCritics":97,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.634,"tmdbVotes":361}}],"duplicate":[{"id":"movie-the-amazing-spider-man-2012","title":"The Amazing Spider-Man","year":2012,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"A teenage Peter Parker grapples with both high school and amazing super-human crises as his alter-ego Spider-Man.","poster":"assets/movie-the-amazing-spider-man-2012-poster.jpg","backdrop":"assets/movie-the-amazing-spider-man-2012-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1930,"ratings":{"rtCritics":71,"rtCriticsLabel":"Certified Fresh","rtAudience":77,"rtAudienceLabel":"Upright","imdb":7,"imdbVotes":791938,"tmdb":6.768,"tmdbVotes":19312}},{"id":"movie-the-amazing-spider-man-2-2014","title":"The Amazing Spider-Man 2","year":2014,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"For Peter Parker, life is busy. Between taking out the bad guys as Spider-Man and spending time with the person he loves, Gwen Stacy, high school graduation cannot come quickly enough. Peter has not forgotten about\u2026","poster":"assets/movie-the-amazing-spider-man-2-2014-poster.jpg","backdrop":"assets/movie-the-amazing-spider-man-2-2014-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":102382,"ratings":{"rtCritics":51,"rtCriticsLabel":"Rotten","rtAudience":64,"rtAudienceLabel":"Upright","imdb":6.6,"imdbVotes":611981,"tmdb":6.567,"tmdbVotes":14919}},{"id":"movie-the-animatrix-2003","title":"The Animatrix","year":2003,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Science Fiction"],"overview":"Straight from the creators of the groundbreaking Matrix trilogy, this collection of short animated films from the world's leading anime directors fuses computer graphics and Japanese anime to provide the background\u2026","poster":"assets/movie-the-animatrix-2003-poster.jpg","backdrop":"assets/movie-the-animatrix-2003-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":55931,"ratings":{"rtCritics":86,"rtCriticsLabel":"Fresh","rtAudience":78,"rtAudienceLabel":"Upright","imdb":7.3,"imdbVotes":91929,"tmdb":7.221,"tmdbVotes":1872}},{"id":"movie-ant-man-and-the-wasp-quantumania-2023","title":"Ant-Man and the Wasp: Quantumania","year":2023,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"Super-Hero partners Scott Lang and Hope van Dyne, along with with Hope's parents Janet van Dyne and Hank Pym, and Scott's daughter Cassie Lang, find themselves exploring the Quantum Realm, interacting with strange\u2026","poster":"assets/movie-ant-man-and-the-wasp-quantumania-2023-poster.jpg","backdrop":"assets/movie-ant-man-and-the-wasp-quantumania-2023-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":640146,"ratings":{"rtCritics":46,"rtCriticsLabel":"Rotten","rtAudience":81,"rtAudienceLabel":"Upright","imdb":6,"imdbVotes":281738,"tmdb":6.197,"tmdbVotes":6236}},{"id":"movie-appleseed-alpha-2014","title":"Appleseed Alpha","year":2014,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Science Fiction","Action"],"overview":"The Third World War (2099\u20132126) devastated part of the Earth. Former nations are reforming while new powers emerge, and groups of humans struggle to survive in ruined cities. The story follows Deunan Knute and her\u2026","poster":"assets/movie-appleseed-alpha-2014-poster.jpg","backdrop":"assets/movie-appleseed-alpha-2014-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"center_crop","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":269650,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":59,"rtAudienceLabel":"Spilled","imdb":6.5,"imdbVotes":9689,"tmdb":6.808,"tmdbVotes":436}},{"id":"movie-aquaman-and-the-lost-kingdom-2023","title":"Aquaman and the Lost Kingdom","year":2023,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Fantasy"],"overview":"Black Manta seeks revenge on Aquaman for his father's death. Wielding the Black Trident's power, he becomes a formidable foe. To defend Atlantis, Arthur (Aquaman) forges an alliance with his imprisoned brother. They\u2026","poster":"assets/movie-aquaman-and-the-lost-kingdom-2023-poster.jpg","backdrop":"assets/movie-aquaman-and-the-lost-kingdom-2023-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":572802,"ratings":{"rtCritics":33,"rtCriticsLabel":"Rotten","rtAudience":79,"rtAudienceLabel":"Upright","imdb":5.6,"imdbVotes":122422,"tmdb":6.48,"tmdbVotes":3748}},{"id":"movie-the-avengers-2012","title":"The Avengers","year":2012,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Science Fiction","Action","Adventure"],"overview":"When an unexpected enemy emerges and threatens global safety and security, Nick Fury, director of the international peacekeeping agency known as S.H.I.E.L.D., finds himself in need of a team to pull the world back\u2026","poster":"assets/movie-the-avengers-2012-poster.jpg","backdrop":"assets/movie-the-avengers-2012-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":24428,"ratings":{"rtCritics":91,"rtCriticsLabel":"Certified Fresh","rtAudience":91,"rtAudienceLabel":"Upright","imdb":8,"imdbVotes":1590693,"tmdb":8.084,"tmdbVotes":40262}},{"id":"movie-avengers-confidential-black-widow-punisher-2014","title":"Avengers Confidential: Black Widow & Punisher","year":2014,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Science Fiction","Action"],"overview":"When the Punisher takes out a black-market weapons dealer, he stumbles upon a far-reaching terrorist plot devised by a group known as Leviathan.","poster":"assets/movie-avengers-confidential-black-widow-punisher-2014-poster.jpg","backdrop":"assets/movie-avengers-confidential-black-widow-punisher-2014-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":257346,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":55,"rtAudienceLabel":"Spilled","imdb":5.7,"imdbVotes":5166,"tmdb":6.368,"tmdbVotes":303}},{"id":"movie-avengers-age-of-ultron-2015","title":"Avengers: Age of Ultron","year":2015,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"When Tony Stark tries to jumpstart a dormant peacekeeping program, things go awry and Earth\u2019s Mightiest Heroes are put to the ultimate test as the fate of the planet hangs in the balance. As the villainous Ultron\u2026","poster":"assets/movie-avengers-age-of-ultron-2015-poster.jpg","backdrop":"assets/movie-avengers-age-of-ultron-2015-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":99861,"ratings":{"rtCritics":75,"rtCriticsLabel":"Certified Fresh","rtAudience":82,"rtAudienceLabel":"Upright","imdb":7.3,"imdbVotes":1025876,"tmdb":7.278,"tmdbVotes":25289}},{"id":"movie-avengers-infinity-war-2018","title":"Avengers: Infinity War","year":2018,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Adventure","Action","Science Fiction"],"overview":"As the Avengers and their allies have continued to protect the world from threats too large for any one hero to handle, a new danger has emerged from the cosmic shadows: Thanos. A despot of intergalactic infamy, his\u2026","poster":"assets/movie-avengers-infinity-war-2018-poster.jpg","backdrop":"assets/movie-avengers-infinity-war-2018-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":299536,"ratings":{"rtCritics":85,"rtCriticsLabel":"Certified Fresh","rtAudience":92,"rtAudienceLabel":"Upright","imdb":8.4,"imdbVotes":1421954,"tmdb":8.246,"tmdbVotes":33331}},{"id":"movie-batman-ninja-2018","title":"Batman Ninja","year":2018,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Action","Science Fiction"],"overview":"Batman, along with many of his allies and adversaries, finds himself transported to feudal Japan by Gorilla Grodd's time displacement machine.","poster":"assets/movie-batman-ninja-2018-poster.jpg","backdrop":"assets/movie-batman-ninja-2018-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":485942,"ratings":{"rtCritics":84,"rtCriticsLabel":"Fresh","rtAudience":60,"rtAudienceLabel":"Upright","imdb":5.6,"imdbVotes":24579,"tmdb":5.9,"tmdbVotes":1106}},{"id":"movie-batman-v-superman-dawn-of-justice-2016","title":"Batman v Superman: Dawn of Justice","year":2016,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Fantasy"],"overview":"Fearing the actions of a god-like Super Hero left unchecked, Gotham City\u2019s own formidable, forceful vigilante takes on Metropolis\u2019s most revered, modern-day savior, while the world wrestles with what sort of hero it\u2026","poster":"assets/movie-batman-v-superman-dawn-of-justice-2016-poster.jpg","backdrop":"assets/movie-batman-v-superman-dawn-of-justice-2016-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":209112,"ratings":{"rtCritics":28,"rtCriticsLabel":"Rotten","rtAudience":63,"rtAudienceLabel":"Upright","imdb":6.4,"imdbVotes":801382,"tmdb":6.014,"tmdbVotes":19527}},{"id":"movie-batman-the-dark-knight-returns-part-1-2012","title":"Batman: The Dark Knight Returns, Part 1","year":2012,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Science Fiction","Action","Animation"],"overview":"Batman has not been seen for ten years. A new breed of criminal ravages Gotham City, forcing 55-year-old Bruce Wayne back into the cape and cowl. But, does he still have what it takes to fight crime in a new era?","poster":"assets/movie-batman-the-dark-knight-returns-part-1-2012-poster.jpg","backdrop":"assets/movie-batman-the-dark-knight-returns-part-1-2012-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":123025,"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":93,"rtAudienceLabel":"Upright","imdb":7.9,"imdbVotes":68943,"tmdb":7.742,"tmdbVotes":1766}},{"id":"movie-black-adam-2022","title":"Black Adam","year":2022,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"Nearly 5,000 years after he was bestowed with the almighty powers of the Egyptian gods\u2014and imprisoned just as quickly\u2014Black Adam is freed from his earthly tomb, ready to unleash his unique form of justice on the\u2026","poster":"assets/movie-black-adam-2022-poster.jpg","backdrop":"assets/movie-black-adam-2022-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":436270,"ratings":{"rtCritics":39,"rtCriticsLabel":"Rotten","rtAudience":87,"rtAudienceLabel":"Upright","imdb":6.1,"imdbVotes":309624,"tmdb":6.747,"tmdbVotes":7370}},{"id":"movie-black-panther-2018","title":"Black Panther","year":2018,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"King T'Challa returns home to the reclusive, technologically advanced African nation of Wakanda to serve as his country's new leader. However, T'Challa soon finds that he is challenged for the throne by factions\u2026","poster":"assets/movie-black-panther-2018-poster.jpg","backdrop":"assets/movie-black-panther-2018-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":284054,"ratings":{"rtCritics":96,"rtCriticsLabel":"Certified Fresh","rtAudience":null,"rtAudienceLabel":"Spilled","imdb":7.3,"imdbVotes":931120,"tmdb":7.36,"tmdbVotes":24190}},{"id":"movie-black-panther-wakanda-forever-2022","title":"Black Panther: Wakanda Forever","year":2022,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"Queen Ramonda, Shuri, M\u2019Baku, Okoye and the Dora Milaje fight to protect their nation from intervening world powers in the wake of King T\u2019Challa\u2019s death. As the Wakandans strive to embrace their next chapter, the\u2026","poster":"assets/movie-black-panther-wakanda-forever-2022-poster.jpg","backdrop":"assets/movie-black-panther-wakanda-forever-2022-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":505642,"ratings":{"rtCritics":84,"rtCriticsLabel":"Certified Fresh","rtAudience":93,"rtAudienceLabel":"Upright","imdb":6.6,"imdbVotes":405088,"tmdb":6.984,"tmdbVotes":7920}},{"id":"movie-blame-2017","title":"BLAME!","year":2017,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Drama","Science Fiction"],"overview":"In the distant technological future, civilization has reached its ultimate Net-based form. An \"infection\" in the past caused the automated systems to spiral out of order, resulting in a multi-leveled city structure\u2026","poster":"assets/movie-blame-2017-poster.jpg","backdrop":"assets/movie-blame-2017-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":409421,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":61,"rtAudienceLabel":"Upright","imdb":6.6,"imdbVotes":10258,"tmdb":6.523,"tmdbVotes":370}},{"id":"movie-bleach-the-movie-fade-to-black-2008","title":"Bleach the Movie: Fade to Black","year":2008,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Animation","Fantasy"],"overview":"A strange disturbance in the World of the Living sends Ichigo and Kon to the Soul Society, where the Seireitei has been devastated by an explosion of reishi and Rukia is missing. Stranger still, none of the Soul\u2026","poster":"assets/movie-bleach-the-movie-fade-to-black-2008-poster.jpg","backdrop":"assets/movie-bleach-the-movie-fade-to-black-2008-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":17165,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":67,"rtAudienceLabel":"Upright","imdb":7.1,"imdbVotes":3693,"tmdb":7.1,"tmdbVotes":206}},{"id":"tv-90-day-fiance-before-the-90-days-2017","title":"90 Day Fianc\u00e9: Before the 90 Days","year":2017,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Reality"],"overview":"Follow couples who have an existing relationship online, but haven't met in person. We'll experience their journey as they travel to the other's foreign country for the first time in an attempt to establish an\u2026","poster":"assets/tv-90-day-fiance-before-the-90-days-2017-poster.jpg","backdrop":"assets/tv-90-day-fiance-before-the-90-days-2017-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":73319,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.5,"tmdbVotes":45}},{"id":"tv-90-day-fiance-the-other-way-2019","title":"90 Day Fianc\u00e9: The Other Way","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Reality"],"overview":"Americans move to a foreign country all in the name of love. Will uprooting their lives in the United States pay off, or will they be packing up and moving back to America brokenhearted?","poster":"assets/tv-90-day-fiance-the-other-way-2019-poster.jpg","backdrop":"assets/tv-90-day-fiance-the-other-way-2019-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":90046,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.8,"tmdbVotes":34}},{"id":"tv-the-100-2014","title":"The 100","year":2014,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Sci-Fi & Fantasy","Action & Adventure","Drama"],"overview":"100 years in the future, when the Earth has been abandoned due to radioactivity, the last surviving humans live on an ark orbiting the planet \u2014 but the ark won't last forever. So the repressive regime picks 100\u2026","poster":"assets/tv-the-100-2014-poster.jpg","backdrop":"assets/tv-the-100-2014-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":48866,"ratings":{"rtCritics":93,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.878,"tmdbVotes":8855}},{"id":"tv-the-abbott-and-costello-show-1952","title":"The Abbott and Costello Show","year":1952,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy"],"overview":"Bud and Lou are unemployed actors living in Mr. Fields\u2019 boarding house. Lou\u2019s girlfriend Hillary lives across the hall. Many situations arise leading to slapstick and puns.","poster":"assets/tv-the-abbott-and-costello-show-1952-poster.jpg","backdrop":"assets/tv-the-abbott-and-costello-show-1952-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":11821,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.2,"tmdbVotes":22}},{"id":"tv-accel-world-2012","title":"Accel World","year":2012,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Action & Adventure","Drama"],"overview":"A short, overweight student uses the Neuro Link, an evolution of the Nerve Gear, to escape himself from the reality. But his skills in the virtual world brings him to the attention of Kuroyukihime, a popular student\u2026","poster":"assets/tv-accel-world-2012-poster.jpg","backdrop":"assets/tv-accel-world-2012-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"center_crop","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":43167,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.429,"tmdbVotes":163}},{"id":"tv-ahsoka-2023","title":"Ahsoka","year":2023,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Sci-Fi & Fantasy","Action & Adventure","Drama"],"overview":"Former Jedi Knight Ahsoka Tano investigates an emerging threat to a vulnerable galaxy.","poster":"assets/tv-ahsoka-2023-poster.jpg","backdrop":"assets/tv-ahsoka-2023-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":114461,"ratings":{"rtCritics":85,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.4,"tmdbVotes":1351}},{"id":"tv-american-dad-2005","title":"American Dad!","year":2005,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Comedy"],"overview":"The series focuses on an eccentric motley crew that is the Smith family and their three housemates: Father, husband, and breadwinner Stan Smith; his better half housewife, Francine Smith; their college-aged daughter,\u2026","poster":"assets/tv-american-dad-2005-poster.jpg","backdrop":"assets/tv-american-dad-2005-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1433,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.022,"tmdbVotes":2481}},{"id":"tv-american-gods-2017","title":"American Gods","year":2017,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Mystery","Sci-Fi & Fantasy"],"overview":"An ex-con becomes the traveling partner of a conman who turns out to be one of the older gods trying to recruit troops to battle the upstart deities. Based on Neil Gaiman's fantasy novel.","poster":"assets/tv-american-gods-2017-poster.jpg","backdrop":"assets/tv-american-gods-2017-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":46639,"ratings":{"rtCritics":75,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.1,"tmdbVotes":1852}},{"id":"tv-andromeda-2000","title":"Andromeda","year":2000,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action & Adventure","Drama","Sci-Fi & Fantasy"],"overview":"Captain Dylan Hunt and his crew quest to restore a government that once presided over an extended peace and prosperity.","poster":"assets/tv-andromeda-2000-poster.jpg","backdrop":"assets/tv-andromeda-2000-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":2985,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.068,"tmdbVotes":315}},{"id":"tv-aqua-teen-hunger-force-2000","title":"Aqua Teen Hunger Force","year":2000,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Comedy"],"overview":"The surreal adventures of three anthropomorphic fast food items: Master Shake, Frylock and Meatwad, and their human nextdoor neighbor, Carl Brutananadilewski.","poster":"assets/tv-aqua-teen-hunger-force-2000-poster.jpg","backdrop":"assets/tv-aqua-teen-hunger-force-2000-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":251,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.5,"tmdbVotes":272}},{"id":"tv-arifureta-from-commonplace-to-world-s-strongest-2019","title":"Arifureta: From Commonplace to World's Strongest","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"Hajime Nagumo and his high school class are suddenly summoned to a fantastical land as heroes. But while most of his classmates have powerful stats and abilities, Hajime does not. Underappreciated and unprepared, he\u2026","poster":"assets/tv-arifureta-from-commonplace-to-world-s-strongest-2019-poster.jpg","backdrop":"assets/tv-arifureta-from-commonplace-to-world-s-strongest-2019-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":86034,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.382,"tmdbVotes":662}},{"id":"tv-arrow-2012","title":"Arrow","year":2012,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Crime","Drama","Action & Adventure"],"overview":"Spoiled billionaire playboy Oliver Queen is missing and presumed dead when his yacht is lost at sea. He returns five years later a changed man, determined to clean up the city as a hooded vigilante armed with a bow.","poster":"assets/tv-arrow-2012-poster.jpg","backdrop":"assets/tv-arrow-2012-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1412,"ratings":{"rtCritics":86,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.834,"tmdbVotes":6537}},{"id":"tv-avatar-the-last-airbender-2024","title":"Avatar: The Last Airbender","year":2024,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action & Adventure","Sci-Fi & Fantasy","Drama"],"overview":"A young boy known as the Avatar must master the four elemental powers to save a world at war \u2014 and fight a ruthless enemy bent on stopping him.","poster":"assets/tv-avatar-the-last-airbender-2024-poster.jpg","backdrop":"assets/tv-avatar-the-last-airbender-2024-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":82452,"ratings":{"rtCritics":66,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.8,"tmdbVotes":1406}},{"id":"tv-avatar-seven-havens-2026","title":"Avatar: Seven Havens","year":2026,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"In a world shattered by a devastating cataclysm, a young Earthbender discovers she's the new Avatar after Korra. But in this dangerous era, that title marks her as humanity's destroyer, not its savior. Hunted by both\u2026","poster":"assets/tv-avatar-seven-havens-2026-poster.jpg","backdrop":"assets/tv-avatar-seven-havens-2026-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":284833,"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.9,"tmdbVotes":183}},{"id":"tv-batman-the-brave-and-the-bold-2008","title":"Batman: The Brave and the Bold","year":2008,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"The Caped Crusader is teamed up with Blue Beetle, Green Arrow, Aquaman and countless others in his quest to uphold justice.","poster":"assets/tv-batman-the-brave-and-the-bold-2008-poster.jpg","backdrop":"assets/tv-batman-the-brave-and-the-bold-2008-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":15804,"ratings":{"rtCritics":96,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.6,"tmdbVotes":295}},{"id":"tv-batwoman-2019","title":"Batwoman","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Sci-Fi & Fantasy","Action & Adventure"],"overview":"Kate Kane, armed with a passion for social justice and a flair for speaking her mind, soars onto the streets of Gotham as Batwoman, an out lesbian and highly trained street fighter primed to snuff out the failing\u2026","poster":"assets/tv-batwoman-2019-poster.jpg","backdrop":"assets/tv-batwoman-2019-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":89247,"ratings":{"rtCritics":83,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.8,"tmdbVotes":1619}},{"id":"tv-big-mouth-2017","title":"Big Mouth","year":2017,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy","Animation"],"overview":"Teenage friends find their lives upended by the wonders and horrors of puberty in this edgy comedy from real-life pals Nick Kroll and Andrew Goldberg.","poster":"assets/tv-big-mouth-2017-poster.jpg","backdrop":"assets/tv-big-mouth-2017-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":74204,"ratings":{"rtCritics":95,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.591,"tmdbVotes":1274}},{"id":"tv-black-lightning-2018","title":"Black Lightning","year":2018,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action & Adventure","Sci-Fi & Fantasy","Drama"],"overview":"Jefferson Pierce is a man wrestling with a secret. As the father of two daughters and principal of a charter high school that also serves as a safe haven for young people in a New Orleans neighborhood overrun by gang\u2026","poster":"assets/tv-black-lightning-2018-poster.jpg","backdrop":"assets/tv-black-lightning-2018-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":71663,"ratings":{"rtCritics":92,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.907,"tmdbVotes":991}}]}} diff --git a/app/src/debug/assets/wolfskin-requests.json b/app/src/debug/assets/wolfskin-requests.json new file mode 100644 index 00000000..507ebd65 --- /dev/null +++ b/app/src/debug/assets/wolfskin-requests.json @@ -0,0 +1,217 @@ +{ + "source": "Locked Opus fixture/fixture.json; index.html EXAMPLES() pool order", + "items": [ + { + "id": "x1", + "mediaType": "tv", + "tmdbId": 11821, + "title": "The Abbott and Costello Show", + "requesterKey": "justin", + "requesterName": "Justin", + "actorKey": "justin", + "actorName": "Justin", + "stage": "Downloading", + "poster": "tv-the-abbott-and-costello-show-1952-poster.jpg", + "ratings": [ + { + "mark": "tmdb", + "score": 7.2, + "percentage": false + } + ] + }, + { + "id": "x2", + "mediaType": "movie", + "tmdbId": 13483, + "title": "Awake", + "requesterKey": "mindel", + "requesterName": "Mindel", + "actorKey": "justin", + "actorName": "Justin", + "stage": "AlmostReady", + "poster": "movie-awake-2007-poster.jpg", + "ratings": [ + { + "mark": "rotten", + "score": 23, + "percentage": true + }, + { + "mark": "spilled", + "score": 55, + "percentage": true + }, + { + "mark": "imdb", + "score": 6.5, + "percentage": false + } + ] + }, + { + "id": "x3", + "mediaType": "tv", + "tmdbId": 70785, + "title": "Anne with an E", + "requesterKey": "shared", + "requesterName": "Shared", + "actorKey": "mindel", + "actorName": "Mindel", + "stage": "Searching", + "poster": "tv-anne-with-an-e-2017-poster.jpg", + "ratings": [ + { + "mark": "fresh", + "score": 63, + "percentage": true + } + ] + }, + { + "id": "x4", + "mediaType": "movie", + "tmdbId": 99861, + "title": "Avengers: Age of Ultron", + "requesterKey": "justin", + "requesterName": "Justin", + "actorKey": "justin", + "actorName": "Justin", + "stage": "Waiting", + "poster": "movie-avengers-age-of-ultron-2015-poster.jpg", + "ratings": [ + { + "mark": "fresh", + "score": 75, + "percentage": true + }, + { + "mark": "upright", + "score": 82, + "percentage": true + }, + { + "mark": "imdb", + "score": 7.3, + "percentage": false + } + ] + }, + { + "id": "x5", + "mediaType": "movie", + "tmdbId": 1033148, + "title": "Die My Love", + "requesterKey": "mindel", + "requesterName": "Mindel", + "actorKey": "mindel", + "actorName": "Mindel", + "stage": "Failed", + "poster": "movie-die-my-love-2025-poster.jpg", + "ratings": [ + { + "mark": "fresh", + "score": 74, + "percentage": true + }, + { + "mark": "spilled", + "score": 45, + "percentage": true + }, + { + "mark": "imdb", + "score": 6, + "percentage": false + } + ] + }, + { + "id": "x6", + "mediaType": "movie", + "tmdbId": 416153, + "title": "Arctic Dogs", + "requesterKey": "shared", + "requesterName": "Shared", + "actorKey": "justin", + "actorName": "Justin", + "stage": "Ready", + "poster": "movie-arctic-dogs-2019-poster.jpg", + "ratings": [ + { + "mark": "rotten", + "score": 13, + "percentage": true + }, + { + "mark": "upright", + "score": 60, + "percentage": true + }, + { + "mark": "imdb", + "score": 4.9, + "percentage": false + } + ] + }, + { + "id": "x7", + "mediaType": "movie", + "tmdbId": 76203, + "title": "12 Years a Slave", + "requesterKey": "justin", + "requesterName": "Justin", + "actorKey": "shared", + "actorName": "Shared", + "stage": "Waiting", + "poster": "movie-12-years-a-slave-2013-poster.jpg", + "ratings": [ + { + "mark": "fresh", + "score": 95, + "percentage": true + }, + { + "mark": "upright", + "score": 90, + "percentage": true + }, + { + "mark": "imdb", + "score": 8.1, + "percentage": false + } + ] + }, + { + "id": "x8", + "mediaType": "movie", + "tmdbId": 14069, + "title": "The Girl Who Leapt Through Time", + "requesterKey": "mindel", + "requesterName": "Mindel", + "actorKey": "justin", + "actorName": "Justin", + "stage": "Waiting", + "poster": "movie-the-girl-who-leapt-through-time-2006-poster.jpg", + "ratings": [ + { + "mark": "fresh", + "score": 87, + "percentage": true + }, + { + "mark": "upright", + "score": 90, + "percentage": true + }, + { + "mark": "imdb", + "score": 7.6, + "percentage": false + } + ] + } + ] +} diff --git a/app/src/debug/assets/wolfskin-requests/movie-12-years-a-slave-2013-poster.jpg b/app/src/debug/assets/wolfskin-requests/movie-12-years-a-slave-2013-poster.jpg new file mode 100644 index 00000000..ff1f55e6 Binary files /dev/null and b/app/src/debug/assets/wolfskin-requests/movie-12-years-a-slave-2013-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-requests/movie-arctic-dogs-2019-poster.jpg b/app/src/debug/assets/wolfskin-requests/movie-arctic-dogs-2019-poster.jpg new file mode 100644 index 00000000..07552443 Binary files /dev/null and b/app/src/debug/assets/wolfskin-requests/movie-arctic-dogs-2019-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-requests/movie-avengers-age-of-ultron-2015-poster.jpg b/app/src/debug/assets/wolfskin-requests/movie-avengers-age-of-ultron-2015-poster.jpg new file mode 100644 index 00000000..300840ff Binary files /dev/null and b/app/src/debug/assets/wolfskin-requests/movie-avengers-age-of-ultron-2015-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-requests/movie-awake-2007-poster.jpg b/app/src/debug/assets/wolfskin-requests/movie-awake-2007-poster.jpg new file mode 100644 index 00000000..32595897 Binary files /dev/null and b/app/src/debug/assets/wolfskin-requests/movie-awake-2007-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-requests/movie-die-my-love-2025-poster.jpg b/app/src/debug/assets/wolfskin-requests/movie-die-my-love-2025-poster.jpg new file mode 100644 index 00000000..f6eca818 Binary files /dev/null and b/app/src/debug/assets/wolfskin-requests/movie-die-my-love-2025-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-requests/movie-the-girl-who-leapt-through-time-2006-poster.jpg b/app/src/debug/assets/wolfskin-requests/movie-the-girl-who-leapt-through-time-2006-poster.jpg new file mode 100644 index 00000000..ded6cd2a Binary files /dev/null and b/app/src/debug/assets/wolfskin-requests/movie-the-girl-who-leapt-through-time-2006-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-requests/tv-anne-with-an-e-2017-poster.jpg b/app/src/debug/assets/wolfskin-requests/tv-anne-with-an-e-2017-poster.jpg new file mode 100644 index 00000000..55d443b4 Binary files /dev/null and b/app/src/debug/assets/wolfskin-requests/tv-anne-with-an-e-2017-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-requests/tv-the-abbott-and-costello-show-1952-poster.jpg b/app/src/debug/assets/wolfskin-requests/tv-the-abbott-and-costello-show-1952-poster.jpg new file mode 100644 index 00000000..7d6768ea Binary files /dev/null and b/app/src/debug/assets/wolfskin-requests/tv-the-abbott-and-costello-show-1952-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-shell.json b/app/src/debug/assets/wolfskin-shell.json new file mode 100644 index 00000000..d99323a9 --- /dev/null +++ b/app/src/debug/assets/wolfskin-shell.json @@ -0,0 +1,78 @@ +{ + "source": "Locked Opus fixture/fixture.json; shell-only projection; debug/test only", + "profiles": [ + { + "key": "justin", + "name": "Justin", + "initial": "J", + "color": "#62c4ff", + "destinations": { + "Home": { + "kind": "home" + }, + "Movies": { + "kind": "library", + "collection": "movies" + }, + "Shows": { + "kind": "library", + "collection": "shows" + }, + "Anime": { + "kind": "library", + "collection": "anime" + }, + "Discover": { + "kind": "discover", + "collection": "discover" + } + } + }, + { + "key": "mindel", + "name": "Mindel", + "initial": "M", + "color": "#ff9d72", + "destinations": { + "Home": { + "kind": "home" + }, + "Movies": { + "kind": "library", + "collection": "movies" + }, + "Shows": { + "kind": "library", + "collection": "shows" + }, + "Discover": { + "kind": "discover", + "collection": "discover" + } + } + }, + { + "key": "shared", + "name": "Shared", + "initial": "S", + "color": "#9be38f", + "destinations": { + "Home": { + "kind": "home" + }, + "Movies": { + "kind": "library", + "collection": "movies" + }, + "Shows": { + "kind": "library", + "collection": "shows" + }, + "Discover": { + "kind": "discover", + "collection": "discover" + } + } + } + ] +} diff --git a/app/src/debug/assets/wolfskin-titles.json b/app/src/debug/assets/wolfskin-titles.json new file mode 100644 index 00000000..c7559aaa --- /dev/null +++ b/app/src/debug/assets/wolfskin-titles.json @@ -0,0 +1 @@ +{"profiles":[{"key":"justin","name":"Justin","initial":"J","color":"#62c4ff","destinations":{"Home":{"kind":"home"},"Movies":{"kind":"library","collection":"movies"},"Shows":{"kind":"library","collection":"shows"},"Anime":{"kind":"library","collection":"anime"},"Discover":{"kind":"discover","collection":"discover"}},"movies":[{"id":"movie-the-girl-who-leapt-through-time-2006","title":"The Girl Who Leapt Through Time","year":2006,"type":"movie","runtimeSeconds":5886,"seasonCount":null,"communityRating":7.772,"criticRating":87,"genres":["Fantasy","Animation","Drama"],"overview":"When 17-year-old Makoto Konno gains the ability to 'leap' backwards through time, she immediately sets about improving her grades and preventing personal mishaps. However, she soon realises that changing the past\u2026","poster":"assets/movie-the-girl-who-leapt-through-time-2006-poster.jpg","backdrop":"assets/movie-the-girl-who-leapt-through-time-2006-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T17:39:11.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":14069,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":87,"rtCriticsLabel":"Fresh","rtAudience":90,"rtAudienceLabel":"Upright","imdb":7.6,"imdbVotes":76917,"tmdb":7.775,"tmdbVotes":2345}},{"id":"movie-locke-2014","title":"Locke","year":2014,"type":"movie","runtimeSeconds":5090,"seasonCount":null,"communityRating":6.891,"criticRating":91,"genres":["Drama","Thriller"],"overview":"Ivan Locke has worked hard to craft a good life for himself. Tonight, that life will collapse around him. On the eve of the biggest challenge of his career, Ivan receives a phone call that sets in motion a series of\u2026","poster":"assets/movie-locke-2014-poster.jpg","backdrop":"assets/movie-locke-2014-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T17:38:48.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":210479,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":90,"rtCriticsLabel":"Certified Fresh","rtAudience":72,"rtAudienceLabel":"Upright","imdb":7.1,"imdbVotes":171265,"tmdb":6.889,"tmdbVotes":3088}},{"id":"movie-look-who-s-back-2015","title":"Look Who's Back","year":2015,"type":"movie","runtimeSeconds":6936,"seasonCount":null,"communityRating":6.793,"criticRating":null,"genres":["Comedy"],"overview":"When Adolf Hitler reawakens at the site of his former bunker in present-day Berlin, he is mistaken for a comedian and quickly becomes a media phenomenon.","poster":"assets/movie-look-who-s-back-2015-poster.jpg","backdrop":"assets/movie-look-who-s-back-2015-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:27:48.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":318917,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":81,"rtAudienceLabel":"Upright","imdb":7,"imdbVotes":54672,"tmdb":6.796,"tmdbVotes":1990}},{"id":"movie-memories-1995","title":"Memories","year":1995,"type":"movie","runtimeSeconds":6805,"seasonCount":null,"communityRating":7.465,"criticRating":null,"genres":["Fantasy","Animation","Science Fiction"],"overview":"Three back-to-back anime films by three different directors make up this sci-fi trilogy three years in the making.","poster":"assets/movie-memories-1995-poster.jpg","backdrop":"assets/movie-memories-1995-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-30T21:36:03.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":42994,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":82,"rtAudienceLabel":"Upright","imdb":7.5,"imdbVotes":26638,"tmdb":7.459,"tmdbVotes":622}},{"id":"movie-reincarnated-2012","title":"Reincarnated","year":2012,"type":"movie","runtimeSeconds":5759,"seasonCount":null,"communityRating":6.145,"criticRating":28,"genres":["Music","Documentary"],"overview":"Evolution as an artist is often times what separates legends from the more mundane. After being heavily influenced by his experience in Jamaica \u2013 and his subsequent name change from Snoop Dogg to Snoop Lion \u2013 the LBC\u2026","poster":"assets/movie-reincarnated-2012-poster.jpg","backdrop":"assets/movie-reincarnated-2012-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:27:26.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":123431,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":28,"rtCriticsLabel":"Rotten","rtAudience":41,"rtAudienceLabel":"Spilled","imdb":6.2,"imdbVotes":2563,"tmdb":6.1,"tmdbVotes":69}},{"id":"movie-shipwrecked-nightmare-at-sea-2026","title":"Shipwrecked: Nightmare at Sea","year":2026,"type":"movie","runtimeSeconds":5385,"seasonCount":null,"communityRating":7.181,"criticRating":null,"genres":["Documentary"],"overview":"Never-before-seen footage and survivor accounts trace the 2012 shipwreck of a luxury cruise and the disaster that ensued, in this immersive documentary.","poster":"assets/movie-shipwrecked-nightmare-at-sea-2026-poster.jpg","backdrop":"assets/movie-shipwrecked-nightmare-at-sea-2026-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-20T20:11:43.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":1715492,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":6.5,"imdbVotes":5080,"tmdb":7.172,"tmdbVotes":87}},{"id":"movie-steins-gate-the-movie-load-region-of-deja-vu-2013","title":"Steins;Gate: The Movie - Load Region of D\u00e9j\u00e0 Vu","year":2013,"type":"movie","runtimeSeconds":5403,"seasonCount":null,"communityRating":7.8,"criticRating":null,"genres":["Animation","Mystery","Sci-Fi"],"overview":"After the events of the anime, Rintarou begins to feel the repercussions of extensive time travel, and eventually completely fades from reality. Kurisu, being the only companion to remember him, now must find a way\u2026","poster":"assets/movie-steins-gate-the-movie-load-region-of-deja-vu-2013-poster.jpg","backdrop":"assets/movie-steins-gate-the-movie-load-region-of-deja-vu-2013-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-22T14:55:54.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","artwork":{"posterKind":"poster","backdropKind":"backdrop"}}],"shows":[{"id":"tv-andor-2022","title":"Andor","year":2022,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":8.293,"criticRating":null,"genres":["Sci-Fi & Fantasy","Action & Adventure","Drama"],"overview":"In an era filled with danger, deception and intrigue, Cassian Andor will discover the difference he can make in the struggle against the tyrannical Galactic Empire. He embarks on a path that is destined to turn him\u2026","poster":"assets/tv-andor-2022-poster.jpg","backdrop":"assets/tv-andor-2022-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0432996Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":83867,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":96,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.321,"tmdbVotes":2312}},{"id":"tv-the-boys-2019","title":"The Boys","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":5,"communityRating":8.443,"criticRating":null,"genres":["Sci-Fi & Fantasy","Action & Adventure"],"overview":"A group of vigilantes known informally as \u201cThe Boys\u201d set out to take down corrupt superheroes with no more than blue-collar grit and a willingness to fight dirty.","poster":"assets/tv-the-boys-2019-poster.jpg","backdrop":"assets/tv-the-boys-2019-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0410131Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":76479,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":92,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.4,"tmdbVotes":13628}},{"id":"tv-californication-2007","title":"Californication","year":2007,"type":"tv","runtimeSeconds":1680,"seasonCount":7,"communityRating":7.632,"criticRating":null,"genres":["Comedy","Drama"],"overview":"A self-loathing, alcoholic writer attempts to repair his damaged relationships with his daughter and her mother while combating sex addiction, a budding drug problem, and the seeming inability to avoid making bad\u2026","poster":"assets/tv-californication-2007-poster.jpg","backdrop":"assets/tv-californication-2007-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0428037Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":1215,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":57,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.62,"tmdbVotes":1406}},{"id":"tv-firefly-2002","title":"Firefly","year":2002,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":8.347,"criticRating":null,"genres":["Drama","Action & Adventure","Sci-Fi & Fantasy"],"overview":"In the year 2517, the universe is a vast frontier where lawlessness reigns and adventure awaits! Join Captain Malcolm Reynolds and his ragtag crew aboard the spaceship Serenity as they navigate the fringes of\u2026","poster":"assets/tv-firefly-2002-poster.jpg","backdrop":"assets/tv-firefly-2002-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-20T11:40:08.4202369Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":1437,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":77,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.351,"tmdbVotes":2550}},{"id":"tv-fleabag-2016","title":"Fleabag","year":2016,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":8.278,"criticRating":null,"genres":["Comedy","Drama"],"overview":"A portrait into the mind of a dry-witted, sexual, angry, porn-watching, grief-riddled woman, trying to make sense of the world. As she hurls herself headlong at modern living, Fleabag is thrown roughly up against the\u2026","poster":"assets/tv-fleabag-2016-poster.jpg","backdrop":"assets/tv-fleabag-2016-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T17:42:25.4848214Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":67070,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.3,"tmdbVotes":1993}},{"id":"tv-gravity-falls-2012","title":"Gravity Falls","year":2012,"type":"tv","runtimeSeconds":1320,"seasonCount":2,"communityRating":8.619,"criticRating":null,"genres":["Action & Adventure","Animation","Comedy"],"overview":"Twin brother and sister Dipper and Mabel Pines are in for an unexpected adventure when they spend the summer helping their great uncle Stan run a tourist trap in the mysterious town of Gravity Falls, Oregon.","poster":"assets/tv-gravity-falls-2012-poster.jpg","backdrop":"assets/tv-gravity-falls-2012-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0435827Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":40075,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.624,"tmdbVotes":3647}},{"id":"tv-invincible-2021","title":"INVINCIBLE","year":2021,"type":"tv","runtimeSeconds":null,"seasonCount":4,"communityRating":8.638,"criticRating":null,"genres":["Animation","Drama","Sci-Fi & Fantasy"],"overview":"Mark Grayson is a normal teenager except for the fact that his father is the most powerful superhero on the planet. Shortly after his seventeenth birthday, Mark begins to develop powers of his own and enters into his\u2026","poster":"assets/tv-invincible-2021-poster.jpg","backdrop":"assets/tv-invincible-2021-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.040159Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":95557,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":99,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.6,"tmdbVotes":6155}},{"id":"tv-the-legend-of-korra-2012","title":"The Legend of Korra","year":2012,"type":"tv","runtimeSeconds":1380,"seasonCount":4,"communityRating":8.2,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"Avatar Korra, a headstrong, rebellious, feisty young woman who continually challenges and breaks with tradition, is on her quest to become a fully realized Avatar. In this story, the Avatar struggles to find balance\u2026","poster":"assets/tv-the-legend-of-korra-2012-poster.jpg","backdrop":"assets/tv-the-legend-of-korra-2012-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-20T00:19:23.2494945Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":33880,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":88,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.221,"tmdbVotes":2482}},{"id":"tv-love-death-robots-2019","title":"Love, Death & Robots","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":4,"communityRating":8.205,"criticRating":null,"genres":["Animation","Sci-Fi & Fantasy"],"overview":"Terrifying creatures, wicked surprises and dark comedy converge in this NSFW anthology of animated stories presented by Tim Miller and David Fincher.","poster":"assets/tv-love-death-robots-2019-poster.jpg","backdrop":"assets/tv-love-death-robots-2019-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-20T11:31:20.8818757Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":86831,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":89,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.203,"tmdbVotes":4238}},{"id":"tv-norsemen-2016","title":"Norsemen","year":2016,"type":"tv","runtimeSeconds":1800,"seasonCount":3,"communityRating":7.177,"criticRating":null,"genres":["Comedy","Drama"],"overview":"Norsemen is an epic and humorous drama series set in the Viking Age. The residents of an 8th-century Viking village experience political rivalry, social change and innovations that upend their culture and way of life.","poster":"assets/tv-norsemen-2016-poster.jpg","backdrop":"assets/tv-norsemen-2016-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.034182Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":68126,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.2,"tmdbVotes":233}},{"id":"tv-rick-and-morty-2013","title":"Rick and Morty","year":2013,"type":"tv","runtimeSeconds":null,"seasonCount":9,"communityRating":8.679,"criticRating":null,"genres":["Animation","Comedy","Sci-Fi & Fantasy"],"overview":"Follows a sociopathic genius scientist who drags his inherently timid grandson on adventures across the universe.","poster":"assets/tv-rick-and-morty-2013-poster.jpg","backdrop":"assets/tv-rick-and-morty-2013-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0419581Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":60625,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":91,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.7,"tmdbVotes":11548}},{"id":"tv-secret-level-2024","title":"Secret Level","year":2024,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":7.411,"criticRating":null,"genres":["Animation","Sci-Fi & Fantasy","Action & Adventure"],"overview":"Adult animated series of original short stories which are set within the worlds of beloved video games. Each episode serves as a gateway to a new adventure, unlocking exciting worlds from beloved gaming classics and\u2026","poster":"assets/tv-secret-level-2024-poster.jpg","backdrop":"assets/tv-secret-level-2024-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0336417Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":261579,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":65,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.392,"tmdbVotes":612}},{"id":"tv-silo-2023","title":"Silo","year":2023,"type":"tv","runtimeSeconds":null,"seasonCount":3,"communityRating":8.178,"criticRating":null,"genres":["Sci-Fi & Fantasy","Drama"],"overview":"In a ruined and toxic future, thousands live in a giant silo deep underground. After its sheriff breaks a cardinal rule and residents die mysteriously, engineer Juliette starts to uncover shocking secrets and the\u2026","poster":"assets/tv-silo-2023-poster.jpg","backdrop":"assets/tv-silo-2023-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0346526Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":125988,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":92,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.232,"tmdbVotes":2881}},{"id":"tv-south-park-1997","title":"South Park","year":1997,"type":"tv","runtimeSeconds":null,"seasonCount":29,"communityRating":8.336,"criticRating":null,"genres":["Animation","Comedy"],"overview":"Follow the misadventures of four irreverent grade-schoolers in the quiet, dysfunctional town of South Park, Colorado.","poster":"assets/tv-south-park-1997-poster.jpg","backdrop":"assets/tv-south-park-1997-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0456124Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":2190,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":80,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.332,"tmdbVotes":5250}}],"anime":[{"id":"tv-bleach-2004","title":"Bleach","year":2004,"type":"tv","runtimeSeconds":1440,"seasonCount":17,"communityRating":8.363,"criticRating":null,"genres":["Action & Adventure","Animation","Sci-Fi & Fantasy"],"overview":"For as long as he can remember, Ichigo Kurosaki has been able to see ghosts. But when he meets Rukia, a Soul Reaper who battles evil spirits known as Hollows, he finds his life is changed forever. Now, with a\u2026","poster":"assets/tv-bleach-2004-poster.jpg","backdrop":"assets/tv-bleach-2004-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0359827Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":30984,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.4,"tmdbVotes":2331}},{"id":"tv-chainsaw-man-2022","title":"Chainsaw Man","year":2022,"type":"tv","runtimeSeconds":1440,"seasonCount":1,"communityRating":8.515,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"Denji has a simple dream\u2014to live a happy and peaceful life, spending time with a girl he likes. This is a far cry from reality, however, as Denji is forced by the yakuza into killing devils in order to pay off his\u2026","poster":"assets/tv-chainsaw-man-2022-poster.jpg","backdrop":"assets/tv-chainsaw-man-2022-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-20T22:28:13.2095501Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":114410,"artwork":{"posterKind":"center_crop","backdropKind":"backdrop"},"ratings":{"rtCritics":97,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.508,"tmdbVotes":2364}},{"id":"tv-cyberpunk-edgerunners-2022","title":"Cyberpunk: Edgerunners","year":2022,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":8.466,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"In a dystopia riddled with corruption and cybernetic implants, a talented but reckless street kid strives to become a mercenary outlaw \u2014 an edgerunner.","poster":"assets/tv-cyberpunk-edgerunners-2022-poster.jpg","backdrop":"assets/tv-cyberpunk-edgerunners-2022-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-20T22:28:13.2093107Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":105248,"artwork":{"posterKind":"center_crop","backdropKind":"backdrop"},"ratings":{"rtCritics":89,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.507,"tmdbVotes":2132}},{"id":"tv-dan-da-dan-2024","title":"Dan Da Dan","year":2024,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":8.538,"criticRating":null,"genres":["Animation","Action & Adventure","Comedy"],"overview":"In a bet to prove whether ghosts or aliens exist, two high schoolers face terrifying paranormal threats, gain superpowers and maybe even fall in love?!","poster":"assets/tv-dan-da-dan-2024-poster.jpg","backdrop":"assets/tv-dan-da-dan-2024-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-22T10:31:16.2652252Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":240411,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.517,"tmdbVotes":986}},{"id":"tv-dr-stone-2019","title":"Dr. STONE","year":2019,"type":"tv","runtimeSeconds":1440,"seasonCount":4,"communityRating":8.541,"criticRating":null,"genres":["Animation","Action & Adventure","Comedy"],"overview":"One fateful day, all of humanity was petrified by a blinding flash of light. After several millennia, high schooler Taiju awakens and finds himself lost in a world of statues. However, he\u2019s not alone! His\u2026","poster":"assets/tv-dr-stone-2019-poster.jpg","backdrop":"assets/tv-dr-stone-2019-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-20T22:28:13.2091579Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":86031,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.53,"tmdbVotes":1814}},{"id":"tv-frieren-beyond-journey-s-end-2023","title":"Frieren: Beyond Journey's End","year":2023,"type":"tv","runtimeSeconds":1500,"seasonCount":2,"communityRating":8.803,"criticRating":null,"genres":["Animation","Action & Adventure","Drama"],"overview":"After the party of heroes defeated the Demon King, they restored peace to the land and returned to lives of solitude. Generations pass, and the elven mage Frieren comes face to face with humanity\u2019s mortality. She\u2026","poster":"assets/tv-frieren-beyond-journey-s-end-2023-poster.jpg","backdrop":"assets/tv-frieren-beyond-journey-s-end-2023-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-20T22:28:13.2094435Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":209867,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.826,"tmdbVotes":1016}},{"id":"tv-fullmetal-alchemist-brotherhood-2009","title":"Fullmetal Alchemist: Brotherhood","year":2009,"type":"tv","runtimeSeconds":1500,"seasonCount":1,"communityRating":8.7,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"Disregard for alchemy\u2019s laws ripped half of Edward Elric\u2019s limbs from his body and left his brother Alphonse\u2019s soul clinging to a suit of armor. To restore what was lost, the brothers seek the Philosopher\u2019s Stone.\u2026","poster":"assets/tv-fullmetal-alchemist-brotherhood-2009-poster.jpg","backdrop":"assets/tv-fullmetal-alchemist-brotherhood-2009-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-20T10:27:12.3573939Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":31911,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.7,"tmdbVotes":2633}},{"id":"tv-jujutsu-kaisen-2020","title":"JUJUTSU KAISEN","year":2020,"type":"tv","runtimeSeconds":1440,"seasonCount":3,"communityRating":8.583,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"Yuji Itadori is a boy with tremendous physical strength, though he lives a completely ordinary high school life. One day, to save a classmate who has been attacked by curses, he eats the finger of Ryomen Sukuna,\u2026","poster":"assets/tv-jujutsu-kaisen-2020-poster.jpg","backdrop":"assets/tv-jujutsu-kaisen-2020-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-20T22:28:13.207573Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":95479,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.574,"tmdbVotes":4735}},{"id":"tv-kaiju-no-8-2024","title":"Kaiju No. 8","year":2024,"type":"tv","runtimeSeconds":1440,"seasonCount":2,"communityRating":8.436,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"In a world plagued by creatures known as Kaiju, Kafka Hibino aspired to enlist in The Defense Force. He makes a promise to enlist with his childhood friend, Mina Ashiro. Soon, life takes them in separate ways. While\u2026","poster":"assets/tv-kaiju-no-8-2024-poster.jpg","backdrop":"assets/tv-kaiju-no-8-2024-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-22T10:31:16.2646566Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":207468,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.4,"tmdbVotes":836}},{"id":"tv-my-hero-academia-2016","title":"My Hero Academia","year":2016,"type":"tv","runtimeSeconds":1440,"seasonCount":8,"communityRating":8.607,"criticRating":null,"genres":["Action & Adventure","Animation","Sci-Fi & Fantasy"],"overview":"After he saves a bully from a Villain, a normal student is granted a superpower that allows him to attend a high school training academy for Heroes.","poster":"assets/tv-my-hero-academia-2016-poster.jpg","backdrop":"assets/tv-my-hero-academia-2016-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-20T22:28:13.2089315Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":65930,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.6,"tmdbVotes":5426}},{"id":"tv-neon-genesis-evangelion-1995","title":"Neon Genesis Evangelion","year":1995,"type":"tv","runtimeSeconds":1500,"seasonCount":1,"communityRating":8.568,"criticRating":null,"genres":["Sci-Fi & Fantasy","Animation","Drama"],"overview":"At the turn of the century, the Angels returned to Earth, seeking to wipe out humanity in an apocalyptic fury. Devastated, mankind's last remnants moved underground to wait for the day when the Angels would come back\u2026","poster":"assets/tv-neon-genesis-evangelion-1995-poster.jpg","backdrop":"assets/tv-neon-genesis-evangelion-1995-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0340629Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":890,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.56,"tmdbVotes":2205}},{"id":"tv-record-of-ragnarok-2021","title":"Record of Ragnarok","year":2021,"type":"tv","runtimeSeconds":null,"seasonCount":3,"communityRating":8.402,"criticRating":null,"genres":["Action & Adventure","Animation","Sci-Fi & Fantasy"],"overview":"Before eradicating humankind from the world, the gods give them one last chance to prove themselves worthy of survival. Let the Ragnarok battles begin.","poster":"assets/tv-record-of-ragnarok-2021-poster.jpg","backdrop":"assets/tv-record-of-ragnarok-2021-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-20T22:28:13.2085766Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":114868,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.403,"tmdbVotes":1929}},{"id":"tv-sakamoto-days-2025","title":"SAKAMOTO DAYS","year":2025,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":8.071,"criticRating":null,"genres":["Animation","Comedy","Action & Adventure"],"overview":"Once the greatest hitman of all, Taro Sakamoto retired in the name of love. But when his past catches up, he must fight to protect his beloved family.","poster":"assets/tv-sakamoto-days-2025-poster.jpg","backdrop":"assets/tv-sakamoto-days-2025-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-22T10:31:16.266066Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":207332,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.057,"tmdbVotes":375}},{"id":"tv-sentenced-to-be-a-hero-2025","title":"Sentenced to Be a Hero","year":2025,"type":"tv","runtimeSeconds":1440,"seasonCount":1,"communityRating":8.338,"criticRating":null,"genres":["Animation","Sci-Fi & Fantasy","Action & Adventure"],"overview":"In a world where heroism is a punishment, Xylo Forbartz, a condemned goddess killer, battles endless hordes of monstrous abominations as part of Penal Hero Unit 9004. Death is no escape, only a cycle of resurrection\u2026","poster":"assets/tv-sentenced-to-be-a-hero-2025-poster.jpg","backdrop":"assets/tv-sentenced-to-be-a-hero-2025-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-22T10:31:16.2666791Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":249907,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.244,"tmdbVotes":129}},{"id":"tv-spy-x-family-2022","title":"SPY x FAMILY","year":2022,"type":"tv","runtimeSeconds":1440,"seasonCount":3,"communityRating":8.506,"criticRating":null,"genres":["Animation","Action & Adventure","Comedy"],"overview":"A spy, an assassin and a telepath come together to pose as a family, each for their own reasons, while hiding their true identities from each other.","poster":"assets/tv-spy-x-family-2022-poster.jpg","backdrop":"assets/tv-spy-x-family-2022-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-22T10:31:16.2670364Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":120089,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.5,"tmdbVotes":2382}},{"id":"tv-the-tatami-galaxy-2010","title":"The Tatami Galaxy","year":2010,"type":"tv","runtimeSeconds":1500,"seasonCount":2,"communityRating":8.271,"criticRating":null,"genres":["Animation","Comedy","Drama"],"overview":"When a college dropout stops for a late night bite at a mysterious ramen stand, he crosses paths with a self-proclaimed deity of matrimony. This bizarre meeting sends the young man hurtling through a horrifying\u2026","poster":"assets/tv-the-tatami-galaxy-2010-poster.jpg","backdrop":"assets/tv-the-tatami-galaxy-2010-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-18T05:52:51.0023256Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":36243,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.3,"tmdbVotes":152}},{"id":"tv-vinland-saga-2019","title":"Vinland Saga","year":2019,"type":"tv","runtimeSeconds":1500,"seasonCount":2,"communityRating":8.527,"criticRating":null,"genres":["Animation","War & Politics","Action & Adventure"],"overview":"For a thousand years, the Vikings have made quite a name and reputation for themselves as the strongest families with a thirst for violence. Thorfinn, the son of one of the Vikings' greatest warriors, spends his\u2026","poster":"assets/tv-vinland-saga-2019-poster.jpg","backdrop":"assets/tv-vinland-saga-2019-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-20T22:28:13.207389Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":88803,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.509,"tmdbVotes":1064}},{"id":"tv-yu-yu-hakusho-1992","title":"Yu Yu Hakusho","year":1992,"type":"tv","runtimeSeconds":1440,"seasonCount":4,"communityRating":8.5,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"After dying to save a boy, delinquent tough guy Yusuke Urameshi is granted another chance at life by redeeming himself as a \"Spirit Detective.\"","poster":"assets/tv-yu-yu-hakusho-1992-poster.jpg","backdrop":"assets/tv-yu-yu-hakusho-1992-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-19T21:46:01.5733049Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":30669,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.475,"tmdbVotes":519}}],"resume":[],"nextUp":[{"id":"episode-three-monsters-1992-s1e6","title":"Three Monsters","year":1992,"type":"episode","runtimeSeconds":1421,"seasonCount":null,"communityRating":7.4,"criticRating":null,"genres":["Animation","Action","Adventure"],"overview":"Yusuke receives his first real case as Spirit Detective. Three demon thieves have muscled their way into King Yama's sacred vault, stealing the three Artifacts of Darkness. Yusuke must recover the artifacts and bring\u2026","poster":"assets/episode-three-monsters-1992-s1e6-poster.jpg","backdrop":"assets/episode-three-monsters-1992-s1e6-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-19T21:59:21.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","seriesTitle":"Yu Yu Hakusho","seasonNumber":1,"episodeNumber":6,"artwork":{"posterKind":"poster","backdropKind":"backdrop"}},{"id":"episode-all-hands-on-deck-class-1-a-2021-s5e1","title":"All Hands on Deck! Class 1-A","year":2021,"type":"episode","runtimeSeconds":1433,"seasonCount":null,"communityRating":6.938,"criticRating":null,"genres":["Animation","Action","Adventure"],"overview":"There's an emergency drill at U.A. High School, and Class 1-A is requested to report for duty!","poster":"assets/episode-all-hands-on-deck-class-1-a-2021-s5e1-poster.jpg","backdrop":"assets/episode-all-hands-on-deck-class-1-a-2021-s5e1-backdrop.jpg","played":false,"playCount":2,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-22T04:04:50.0000000Z","lastPlayedAt":"2026-10-19T17:47:09.3028025Z","availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","seriesTitle":"My Hero Academia","seasonNumber":5,"episodeNumber":1,"artwork":{"posterKind":"poster","backdropKind":"backdrop"}},{"id":"episode-erickerhead-2026-s9e6","title":"Erickerhead","year":2026,"type":"episode","runtimeSeconds":1357,"seasonCount":null,"communityRating":8.196,"criticRating":null,"genres":[],"overview":"Rick's stomach is mad, broh. But it's all-you-can-eat-and-drink here, broh!","poster":"assets/episode-erickerhead-2026-s9e6-poster.jpg","backdrop":"assets/episode-erickerhead-2026-s9e6-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-28T10:23:23.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","seriesTitle":"Rick and Morty","seasonNumber":9,"episodeNumber":6,"artwork":{"posterKind":"poster","backdropKind":"backdrop"}},{"id":"episode-girls-interrupted-2007-s1e7","title":"Girls, Interrupted","year":2007,"type":"episode","runtimeSeconds":1642,"seasonCount":null,"communityRating":7.4,"criticRating":null,"genres":["Comedy","Drama"],"overview":"Hank is disturbed by Becca's negative reaction towards the concept of happy endings, even more so when he finds out that it is partially his fault.\nMarcy comes up with the idea of a threesome with Charlie and Dani,\u2026","poster":"assets/episode-girls-interrupted-2007-s1e7-poster.jpg","backdrop":"assets/episode-girls-interrupted-2007-s1e7-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-05T02:46:18.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","seriesTitle":"Californication","seasonNumber":1,"episodeNumber":7,"artwork":{"posterKind":"poster","backdropKind":"backdrop"}},{"id":"episode-announcement-2022-s1e7","title":"Announcement","year":2022,"type":"episode","runtimeSeconds":3012,"seasonCount":null,"communityRating":7.8,"criticRating":null,"genres":["Action","Adventure","Drama"],"overview":"The repercussions of the Aldhani heist reach all the way to Coruscant, while Cassian returns home.","poster":"assets/episode-announcement-2022-s1e7-poster.jpg","backdrop":"assets/episode-announcement-2022-s1e7-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T12:56:24.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","seriesTitle":"Andor","seasonNumber":1,"episodeNumber":7,"artwork":{"posterKind":"poster","backdropKind":"backdrop"}},{"id":"episode-south-american-biker-gangs-2026-s29e1","title":"South American Biker Gangs","year":2026,"type":"episode","runtimeSeconds":1335,"seasonCount":null,"communityRating":6.4,"criticRating":null,"genres":["Animation","Comedy"],"overview":"When e-bikes arrive in South America, the boys take over the streets and the parents of South America can hardly recognize South America.","poster":"assets/episode-south-american-biker-gangs-2026-s29e1-poster.jpg","backdrop":"assets/episode-south-american-biker-gangs-2026-s29e1-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-01T06:40:46.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","seriesTitle":"South Park","seasonNumber":29,"episodeNumber":1,"artwork":{"posterKind":"poster","backdropKind":"backdrop"}}],"recentlyAdded":[{"id":"movie-steins-gate-the-movie-load-region-of-deja-vu-2013","title":"Steins;Gate: The Movie - Load Region of D\u00e9j\u00e0 Vu","year":2013,"type":"movie","runtimeSeconds":5403,"seasonCount":null,"communityRating":7.8,"criticRating":null,"genres":["Animation","Mystery","Sci-Fi"],"overview":"After the events of the anime, Rintarou begins to feel the repercussions of extensive time travel, and eventually completely fades from reality. Kurisu, being the only companion to remember him, now must find a way\u2026","poster":"assets/movie-steins-gate-the-movie-load-region-of-deja-vu-2013-poster.jpg","backdrop":"assets/movie-steins-gate-the-movie-load-region-of-deja-vu-2013-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-22T14:55:54.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","artwork":{"posterKind":"poster","backdropKind":"backdrop"}},{"id":"tv-yu-yu-hakusho-1992","title":"Yu Yu Hakusho","year":1992,"type":"tv","runtimeSeconds":1440,"seasonCount":4,"communityRating":8.5,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"After dying to save a boy, delinquent tough guy Yusuke Urameshi is granted another chance at life by redeeming himself as a \"Spirit Detective.\"","poster":"assets/tv-yu-yu-hakusho-1992-poster.jpg","backdrop":"assets/tv-yu-yu-hakusho-1992-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-19T21:46:01.5733049Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":30669,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.475,"tmdbVotes":519}},{"id":"movie-memories-1995","title":"Memories","year":1995,"type":"movie","runtimeSeconds":6805,"seasonCount":null,"communityRating":7.465,"criticRating":null,"genres":["Fantasy","Animation","Science Fiction"],"overview":"Three back-to-back anime films by three different directors make up this sci-fi trilogy three years in the making.","poster":"assets/movie-memories-1995-poster.jpg","backdrop":"assets/movie-memories-1995-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-30T21:36:03.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":42994,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":82,"rtAudienceLabel":"Upright","imdb":7.5,"imdbVotes":26638,"tmdb":7.459,"tmdbVotes":622}},{"id":"tv-firefly-2002","title":"Firefly","year":2002,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":8.347,"criticRating":null,"genres":["Drama","Action & Adventure","Sci-Fi & Fantasy"],"overview":"In the year 2517, the universe is a vast frontier where lawlessness reigns and adventure awaits! Join Captain Malcolm Reynolds and his ragtag crew aboard the spaceship Serenity as they navigate the fringes of\u2026","poster":"assets/tv-firefly-2002-poster.jpg","backdrop":"assets/tv-firefly-2002-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-20T11:40:08.4202369Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":1437,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":77,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.351,"tmdbVotes":2550}},{"id":"tv-love-death-robots-2019","title":"Love, Death & Robots","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":4,"communityRating":8.205,"criticRating":null,"genres":["Animation","Sci-Fi & Fantasy"],"overview":"Terrifying creatures, wicked surprises and dark comedy converge in this NSFW anthology of animated stories presented by Tim Miller and David Fincher.","poster":"assets/tv-love-death-robots-2019-poster.jpg","backdrop":"assets/tv-love-death-robots-2019-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-20T11:31:20.8818757Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":86831,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":89,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.203,"tmdbVotes":4238}},{"id":"tv-the-legend-of-korra-2012","title":"The Legend of Korra","year":2012,"type":"tv","runtimeSeconds":1380,"seasonCount":4,"communityRating":8.2,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"Avatar Korra, a headstrong, rebellious, feisty young woman who continually challenges and breaks with tradition, is on her quest to become a fully realized Avatar. In this story, the Avatar struggles to find balance\u2026","poster":"assets/tv-the-legend-of-korra-2012-poster.jpg","backdrop":"assets/tv-the-legend-of-korra-2012-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-20T00:19:23.2494945Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":33880,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":88,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.221,"tmdbVotes":2482}},{"id":"tv-spy-x-family-2022","title":"SPY x FAMILY","year":2022,"type":"tv","runtimeSeconds":1440,"seasonCount":3,"communityRating":8.506,"criticRating":null,"genres":["Animation","Action & Adventure","Comedy"],"overview":"A spy, an assassin and a telepath come together to pose as a family, each for their own reasons, while hiding their true identities from each other.","poster":"assets/tv-spy-x-family-2022-poster.jpg","backdrop":"assets/tv-spy-x-family-2022-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-22T10:31:16.2670364Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":120089,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.5,"tmdbVotes":2382}},{"id":"tv-sentenced-to-be-a-hero-2025","title":"Sentenced to Be a Hero","year":2025,"type":"tv","runtimeSeconds":1440,"seasonCount":1,"communityRating":8.338,"criticRating":null,"genres":["Animation","Sci-Fi & Fantasy","Action & Adventure"],"overview":"In a world where heroism is a punishment, Xylo Forbartz, a condemned goddess killer, battles endless hordes of monstrous abominations as part of Penal Hero Unit 9004. Death is no escape, only a cycle of resurrection\u2026","poster":"assets/tv-sentenced-to-be-a-hero-2025-poster.jpg","backdrop":"assets/tv-sentenced-to-be-a-hero-2025-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-22T10:31:16.2666791Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":249907,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.244,"tmdbVotes":129}},{"id":"tv-sakamoto-days-2025","title":"SAKAMOTO DAYS","year":2025,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":8.071,"criticRating":null,"genres":["Animation","Comedy","Action & Adventure"],"overview":"Once the greatest hitman of all, Taro Sakamoto retired in the name of love. But when his past catches up, he must fight to protect his beloved family.","poster":"assets/tv-sakamoto-days-2025-poster.jpg","backdrop":"assets/tv-sakamoto-days-2025-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-22T10:31:16.266066Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":207332,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.057,"tmdbVotes":375}},{"id":"tv-dan-da-dan-2024","title":"Dan Da Dan","year":2024,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":8.538,"criticRating":null,"genres":["Animation","Action & Adventure","Comedy"],"overview":"In a bet to prove whether ghosts or aliens exist, two high schoolers face terrifying paranormal threats, gain superpowers and maybe even fall in love?!","poster":"assets/tv-dan-da-dan-2024-poster.jpg","backdrop":"assets/tv-dan-da-dan-2024-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-22T10:31:16.2652252Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":240411,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.517,"tmdbVotes":986}},{"id":"tv-kaiju-no-8-2024","title":"Kaiju No. 8","year":2024,"type":"tv","runtimeSeconds":1440,"seasonCount":2,"communityRating":8.436,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"In a world plagued by creatures known as Kaiju, Kafka Hibino aspired to enlist in The Defense Force. He makes a promise to enlist with his childhood friend, Mina Ashiro. Soon, life takes them in separate ways. While\u2026","poster":"assets/tv-kaiju-no-8-2024-poster.jpg","backdrop":"assets/tv-kaiju-no-8-2024-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-22T10:31:16.2646566Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":207468,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.4,"tmdbVotes":836}},{"id":"tv-chainsaw-man-2022","title":"Chainsaw Man","year":2022,"type":"tv","runtimeSeconds":1440,"seasonCount":1,"communityRating":8.515,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"Denji has a simple dream\u2014to live a happy and peaceful life, spending time with a girl he likes. This is a far cry from reality, however, as Denji is forced by the yakuza into killing devils in order to pay off his\u2026","poster":"assets/tv-chainsaw-man-2022-poster.jpg","backdrop":"assets/tv-chainsaw-man-2022-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-20T22:28:13.2095501Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":114410,"artwork":{"posterKind":"center_crop","backdropKind":"backdrop"},"ratings":{"rtCritics":97,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.508,"tmdbVotes":2364}}],"discover":[{"id":"movie-the-amazing-spider-man-2012","title":"The Amazing Spider-Man","year":2012,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"A teenage Peter Parker grapples with both high school and amazing super-human crises as his alter-ego Spider-Man.","poster":"assets/movie-the-amazing-spider-man-2012-poster.jpg","backdrop":"assets/movie-the-amazing-spider-man-2012-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1930,"ratings":{"rtCritics":71,"rtCriticsLabel":"Certified Fresh","rtAudience":77,"rtAudienceLabel":"Upright","imdb":7,"imdbVotes":791938,"tmdb":6.768,"tmdbVotes":19312}},{"id":"movie-the-amazing-spider-man-2-2014","title":"The Amazing Spider-Man 2","year":2014,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"For Peter Parker, life is busy. Between taking out the bad guys as Spider-Man and spending time with the person he loves, Gwen Stacy, high school graduation cannot come quickly enough. Peter has not forgotten about\u2026","poster":"assets/movie-the-amazing-spider-man-2-2014-poster.jpg","backdrop":"assets/movie-the-amazing-spider-man-2-2014-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":102382,"ratings":{"rtCritics":51,"rtCriticsLabel":"Rotten","rtAudience":64,"rtAudienceLabel":"Upright","imdb":6.6,"imdbVotes":611981,"tmdb":6.567,"tmdbVotes":14919}},{"id":"movie-the-animatrix-2003","title":"The Animatrix","year":2003,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Science Fiction"],"overview":"Straight from the creators of the groundbreaking Matrix trilogy, this collection of short animated films from the world's leading anime directors fuses computer graphics and Japanese anime to provide the background\u2026","poster":"assets/movie-the-animatrix-2003-poster.jpg","backdrop":"assets/movie-the-animatrix-2003-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":55931,"ratings":{"rtCritics":86,"rtCriticsLabel":"Fresh","rtAudience":78,"rtAudienceLabel":"Upright","imdb":7.3,"imdbVotes":91929,"tmdb":7.221,"tmdbVotes":1872}},{"id":"movie-ant-man-and-the-wasp-quantumania-2023","title":"Ant-Man and the Wasp: Quantumania","year":2023,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"Super-Hero partners Scott Lang and Hope van Dyne, along with with Hope's parents Janet van Dyne and Hank Pym, and Scott's daughter Cassie Lang, find themselves exploring the Quantum Realm, interacting with strange\u2026","poster":"assets/movie-ant-man-and-the-wasp-quantumania-2023-poster.jpg","backdrop":"assets/movie-ant-man-and-the-wasp-quantumania-2023-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":640146,"ratings":{"rtCritics":46,"rtCriticsLabel":"Rotten","rtAudience":81,"rtAudienceLabel":"Upright","imdb":6,"imdbVotes":281738,"tmdb":6.197,"tmdbVotes":6236}},{"id":"movie-appleseed-alpha-2014","title":"Appleseed Alpha","year":2014,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Science Fiction","Action"],"overview":"The Third World War (2099\u20132126) devastated part of the Earth. Former nations are reforming while new powers emerge, and groups of humans struggle to survive in ruined cities. The story follows Deunan Knute and her\u2026","poster":"assets/movie-appleseed-alpha-2014-poster.jpg","backdrop":"assets/movie-appleseed-alpha-2014-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"center_crop","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":269650,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":59,"rtAudienceLabel":"Spilled","imdb":6.5,"imdbVotes":9689,"tmdb":6.808,"tmdbVotes":436}},{"id":"movie-aquaman-and-the-lost-kingdom-2023","title":"Aquaman and the Lost Kingdom","year":2023,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Fantasy"],"overview":"Black Manta seeks revenge on Aquaman for his father's death. Wielding the Black Trident's power, he becomes a formidable foe. To defend Atlantis, Arthur (Aquaman) forges an alliance with his imprisoned brother. They\u2026","poster":"assets/movie-aquaman-and-the-lost-kingdom-2023-poster.jpg","backdrop":"assets/movie-aquaman-and-the-lost-kingdom-2023-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":572802,"ratings":{"rtCritics":33,"rtCriticsLabel":"Rotten","rtAudience":79,"rtAudienceLabel":"Upright","imdb":5.6,"imdbVotes":122422,"tmdb":6.48,"tmdbVotes":3748}},{"id":"movie-the-avengers-2012","title":"The Avengers","year":2012,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Science Fiction","Action","Adventure"],"overview":"When an unexpected enemy emerges and threatens global safety and security, Nick Fury, director of the international peacekeeping agency known as S.H.I.E.L.D., finds himself in need of a team to pull the world back\u2026","poster":"assets/movie-the-avengers-2012-poster.jpg","backdrop":"assets/movie-the-avengers-2012-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":24428,"ratings":{"rtCritics":91,"rtCriticsLabel":"Certified Fresh","rtAudience":91,"rtAudienceLabel":"Upright","imdb":8,"imdbVotes":1590693,"tmdb":8.084,"tmdbVotes":40262}},{"id":"movie-avengers-confidential-black-widow-punisher-2014","title":"Avengers Confidential: Black Widow & Punisher","year":2014,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Science Fiction","Action"],"overview":"When the Punisher takes out a black-market weapons dealer, he stumbles upon a far-reaching terrorist plot devised by a group known as Leviathan.","poster":"assets/movie-avengers-confidential-black-widow-punisher-2014-poster.jpg","backdrop":"assets/movie-avengers-confidential-black-widow-punisher-2014-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":257346,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":55,"rtAudienceLabel":"Spilled","imdb":5.7,"imdbVotes":5166,"tmdb":6.368,"tmdbVotes":303}},{"id":"movie-avengers-age-of-ultron-2015","title":"Avengers: Age of Ultron","year":2015,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"When Tony Stark tries to jumpstart a dormant peacekeeping program, things go awry and Earth\u2019s Mightiest Heroes are put to the ultimate test as the fate of the planet hangs in the balance. As the villainous Ultron\u2026","poster":"assets/movie-avengers-age-of-ultron-2015-poster.jpg","backdrop":"assets/movie-avengers-age-of-ultron-2015-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":99861,"ratings":{"rtCritics":75,"rtCriticsLabel":"Certified Fresh","rtAudience":82,"rtAudienceLabel":"Upright","imdb":7.3,"imdbVotes":1025876,"tmdb":7.278,"tmdbVotes":25289}},{"id":"movie-avengers-infinity-war-2018","title":"Avengers: Infinity War","year":2018,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Adventure","Action","Science Fiction"],"overview":"As the Avengers and their allies have continued to protect the world from threats too large for any one hero to handle, a new danger has emerged from the cosmic shadows: Thanos. A despot of intergalactic infamy, his\u2026","poster":"assets/movie-avengers-infinity-war-2018-poster.jpg","backdrop":"assets/movie-avengers-infinity-war-2018-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":299536,"ratings":{"rtCritics":85,"rtCriticsLabel":"Certified Fresh","rtAudience":92,"rtAudienceLabel":"Upright","imdb":8.4,"imdbVotes":1421954,"tmdb":8.246,"tmdbVotes":33331}},{"id":"movie-batman-ninja-2018","title":"Batman Ninja","year":2018,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Action","Science Fiction"],"overview":"Batman, along with many of his allies and adversaries, finds himself transported to feudal Japan by Gorilla Grodd's time displacement machine.","poster":"assets/movie-batman-ninja-2018-poster.jpg","backdrop":"assets/movie-batman-ninja-2018-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":485942,"ratings":{"rtCritics":84,"rtCriticsLabel":"Fresh","rtAudience":60,"rtAudienceLabel":"Upright","imdb":5.6,"imdbVotes":24579,"tmdb":5.9,"tmdbVotes":1106}},{"id":"movie-batman-v-superman-dawn-of-justice-2016","title":"Batman v Superman: Dawn of Justice","year":2016,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Fantasy"],"overview":"Fearing the actions of a god-like Super Hero left unchecked, Gotham City\u2019s own formidable, forceful vigilante takes on Metropolis\u2019s most revered, modern-day savior, while the world wrestles with what sort of hero it\u2026","poster":"assets/movie-batman-v-superman-dawn-of-justice-2016-poster.jpg","backdrop":"assets/movie-batman-v-superman-dawn-of-justice-2016-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":209112,"ratings":{"rtCritics":28,"rtCriticsLabel":"Rotten","rtAudience":63,"rtAudienceLabel":"Upright","imdb":6.4,"imdbVotes":801382,"tmdb":6.014,"tmdbVotes":19527}},{"id":"movie-batman-the-dark-knight-returns-part-1-2012","title":"Batman: The Dark Knight Returns, Part 1","year":2012,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Science Fiction","Action","Animation"],"overview":"Batman has not been seen for ten years. A new breed of criminal ravages Gotham City, forcing 55-year-old Bruce Wayne back into the cape and cowl. But, does he still have what it takes to fight crime in a new era?","poster":"assets/movie-batman-the-dark-knight-returns-part-1-2012-poster.jpg","backdrop":"assets/movie-batman-the-dark-knight-returns-part-1-2012-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":123025,"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":93,"rtAudienceLabel":"Upright","imdb":7.9,"imdbVotes":68943,"tmdb":7.742,"tmdbVotes":1766}},{"id":"movie-black-adam-2022","title":"Black Adam","year":2022,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"Nearly 5,000 years after he was bestowed with the almighty powers of the Egyptian gods\u2014and imprisoned just as quickly\u2014Black Adam is freed from his earthly tomb, ready to unleash his unique form of justice on the\u2026","poster":"assets/movie-black-adam-2022-poster.jpg","backdrop":"assets/movie-black-adam-2022-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":436270,"ratings":{"rtCritics":39,"rtCriticsLabel":"Rotten","rtAudience":87,"rtAudienceLabel":"Upright","imdb":6.1,"imdbVotes":309624,"tmdb":6.747,"tmdbVotes":7370}},{"id":"movie-black-panther-2018","title":"Black Panther","year":2018,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"King T'Challa returns home to the reclusive, technologically advanced African nation of Wakanda to serve as his country's new leader. However, T'Challa soon finds that he is challenged for the throne by factions\u2026","poster":"assets/movie-black-panther-2018-poster.jpg","backdrop":"assets/movie-black-panther-2018-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":284054,"ratings":{"rtCritics":96,"rtCriticsLabel":"Certified Fresh","rtAudience":null,"rtAudienceLabel":"Spilled","imdb":7.3,"imdbVotes":931120,"tmdb":7.36,"tmdbVotes":24190}},{"id":"movie-black-panther-wakanda-forever-2022","title":"Black Panther: Wakanda Forever","year":2022,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"Queen Ramonda, Shuri, M\u2019Baku, Okoye and the Dora Milaje fight to protect their nation from intervening world powers in the wake of King T\u2019Challa\u2019s death. As the Wakandans strive to embrace their next chapter, the\u2026","poster":"assets/movie-black-panther-wakanda-forever-2022-poster.jpg","backdrop":"assets/movie-black-panther-wakanda-forever-2022-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":505642,"ratings":{"rtCritics":84,"rtCriticsLabel":"Certified Fresh","rtAudience":93,"rtAudienceLabel":"Upright","imdb":6.6,"imdbVotes":405088,"tmdb":6.984,"tmdbVotes":7920}},{"id":"movie-blame-2017","title":"BLAME!","year":2017,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Drama","Science Fiction"],"overview":"In the distant technological future, civilization has reached its ultimate Net-based form. An \"infection\" in the past caused the automated systems to spiral out of order, resulting in a multi-leveled city structure\u2026","poster":"assets/movie-blame-2017-poster.jpg","backdrop":"assets/movie-blame-2017-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":409421,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":61,"rtAudienceLabel":"Upright","imdb":6.6,"imdbVotes":10258,"tmdb":6.523,"tmdbVotes":370}},{"id":"movie-bleach-the-movie-fade-to-black-2008","title":"Bleach the Movie: Fade to Black","year":2008,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Animation","Fantasy"],"overview":"A strange disturbance in the World of the Living sends Ichigo and Kon to the Soul Society, where the Seireitei has been devastated by an explosion of reishi and Rukia is missing. Stranger still, none of the Soul\u2026","poster":"assets/movie-bleach-the-movie-fade-to-black-2008-poster.jpg","backdrop":"assets/movie-bleach-the-movie-fade-to-black-2008-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":17165,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":67,"rtAudienceLabel":"Upright","imdb":7.1,"imdbVotes":3693,"tmdb":7.1,"tmdbVotes":206}},{"id":"tv-90-day-fiance-before-the-90-days-2017","title":"90 Day Fianc\u00e9: Before the 90 Days","year":2017,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Reality"],"overview":"Follow couples who have an existing relationship online, but haven't met in person. We'll experience their journey as they travel to the other's foreign country for the first time in an attempt to establish an\u2026","poster":"assets/tv-90-day-fiance-before-the-90-days-2017-poster.jpg","backdrop":"assets/tv-90-day-fiance-before-the-90-days-2017-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":73319,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.5,"tmdbVotes":45}},{"id":"tv-90-day-fiance-the-other-way-2019","title":"90 Day Fianc\u00e9: The Other Way","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Reality"],"overview":"Americans move to a foreign country all in the name of love. Will uprooting their lives in the United States pay off, or will they be packing up and moving back to America brokenhearted?","poster":"assets/tv-90-day-fiance-the-other-way-2019-poster.jpg","backdrop":"assets/tv-90-day-fiance-the-other-way-2019-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":90046,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.8,"tmdbVotes":34}},{"id":"tv-the-100-2014","title":"The 100","year":2014,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Sci-Fi & Fantasy","Action & Adventure","Drama"],"overview":"100 years in the future, when the Earth has been abandoned due to radioactivity, the last surviving humans live on an ark orbiting the planet \u2014 but the ark won't last forever. So the repressive regime picks 100\u2026","poster":"assets/tv-the-100-2014-poster.jpg","backdrop":"assets/tv-the-100-2014-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":48866,"ratings":{"rtCritics":93,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.878,"tmdbVotes":8855}},{"id":"tv-the-abbott-and-costello-show-1952","title":"The Abbott and Costello Show","year":1952,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy"],"overview":"Bud and Lou are unemployed actors living in Mr. Fields\u2019 boarding house. Lou\u2019s girlfriend Hillary lives across the hall. Many situations arise leading to slapstick and puns.","poster":"assets/tv-the-abbott-and-costello-show-1952-poster.jpg","backdrop":"assets/tv-the-abbott-and-costello-show-1952-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":11821,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.2,"tmdbVotes":22}},{"id":"tv-accel-world-2012","title":"Accel World","year":2012,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Action & Adventure","Drama"],"overview":"A short, overweight student uses the Neuro Link, an evolution of the Nerve Gear, to escape himself from the reality. But his skills in the virtual world brings him to the attention of Kuroyukihime, a popular student\u2026","poster":"assets/tv-accel-world-2012-poster.jpg","backdrop":"assets/tv-accel-world-2012-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"center_crop","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":43167,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.429,"tmdbVotes":163}},{"id":"tv-ahsoka-2023","title":"Ahsoka","year":2023,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Sci-Fi & Fantasy","Action & Adventure","Drama"],"overview":"Former Jedi Knight Ahsoka Tano investigates an emerging threat to a vulnerable galaxy.","poster":"assets/tv-ahsoka-2023-poster.jpg","backdrop":"assets/tv-ahsoka-2023-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":114461,"ratings":{"rtCritics":85,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.4,"tmdbVotes":1351}},{"id":"tv-american-dad-2005","title":"American Dad!","year":2005,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Comedy"],"overview":"The series focuses on an eccentric motley crew that is the Smith family and their three housemates: Father, husband, and breadwinner Stan Smith; his better half housewife, Francine Smith; their college-aged daughter,\u2026","poster":"assets/tv-american-dad-2005-poster.jpg","backdrop":"assets/tv-american-dad-2005-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1433,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.022,"tmdbVotes":2481}},{"id":"tv-american-gods-2017","title":"American Gods","year":2017,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Mystery","Sci-Fi & Fantasy"],"overview":"An ex-con becomes the traveling partner of a conman who turns out to be one of the older gods trying to recruit troops to battle the upstart deities. Based on Neil Gaiman's fantasy novel.","poster":"assets/tv-american-gods-2017-poster.jpg","backdrop":"assets/tv-american-gods-2017-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":46639,"ratings":{"rtCritics":75,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.1,"tmdbVotes":1852}},{"id":"tv-andromeda-2000","title":"Andromeda","year":2000,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action & Adventure","Drama","Sci-Fi & Fantasy"],"overview":"Captain Dylan Hunt and his crew quest to restore a government that once presided over an extended peace and prosperity.","poster":"assets/tv-andromeda-2000-poster.jpg","backdrop":"assets/tv-andromeda-2000-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":2985,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.068,"tmdbVotes":315}},{"id":"tv-aqua-teen-hunger-force-2000","title":"Aqua Teen Hunger Force","year":2000,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Comedy"],"overview":"The surreal adventures of three anthropomorphic fast food items: Master Shake, Frylock and Meatwad, and their human nextdoor neighbor, Carl Brutananadilewski.","poster":"assets/tv-aqua-teen-hunger-force-2000-poster.jpg","backdrop":"assets/tv-aqua-teen-hunger-force-2000-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":251,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.5,"tmdbVotes":272}},{"id":"tv-arifureta-from-commonplace-to-world-s-strongest-2019","title":"Arifureta: From Commonplace to World's Strongest","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"Hajime Nagumo and his high school class are suddenly summoned to a fantastical land as heroes. But while most of his classmates have powerful stats and abilities, Hajime does not. Underappreciated and unprepared, he\u2026","poster":"assets/tv-arifureta-from-commonplace-to-world-s-strongest-2019-poster.jpg","backdrop":"assets/tv-arifureta-from-commonplace-to-world-s-strongest-2019-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":86034,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.382,"tmdbVotes":662}},{"id":"tv-arrow-2012","title":"Arrow","year":2012,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Crime","Drama","Action & Adventure"],"overview":"Spoiled billionaire playboy Oliver Queen is missing and presumed dead when his yacht is lost at sea. He returns five years later a changed man, determined to clean up the city as a hooded vigilante armed with a bow.","poster":"assets/tv-arrow-2012-poster.jpg","backdrop":"assets/tv-arrow-2012-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1412,"ratings":{"rtCritics":86,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.834,"tmdbVotes":6537}},{"id":"tv-avatar-the-last-airbender-2024","title":"Avatar: The Last Airbender","year":2024,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action & Adventure","Sci-Fi & Fantasy","Drama"],"overview":"A young boy known as the Avatar must master the four elemental powers to save a world at war \u2014 and fight a ruthless enemy bent on stopping him.","poster":"assets/tv-avatar-the-last-airbender-2024-poster.jpg","backdrop":"assets/tv-avatar-the-last-airbender-2024-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":82452,"ratings":{"rtCritics":66,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.8,"tmdbVotes":1406}},{"id":"tv-avatar-seven-havens-2026","title":"Avatar: Seven Havens","year":2026,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"In a world shattered by a devastating cataclysm, a young Earthbender discovers she's the new Avatar after Korra. But in this dangerous era, that title marks her as humanity's destroyer, not its savior. Hunted by both\u2026","poster":"assets/tv-avatar-seven-havens-2026-poster.jpg","backdrop":"assets/tv-avatar-seven-havens-2026-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":284833,"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.9,"tmdbVotes":183}},{"id":"tv-batman-the-brave-and-the-bold-2008","title":"Batman: The Brave and the Bold","year":2008,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"The Caped Crusader is teamed up with Blue Beetle, Green Arrow, Aquaman and countless others in his quest to uphold justice.","poster":"assets/tv-batman-the-brave-and-the-bold-2008-poster.jpg","backdrop":"assets/tv-batman-the-brave-and-the-bold-2008-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":15804,"ratings":{"rtCritics":96,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.6,"tmdbVotes":295}},{"id":"tv-batwoman-2019","title":"Batwoman","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Sci-Fi & Fantasy","Action & Adventure"],"overview":"Kate Kane, armed with a passion for social justice and a flair for speaking her mind, soars onto the streets of Gotham as Batwoman, an out lesbian and highly trained street fighter primed to snuff out the failing\u2026","poster":"assets/tv-batwoman-2019-poster.jpg","backdrop":"assets/tv-batwoman-2019-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":89247,"ratings":{"rtCritics":83,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.8,"tmdbVotes":1619}},{"id":"tv-big-mouth-2017","title":"Big Mouth","year":2017,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy","Animation"],"overview":"Teenage friends find their lives upended by the wonders and horrors of puberty in this edgy comedy from real-life pals Nick Kroll and Andrew Goldberg.","poster":"assets/tv-big-mouth-2017-poster.jpg","backdrop":"assets/tv-big-mouth-2017-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":74204,"ratings":{"rtCritics":95,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.591,"tmdbVotes":1274}},{"id":"tv-black-lightning-2018","title":"Black Lightning","year":2018,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action & Adventure","Sci-Fi & Fantasy","Drama"],"overview":"Jefferson Pierce is a man wrestling with a secret. As the father of two daughters and principal of a charter high school that also serves as a safe haven for young people in a New Orleans neighborhood overrun by gang\u2026","poster":"assets/tv-black-lightning-2018-poster.jpg","backdrop":"assets/tv-black-lightning-2018-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":71663,"ratings":{"rtCritics":92,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.907,"tmdbVotes":991}}],"discoverySource":{"state":"materialized_snapshot","rankKnown":false,"selection":"First 18 alphabetically indexed movie stubs and first 18 series stubs, not ranked feed order","observedAt":"2026-11-04T20:42:12.030108+00:00"}},{"key":"mindel","name":"Mindel","initial":"M","color":"#ff9d72","destinations":{"Home":{"kind":"home"},"Movies":{"kind":"library","collection":"movies"},"Shows":{"kind":"library","collection":"shows"},"Discover":{"kind":"discover","collection":"discover"}},"movies":[{"id":"movie-chicago-2002","title":"Chicago","year":2002,"type":"movie","runtimeSeconds":6808,"seasonCount":null,"communityRating":7.131,"criticRating":87,"genres":["Comedy","Crime","Drama"],"overview":"Murderesses Velma Kelly and Roxie Hart find themselves on death row together and fight for the fame that will keep them from the gallows in 1920s Chicago.","poster":"assets/movie-chicago-2002-poster.jpg","backdrop":"assets/movie-chicago-2002-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:24:53.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":1574,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":87,"rtCriticsLabel":"Certified Fresh","rtAudience":83,"rtAudienceLabel":"Upright","imdb":7.2,"imdbVotes":259272,"tmdb":7.135,"tmdbVotes":3025}},{"id":"movie-coherence-2014","title":"Coherence","year":2014,"type":"movie","runtimeSeconds":5286,"seasonCount":null,"communityRating":7.21,"criticRating":89,"genres":["Thriller","Science Fiction"],"overview":"Four couples gather for dinner the night a mysterious and powerful comet passes overhead.","poster":"assets/movie-coherence-2014-poster.jpg","backdrop":"assets/movie-coherence-2014-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2017-08-12T23:49:00.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":220289,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":89,"rtCriticsLabel":"Certified Fresh","rtAudience":81,"rtAudienceLabel":"Upright","imdb":7.1,"imdbVotes":180354,"tmdb":7.208,"tmdbVotes":3702}},{"id":"movie-the-killing-of-a-sacred-deer-2017","title":"The Killing of a Sacred Deer","year":2017,"type":"movie","runtimeSeconds":7262,"seasonCount":null,"communityRating":7.003,"criticRating":79,"genres":["Drama","Thriller","Mystery"],"overview":"Dr. Steven Murphy is a renowned cardiovascular surgeon who presides over a spotless household with his wife and two children. Lurking at the margins of his idyllic suburban existence is Martin, a fatherless teen who\u2026","poster":"assets/movie-the-killing-of-a-sacred-deer-2017-poster.jpg","backdrop":"assets/movie-the-killing-of-a-sacred-deer-2017-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-22T21:49:26.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":399057,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":79,"rtCriticsLabel":"Certified Fresh","rtAudience":63,"rtAudienceLabel":"Upright","imdb":7,"imdbVotes":219488,"tmdb":7.001,"tmdbVotes":4640}},{"id":"movie-night-is-short-walk-on-girl-2017","title":"Night Is Short, Walk On Girl","year":2017,"type":"movie","runtimeSeconds":5548,"seasonCount":null,"communityRating":7.421,"criticRating":90,"genres":["Comedy","Romance","Animation"],"overview":"As a group of university students go out for a night on the town, a sophomore known only as \"The Girl with Black Hair\" experiences a series of surreal encounters with the local nightlife \u2013 all the while unaware of\u2026","poster":"assets/movie-night-is-short-walk-on-girl-2017-poster.jpg","backdrop":"assets/movie-night-is-short-walk-on-girl-2017-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T17:39:14.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":430214,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":90,"rtCriticsLabel":"Fresh","rtAudience":84,"rtAudienceLabel":"Upright","imdb":7.5,"imdbVotes":7640,"tmdb":7.4,"tmdbVotes":267}},{"id":"movie-thelma-louise-1991","title":"Thelma & Louise","year":1991,"type":"movie","runtimeSeconds":7786,"seasonCount":null,"communityRating":7.596,"criticRating":87,"genres":["Drama","Crime","Adventure"],"overview":"Taking a break from their dreary lives, close friends Thelma and Louise embark on a short weekend trip that ends in unforeseen incriminating circumstances. As fugitives, both women rediscover the strength of their\u2026","poster":"assets/movie-thelma-louise-1991-poster.jpg","backdrop":"assets/movie-thelma-louise-1991-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:24:40.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":1541,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":87,"rtCriticsLabel":"Certified Fresh","rtAudience":82,"rtAudienceLabel":"Upright","imdb":7.6,"imdbVotes":197947,"tmdb":7.594,"tmdbVotes":4063}},{"id":"movie-vicky-cristina-barcelona-2008","title":"Vicky Cristina Barcelona","year":2008,"type":"movie","runtimeSeconds":5804,"seasonCount":null,"communityRating":6.798,"criticRating":80,"genres":["Drama","Romance"],"overview":"Two girlfriends on a summer holiday in Spain become enamored with the same painter, unaware that his ex-wife, with whom he has a tempestuous relationship, is about to re-enter the picture.","poster":"assets/movie-vicky-cristina-barcelona-2008-poster.jpg","backdrop":"assets/movie-vicky-cristina-barcelona-2008-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:25:34.0000000Z","lastPlayedAt":"2026-08-11T20:12:57.3064089Z","availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":5038,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":80,"rtCriticsLabel":"Certified Fresh","rtAudience":74,"rtAudienceLabel":"Upright","imdb":7.1,"imdbVotes":283286,"tmdb":6.797,"tmdbVotes":4164}}],"shows":[{"id":"tv-all-creatures-great-small-2020","title":"All Creatures Great & Small","year":2020,"type":"tv","runtimeSeconds":3000,"seasonCount":7,"communityRating":8.2,"criticRating":null,"genres":["Drama","Comedy"],"overview":"The heartwarming and humorous adventures of a young country vet in the Yorkshire Dales in the 1930s. A remake of the 1978 series.","poster":"assets/tv-all-creatures-great-small-2020-poster.jpg","backdrop":"assets/tv-all-creatures-great-small-2020-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-11-04T20:13:03.4266156Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":108255,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":99,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.2,"tmdbVotes":168}},{"id":"tv-back-to-life-2019","title":"Back to Life","year":2019,"type":"tv","runtimeSeconds":1500,"seasonCount":2,"communityRating":7.367,"criticRating":null,"genres":["Comedy","Drama"],"overview":"When Miri Matteson returns home after eighteen years, can she integrate back into her old life? With a terrible event from her past hanging over her, it won\u2019t be easy.","poster":"assets/tv-back-to-life-2019-poster.jpg","backdrop":"assets/tv-back-to-life-2019-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0688758Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":88510,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.4,"tmdbVotes":65}},{"id":"tv-big-boys-2022","title":"Big Boys","year":2022,"type":"tv","runtimeSeconds":1440,"seasonCount":3,"communityRating":7.6,"criticRating":null,"genres":["Comedy","Drama"],"overview":"Two boys from very different ends of the 'spectrum of masculinity' become best friends at Brent University freshers' week; in their first year of uni, they explore, experiment and try to discover themselves, helping\u2026","poster":"assets/tv-big-boys-2022-poster.jpg","backdrop":"assets/tv-big-boys-2022-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-11-04T20:25:58.2156837Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":202851,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.6,"tmdbVotes":49}},{"id":"tv-call-the-midwife-2012","title":"Call the Midwife","year":2012,"type":"tv","runtimeSeconds":3120,"seasonCount":15,"communityRating":7.5,"criticRating":null,"genres":["Drama"],"overview":"Drama following the lives of a group of midwives working in the poverty-stricken East End of London during the 1950s, based on the best-selling memoirs of Jennifer Worth.","poster":"assets/tv-call-the-midwife-2012-poster.jpg","backdrop":"assets/tv-call-the-midwife-2012-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0377216Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":39793,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.577,"tmdbVotes":267}},{"id":"tv-derry-girls-2018","title":"Derry Girls","year":2018,"type":"tv","runtimeSeconds":1380,"seasonCount":3,"communityRating":8.144,"criticRating":null,"genres":["Comedy","Drama"],"overview":"Amidst the political conflict of Northern Ireland in the 1990s, five secondary school students square off with the universal challenges of being a teenager.","poster":"assets/tv-derry-girls-2018-poster.jpg","backdrop":"assets/tv-derry-girls-2018-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-02T20:01:55.8955537Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":76148,"artwork":{"posterKind":"center_crop","backdropKind":"backdrop"},"ratings":{"rtCritics":99,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.138,"tmdbVotes":454}},{"id":"tv-desperate-housewives-2004","title":"Desperate Housewives","year":2004,"type":"tv","runtimeSeconds":2520,"seasonCount":8,"communityRating":7.896,"criticRating":null,"genres":["Mystery","Drama","Comedy"],"overview":"Looking down on her friends and family isn't a way of life for Mary Alice Young... it's a way of death. One day, in her perfect house, in the loveliest of suburbs, Mary Alice ended it all. Now she's taking us into\u2026","poster":"assets/tv-desperate-housewives-2004-poster.jpg","backdrop":"assets/tv-desperate-housewives-2004-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-29T20:56:40.3505596Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":693,"artwork":{"posterKind":"poster","backdropKind":"center_crop"},"ratings":{"rtCritics":72,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.896,"tmdbVotes":2171}},{"id":"tv-the-diplomat-2023","title":"The Diplomat","year":2023,"type":"tv","runtimeSeconds":null,"seasonCount":4,"communityRating":7.569,"criticRating":null,"genres":["Drama","War & Politics"],"overview":"Amid an international crisis, a US diplomat contends with her high-profile job as ambassador to the UK and her strained marriage to a political star.","poster":"assets/tv-the-diplomat-2023-poster.jpg","backdrop":"assets/tv-the-diplomat-2023-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0640348Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":203857,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":93,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.652,"tmdbVotes":521}},{"id":"tv-the-durrells-2016","title":"The Durrells","year":2016,"type":"tv","runtimeSeconds":2760,"seasonCount":4,"communityRating":7.402,"criticRating":null,"genres":["Drama","Comedy","Family"],"overview":"In 1935, financially strapped widow Louisa Durrell, whose life has fallen apart, decides to move from England, with her four children (three sons, one daughter), to the island of Corfu, Greece. Once there, the family\u2026","poster":"assets/tv-the-durrells-2016-poster.jpg","backdrop":"assets/tv-the-durrells-2016-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0619436Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":66134,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":94,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.4,"tmdbVotes":127}},{"id":"tv-etoile-2025","title":"\u00c9toile","year":2025,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":7.197,"criticRating":null,"genres":["Comedy","Drama"],"overview":"In an ambitious gambit to save their storied institutions, two world-renowned ballet companies in New York City and Paris swap their most talented stars.","poster":"assets/tv-etoile-2025-poster.jpg","backdrop":"assets/tv-etoile-2025-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0601383Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":225383,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":86,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.3,"tmdbVotes":40}},{"id":"tv-gilmore-girls-2000","title":"Gilmore Girls","year":2000,"type":"tv","runtimeSeconds":2640,"seasonCount":7,"communityRating":7.893,"criticRating":null,"genres":["Comedy","Drama"],"overview":"Set in the charming town of Stars Hollow, Connecticut, the series follows the captivating lives of Lorelai and Rory Gilmore, a mother/daughter pair who have a relationship most people only dream of.","poster":"assets/tv-gilmore-girls-2000-poster.jpg","backdrop":"assets/tv-gilmore-girls-2000-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0631035Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":4586,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.9,"tmdbVotes":1339}},{"id":"tv-ginny-georgia-2021","title":"Ginny & Georgia","year":2021,"type":"tv","runtimeSeconds":null,"seasonCount":3,"communityRating":8.026,"criticRating":null,"genres":["Comedy","Drama"],"overview":"Free-spirited Georgia and her two kids, Ginny and Austin, move north in search of a fresh start but find that the road to new beginnings can be bumpy.","poster":"assets/tv-ginny-georgia-2021-poster.jpg","backdrop":"assets/tv-ginny-georgia-2021-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0694828Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":117581,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":68,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8,"tmdbVotes":1840}},{"id":"tv-hellcats-2010","title":"Hellcats","year":2010,"type":"tv","runtimeSeconds":2460,"seasonCount":1,"communityRating":7.5,"criticRating":null,"genres":["Drama"],"overview":"Pre-law student Marti Perkins' world is flipped upside down when she loses her scholarship, and realizes the only way she can stay in school is by reigniting her dormant teen gymnastic skills to win a place on Lancer\u2026","poster":"assets/tv-hellcats-2010-poster.jpg","backdrop":"assets/tv-hellcats-2010-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-22T20:39:02.7719318Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":32504,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":65,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.5,"tmdbVotes":116}},{"id":"tv-high-potential-2024","title":"High Potential","year":2024,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":8.201,"criticRating":null,"genres":["Drama","Crime","Mystery"],"overview":"Morgan is a single mom with an exceptional mind, whose unconventional knack for solving crimes leads to an unusual and unstoppable partnership with a by-the-book seasoned detective.","poster":"assets/tv-high-potential-2024-poster.jpg","backdrop":"assets/tv-high-potential-2024-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0686091Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":226637,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":98,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.3,"tmdbVotes":707}},{"id":"tv-how-to-get-to-heaven-from-belfast-2026","title":"How to Get to Heaven from Belfast","year":2026,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":7.027,"criticRating":null,"genres":["Mystery","Comedy","Drama"],"overview":"Three lifelong pals embark on a chaotic quest to solve the mystery of their old friend's suspicious death and keep their own dark secret under wraps.","poster":"assets/tv-how-to-get-to-heaven-from-belfast-2026-poster.jpg","backdrop":"assets/tv-how-to-get-to-heaven-from-belfast-2026-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0683192Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":233079,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":95,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.063,"tmdbVotes":95}},{"id":"tv-the-hunting-wives-2025","title":"The Hunting Wives","year":2025,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":6.932,"criticRating":null,"genres":["Drama","Mystery"],"overview":"Sophie trades New England for East Texas and falls into a wealthy socialite's magnetic orbit \u2014 where a clique of housewives hide deadly secrets.","poster":"assets/tv-the-hunting-wives-2025-poster.jpg","backdrop":"assets/tv-the-hunting-wives-2025-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-20T19:42:46.3227892Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":244447,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":81,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.964,"tmdbVotes":112}},{"id":"tv-the-lost-flowers-of-alice-hart-2023","title":"The Lost Flowers of Alice Hart","year":2023,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":7.634,"criticRating":null,"genres":["Drama","Mystery"],"overview":"After losing her parents in a mysterious fire, nine-year-old Alice Hart is raised by her grandmother June on a flower farm where she learns there are secrets within secrets. But years on, an unearthed betrayal sees\u2026","poster":"assets/tv-the-lost-flowers-of-alice-hart-2023-poster.jpg","backdrop":"assets/tv-the-lost-flowers-of-alice-hart-2023-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0607236Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":125816,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":82,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.64,"tmdbVotes":161}},{"id":"tv-love-is-blind-2020","title":"Love Is Blind","year":2020,"type":"tv","runtimeSeconds":null,"seasonCount":11,"communityRating":6.261,"criticRating":null,"genres":["Reality"],"overview":"Nick and Vanessa Lachey host this social experiment where single men and women look for love and get engaged, all before meeting in person.","poster":"assets/tv-love-is-blind-2020-poster.jpg","backdrop":"assets/tv-love-is-blind-2020-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-22T17:11:08.2447226Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":99353,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":66,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.233,"tmdbVotes":118}},{"id":"tv-maximum-pleasure-guaranteed-2026","title":"Maximum Pleasure Guaranteed","year":2026,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":6.676,"criticRating":null,"genres":["Comedy"],"overview":"A newly divorced mom falls down a dangerous rabbit hole of blackmail, murder, and youth soccer.","poster":"assets/tv-maximum-pleasure-guaranteed-2026-poster.jpg","backdrop":"assets/tv-maximum-pleasure-guaranteed-2026-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-07T21:04:02.8277793Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":285404,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":93,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.799,"tmdbVotes":92}},{"id":"tv-minx-2022","title":"Minx","year":2022,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":6.833,"criticRating":null,"genres":["Comedy","Drama"],"overview":"An earnest young feminist joins forces with a low-rent publisher to make the world's first erotic magazine for women.","poster":"assets/tv-minx-2022-poster.jpg","backdrop":"assets/tv-minx-2022-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0653613Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":118303,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":93,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.9,"tmdbVotes":123}},{"id":"tv-offspring-2010","title":"Offspring","year":2010,"type":"tv","runtimeSeconds":3600,"seasonCount":7,"communityRating":6.9,"criticRating":null,"genres":["Drama"],"overview":"An exuberant drama set in Melbourne's Fitzroy, centering on Nina Proudman and her struggle to deal with her fabulously messy family, her hunt for a decent love life and her tendency to overthink and fly off into fantasy.","poster":"assets/tv-offspring-2010-poster.jpg","backdrop":"assets/tv-offspring-2010-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0664581Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":33155,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.9,"tmdbVotes":27}},{"id":"tv-only-murders-in-the-building-2021","title":"Only Murders in the Building","year":2021,"type":"tv","runtimeSeconds":null,"seasonCount":5,"communityRating":8.398,"criticRating":null,"genres":["Comedy","Mystery","Crime"],"overview":"Three strangers share an obsession with true crime and suddenly find themselves wrapped up in one.","poster":"assets/tv-only-murders-in-the-building-2021-poster.jpg","backdrop":"assets/tv-only-murders-in-the-building-2021-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-11-04T20:25:58.2163301Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":107113,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":95,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.398,"tmdbVotes":2333}},{"id":"tv-outlander-blood-of-my-blood-2025","title":"Outlander: Blood of My Blood","year":2025,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":8.542,"criticRating":null,"genres":["Drama"],"overview":"From the battlefields of World War I to the rugged Highlands of 18th century Scotland, two fated couples must defy the forces that seek to tear them apart, unfolding in surprising and unforeseen ways in this romantic\u2026","poster":"assets/tv-outlander-blood-of-my-blood-2025-poster.jpg","backdrop":"assets/tv-outlander-blood-of-my-blood-2025-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0691373Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":207484,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":94,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.738,"tmdbVotes":124}},{"id":"tv-rivals-2024","title":"Rivals","year":2024,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":7.44,"criticRating":null,"genres":["Drama"],"overview":"It is 1986 and Britain is booming. \"Rivals\" dives headfirst into the cutthroat world of TV where hair-dos are big and ambitions are even bigger. Deals are brokered in boardrooms, as well as bedrooms. Nobody can be\u2026","poster":"assets/tv-rivals-2024-poster.jpg","backdrop":"assets/tv-rivals-2024-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0645815Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":208921,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":96,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.4,"tmdbVotes":93}},{"id":"tv-rooster-2026","title":"Rooster","year":2026,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":7.431,"criticRating":null,"genres":["Comedy"],"overview":"On a college campus, an author navigates a complicated relationship with his daughter.","poster":"assets/tv-rooster-2026-poster.jpg","backdrop":"assets/tv-rooster-2026-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.063389Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":254953,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":88,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.423,"tmdbVotes":144}},{"id":"tv-sex-and-the-city-1998","title":"Sex and the City","year":1998,"type":"tv","runtimeSeconds":null,"seasonCount":6,"communityRating":7.365,"criticRating":null,"genres":["Drama","Comedy"],"overview":"Based on the bestselling book by Candace Bushnell, Sex and the City tells the story of four best friends, all single and in their late thirties, as they pursue their careers and talk about their sex lives, all while\u2026","poster":"assets/tv-sex-and-the-city-1998-poster.jpg","backdrop":"assets/tv-sex-and-the-city-1998-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0679324Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":105,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":70,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.351,"tmdbVotes":2220}},{"id":"tv-skymed-2022","title":"SkyMed","year":2022,"type":"tv","runtimeSeconds":2640,"seasonCount":4,"communityRating":6.665,"criticRating":null,"genres":["Drama"],"overview":"Life, death and drama at 20,000 feet. The series weaves together intense character journeys and high-stakes medical rescues, as we follow the triumphs, heartbreaks and tribulations of budding nurses and pilots flying\u2026","poster":"assets/tv-skymed-2022-poster.jpg","backdrop":"assets/tv-skymed-2022-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-22T19:44:29.2431354Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":133908,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.699,"tmdbVotes":98}},{"id":"tv-so-you-think-you-can-dance-2008","title":"So You Think You Can Dance","year":2008,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":9.8,"criticRating":null,"genres":["Family","Reality"],"overview":"So You Think You Can Dance is a joint Belgian-Dutch dance competition show broadcast on RTL 5 and vtm television stations. The first season was broadcast only in the Netherlands, whereas starting with season 2, the\u2026","poster":"assets/tv-so-you-think-you-can-dance-2008-poster.jpg","backdrop":"assets/tv-so-you-think-you-can-dance-2008-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-23T11:11:35.4124418Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":40231,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":9.8,"tmdbVotes":4}},{"id":"tv-the-white-lotus-2021","title":"The White Lotus","year":2021,"type":"tv","runtimeSeconds":null,"seasonCount":3,"communityRating":7.597,"criticRating":null,"genres":["Comedy","Drama","Mystery"],"overview":"Follow the exploits of various guests and employees at an exclusive tropical resort over the span of a week as with each passing day, a darker complexity emerges in these picture-perfect travelers, the hotel\u2019s\u2026","poster":"assets/tv-the-white-lotus-2021-poster.jpg","backdrop":"assets/tv-the-white-lotus-2021-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-20T02:45:52.8742674Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":111803,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":90,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.599,"tmdbVotes":1604}},{"id":"tv-yellowjackets-2021","title":"Yellowjackets","year":2021,"type":"tv","runtimeSeconds":null,"seasonCount":3,"communityRating":7.431,"criticRating":null,"genres":["Drama","Mystery"],"overview":"This equal parts survival epic, psychological horror story and coming-of-age drama tells the saga of a team of wildly talented high school girls soccer players who become the (un)lucky survivors of a plane crash deep\u2026","poster":"assets/tv-yellowjackets-2021-poster.jpg","backdrop":"assets/tv-yellowjackets-2021-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-11-04T20:31:47.4592756Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":117488,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":92,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.431,"tmdbVotes":1070}}],"anime":[],"resume":[{"id":"episode-sex-and-the-country-2001-s4e9","title":"Sex and the Country","year":2001,"type":"episode","runtimeSeconds":1751,"seasonCount":null,"communityRating":5.9,"criticRating":null,"genres":["Comedy","Drama","Romance"],"overview":"Carrie is dragged to Aidan's country home in Suffern, New York. Charlotte visits the MacDougal \"compound\" in Connecticut. Miranda yells at Steve when he tells her he has testicular cancer but has no clue about his\u2026","poster":"assets/episode-sex-and-the-country-2001-s4e9-poster.jpg","backdrop":"assets/episode-sex-and-the-country-2001-s4e9-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":96.08,"progress":0.0549,"addedAt":"2026-07-17T10:53:15.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","seriesTitle":"Sex and the City","seasonNumber":4,"episodeNumber":9,"artwork":{"posterKind":"poster","backdropKind":"backdrop"}}],"nextUp":[{"id":"episode-what-more-do-i-need-2008-s5e7","title":"What More Do I Need?","year":2008,"type":"episode","runtimeSeconds":2521,"seasonCount":null,"communityRating":8,"criticRating":null,"genres":["Comedy","Drama","Mystery"],"overview":"Lynette and Tom uncover the unsettling truth about son Porter. Gabrielle suspects Carlos' best client, Virginia, has ulterior motives. Bree's moment of weakness could bring her great embarrassment and shame.\u2026","poster":"assets/episode-what-more-do-i-need-2008-s5e7-poster.jpg","backdrop":"assets/episode-what-more-do-i-need-2008-s5e7-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-29T14:37:28.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","seriesTitle":"Desperate Housewives","seasonNumber":5,"episodeNumber":7,"artwork":{"posterKind":"center_crop","backdropKind":"backdrop"}},{"id":"episode-new-day-2021-s1e2","title":"New Day","year":2021,"type":"episode","runtimeSeconds":3445,"seasonCount":null,"communityRating":7.143,"criticRating":null,"genres":["Comedy","Drama"],"overview":"A cautiously optimistic Belinda walks a fine line with Tanya, while Armond brainstorms ways to deal with Shane. After her husband belittles her work, Rachel approaches Nicole for advice. Paula and Olivia lose track\u2026","poster":"assets/episode-new-day-2021-s1e2-poster.jpg","backdrop":"assets/episode-new-day-2021-s1e2-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-19T22:18:57.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","seriesTitle":"The White Lotus","seasonNumber":1,"episodeNumber":2,"artwork":{"posterKind":"poster","backdropKind":"backdrop"}},{"id":"episode-the-uncomfortability-2010-s1e2","title":"The Uncomfortability","year":2010,"type":"episode","runtimeSeconds":2687,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy","Drama"],"overview":"Nina's insecurities are revealed when a patient poses an awkward request. Meanwhile Geraldine decides to try online dating, and Jimmy is an unexpected saviour to Cherie and Darcy.","poster":"assets/episode-the-uncomfortability-2010-s1e2-poster.jpg","backdrop":"assets/episode-the-uncomfortability-2010-s1e2-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T11:47:42.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","seriesTitle":"Offspring","seasonNumber":1,"episodeNumber":2,"artwork":{"posterKind":"poster","backdropKind":"backdrop"}},{"id":"episode-episode-2-2016-s1e2","title":"Episode 2","year":2016,"type":"episode","runtimeSeconds":2766,"seasonCount":null,"communityRating":8.3,"criticRating":null,"genres":["Biography","Comedy","Drama"],"overview":"Larry falls dangerously ill, and it falls to Theo and his neighbour Sven to put their rudimentary medical skills to the task of saving his life. The family's money worries continue, but Spiros brings them good news\u2026","poster":"assets/episode-episode-2-2016-s1e2-poster.jpg","backdrop":"assets/episode-episode-2-2016-s1e2-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-31T07:29:17.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","seriesTitle":"The Durrells","seasonNumber":1,"episodeNumber":2,"artwork":{"posterKind":"poster","backdropKind":"backdrop"}},{"id":"episode-remembrance-day-2026-s2e1","title":"Remembrance Day","year":2026,"type":"episode","runtimeSeconds":3822,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Fantasy","Romance"],"overview":"The fiery crosses have been lit across the Highlands; lovers must part, as the call to arms brings friends and enemies home and the Jacobite Rebellion begins in earnest.","poster":"assets/episode-remembrance-day-2026-s2e1-poster.jpg","backdrop":"assets/episode-remembrance-day-2026-s2e1-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-19T03:50:07.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","seriesTitle":"Outlander: Blood of My Blood","seasonNumber":2,"episodeNumber":1,"artwork":{"posterKind":"poster","backdropKind":"backdrop"}},{"id":"episode-one-of-us-2024-s1e7","title":"One of Us","year":2024,"type":"episode","runtimeSeconds":2555,"seasonCount":null,"communityRating":7.7,"criticRating":null,"genres":[],"overview":"Morgan agrees to show Ava around the LAPD, but things quickly take a dangerous turn when the precinct is held hostage by the friends of a recently convicted man. Can Morgan and the detectives outsmart their captors\u2026","poster":"assets/episode-one-of-us-2024-s1e7-poster.jpg","backdrop":"assets/episode-one-of-us-2024-s1e7-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T13:57:22.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","seriesTitle":"High Potential","seasonNumber":1,"episodeNumber":7,"artwork":{"posterKind":"poster","backdropKind":"backdrop"}},{"id":"episode-the-breakup-part-2-2001-s1e17","title":"The Breakup, Part 2","year":2001,"type":"episode","runtimeSeconds":2669,"seasonCount":null,"communityRating":7.4,"criticRating":null,"genres":["Comedy","Drama"],"overview":"After recent events, Rory keeps busy, refusing to give in to self-pity. Meanwhile, Stars Hollow's residents rally around her, much to her dismay.","poster":"assets/episode-the-breakup-part-2-2001-s1e17-poster.jpg","backdrop":"assets/episode-the-breakup-part-2-2001-s1e17-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T11:28:05.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","seriesTitle":"Gilmore Girls","seasonNumber":1,"episodeNumber":17,"artwork":{"posterKind":"poster","backdropKind":"backdrop"}},{"id":"episode-i-heart-ny-2002-s4e18","title":"I Heart NY","year":2002,"type":"episode","runtimeSeconds":1905,"seasonCount":null,"communityRating":6.667,"criticRating":null,"genres":["Comedy","Drama","Romance"],"overview":"Carrie is shocked to find out that Big is moving to Napa, California and plans to give him a New York send-off. Charlotte begins dating another recent divorc\u00e9. Miranda prepares for the new baby as her delivery date\u2026","poster":"assets/episode-i-heart-ny-2002-s4e18-poster.jpg","backdrop":"assets/episode-i-heart-ny-2002-s4e18-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T12:35:14.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","seriesTitle":"Sex and the City","seasonNumber":4,"episodeNumber":18,"artwork":{"posterKind":"poster","backdropKind":"backdrop"}}],"recentlyAdded":[{"id":"tv-yellowjackets-2021","title":"Yellowjackets","year":2021,"type":"tv","runtimeSeconds":null,"seasonCount":3,"communityRating":7.431,"criticRating":null,"genres":["Drama","Mystery"],"overview":"This equal parts survival epic, psychological horror story and coming-of-age drama tells the saga of a team of wildly talented high school girls soccer players who become the (un)lucky survivors of a plane crash deep\u2026","poster":"assets/tv-yellowjackets-2021-poster.jpg","backdrop":"assets/tv-yellowjackets-2021-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-11-04T20:31:47.4592756Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":117488,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":92,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.431,"tmdbVotes":1070}},{"id":"tv-only-murders-in-the-building-2021","title":"Only Murders in the Building","year":2021,"type":"tv","runtimeSeconds":null,"seasonCount":5,"communityRating":8.398,"criticRating":null,"genres":["Comedy","Mystery","Crime"],"overview":"Three strangers share an obsession with true crime and suddenly find themselves wrapped up in one.","poster":"assets/tv-only-murders-in-the-building-2021-poster.jpg","backdrop":"assets/tv-only-murders-in-the-building-2021-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-11-04T20:25:58.2163301Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":107113,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":95,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.398,"tmdbVotes":2333}},{"id":"tv-big-boys-2022","title":"Big Boys","year":2022,"type":"tv","runtimeSeconds":1440,"seasonCount":3,"communityRating":7.6,"criticRating":null,"genres":["Comedy","Drama"],"overview":"Two boys from very different ends of the 'spectrum of masculinity' become best friends at Brent University freshers' week; in their first year of uni, they explore, experiment and try to discover themselves, helping\u2026","poster":"assets/tv-big-boys-2022-poster.jpg","backdrop":"assets/tv-big-boys-2022-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-11-04T20:25:58.2156837Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":202851,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.6,"tmdbVotes":49}},{"id":"tv-all-creatures-great-small-2020","title":"All Creatures Great & Small","year":2020,"type":"tv","runtimeSeconds":3000,"seasonCount":7,"communityRating":8.2,"criticRating":null,"genres":["Drama","Comedy"],"overview":"The heartwarming and humorous adventures of a young country vet in the Yorkshire Dales in the 1930s. A remake of the 1978 series.","poster":"assets/tv-all-creatures-great-small-2020-poster.jpg","backdrop":"assets/tv-all-creatures-great-small-2020-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-11-04T20:13:03.4266156Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":108255,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":99,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.2,"tmdbVotes":168}},{"id":"movie-the-killing-of-a-sacred-deer-2017","title":"The Killing of a Sacred Deer","year":2017,"type":"movie","runtimeSeconds":7262,"seasonCount":null,"communityRating":7.003,"criticRating":79,"genres":["Drama","Thriller","Mystery"],"overview":"Dr. Steven Murphy is a renowned cardiovascular surgeon who presides over a spotless household with his wife and two children. Lurking at the margins of his idyllic suburban existence is Martin, a fatherless teen who\u2026","poster":"assets/movie-the-killing-of-a-sacred-deer-2017-poster.jpg","backdrop":"assets/movie-the-killing-of-a-sacred-deer-2017-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-22T21:49:26.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":399057,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":79,"rtCriticsLabel":"Certified Fresh","rtAudience":63,"rtAudienceLabel":"Upright","imdb":7,"imdbVotes":219488,"tmdb":7.001,"tmdbVotes":4640}},{"id":"tv-derry-girls-2018","title":"Derry Girls","year":2018,"type":"tv","runtimeSeconds":1380,"seasonCount":3,"communityRating":8.144,"criticRating":null,"genres":["Comedy","Drama"],"overview":"Amidst the political conflict of Northern Ireland in the 1990s, five secondary school students square off with the universal challenges of being a teenager.","poster":"assets/tv-derry-girls-2018-poster.jpg","backdrop":"assets/tv-derry-girls-2018-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-02T20:01:55.8955537Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":76148,"artwork":{"posterKind":"center_crop","backdropKind":"backdrop"},"ratings":{"rtCritics":99,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.138,"tmdbVotes":454}},{"id":"tv-so-you-think-you-can-dance-2008","title":"So You Think You Can Dance","year":2008,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":9.8,"criticRating":null,"genres":["Family","Reality"],"overview":"So You Think You Can Dance is a joint Belgian-Dutch dance competition show broadcast on RTL 5 and vtm television stations. The first season was broadcast only in the Netherlands, whereas starting with season 2, the\u2026","poster":"assets/tv-so-you-think-you-can-dance-2008-poster.jpg","backdrop":"assets/tv-so-you-think-you-can-dance-2008-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-23T11:11:35.4124418Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":40231,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":9.8,"tmdbVotes":4}},{"id":"tv-hellcats-2010","title":"Hellcats","year":2010,"type":"tv","runtimeSeconds":2460,"seasonCount":1,"communityRating":7.5,"criticRating":null,"genres":["Drama"],"overview":"Pre-law student Marti Perkins' world is flipped upside down when she loses her scholarship, and realizes the only way she can stay in school is by reigniting her dormant teen gymnastic skills to win a place on Lancer\u2026","poster":"assets/tv-hellcats-2010-poster.jpg","backdrop":"assets/tv-hellcats-2010-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-22T20:39:02.7719318Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":32504,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":65,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.5,"tmdbVotes":116}},{"id":"tv-skymed-2022","title":"SkyMed","year":2022,"type":"tv","runtimeSeconds":2640,"seasonCount":4,"communityRating":6.665,"criticRating":null,"genres":["Drama"],"overview":"Life, death and drama at 20,000 feet. The series weaves together intense character journeys and high-stakes medical rescues, as we follow the triumphs, heartbreaks and tribulations of budding nurses and pilots flying\u2026","poster":"assets/tv-skymed-2022-poster.jpg","backdrop":"assets/tv-skymed-2022-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-22T19:44:29.2431354Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":133908,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.699,"tmdbVotes":98}},{"id":"tv-love-is-blind-2020","title":"Love Is Blind","year":2020,"type":"tv","runtimeSeconds":null,"seasonCount":11,"communityRating":6.261,"criticRating":null,"genres":["Reality"],"overview":"Nick and Vanessa Lachey host this social experiment where single men and women look for love and get engaged, all before meeting in person.","poster":"assets/tv-love-is-blind-2020-poster.jpg","backdrop":"assets/tv-love-is-blind-2020-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-22T17:11:08.2447226Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":99353,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":66,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.233,"tmdbVotes":118}},{"id":"tv-the-hunting-wives-2025","title":"The Hunting Wives","year":2025,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":6.932,"criticRating":null,"genres":["Drama","Mystery"],"overview":"Sophie trades New England for East Texas and falls into a wealthy socialite's magnetic orbit \u2014 where a clique of housewives hide deadly secrets.","poster":"assets/tv-the-hunting-wives-2025-poster.jpg","backdrop":"assets/tv-the-hunting-wives-2025-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-20T19:42:46.3227892Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":244447,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":81,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.964,"tmdbVotes":112}},{"id":"tv-the-white-lotus-2021","title":"The White Lotus","year":2021,"type":"tv","runtimeSeconds":null,"seasonCount":3,"communityRating":7.597,"criticRating":null,"genres":["Comedy","Drama","Mystery"],"overview":"Follow the exploits of various guests and employees at an exclusive tropical resort over the span of a week as with each passing day, a darker complexity emerges in these picture-perfect travelers, the hotel\u2019s\u2026","poster":"assets/tv-the-white-lotus-2021-poster.jpg","backdrop":"assets/tv-the-white-lotus-2021-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-20T02:45:52.8742674Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":111803,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":90,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.599,"tmdbVotes":1604}}],"discover":[{"id":"movie-across-the-hall-2009","title":"Across the Hall","year":2009,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Thriller","Mystery"],"overview":"Convinced that his fiancee is cheating on him, a man follows her to a hotel and calls his best friend to help him avoid a calamity.","poster":"assets/movie-across-the-hall-2009-poster.jpg","backdrop":"assets/movie-across-the-hall-2009-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":21469,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":39,"rtAudienceLabel":"Spilled","imdb":5.8,"imdbVotes":5130,"tmdb":6,"tmdbVotes":129}},{"id":"movie-addicted-2014","title":"Addicted","year":2014,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Thriller"],"overview":"A gallerist risks her family and flourishing career when she enters into an affair with a talented painter and slowly loses control of her life.","poster":"assets/movie-addicted-2014-poster.jpg","backdrop":"assets/movie-addicted-2014-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":235271,"ratings":{"rtCritics":7,"rtCriticsLabel":"Rotten","rtAudience":51,"rtAudienceLabel":"Spilled","imdb":5,"imdbVotes":13131,"tmdb":5.928,"tmdbVotes":466}},{"id":"movie-adulterers-2016","title":"Adulterers","year":2016,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Thriller","Drama"],"overview":"On a steamy New Orleans afternoon, Sam Deuprey decides to surprise his beautiful wife, Ashley, for their anniversary and comes home early. But Ashley is not alone in the bedroom. She and her lover, Damien are about\u2026","poster":"assets/movie-adulterers-2016-poster.jpg","backdrop":"assets/movie-adulterers-2016-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":376004,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":37,"rtAudienceLabel":"Spilled","imdb":5.1,"imdbVotes":2144,"tmdb":6.2,"tmdbVotes":116}},{"id":"movie-alone-with-her-2006","title":"Alone With Her","year":2006,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Crime","Drama","Thriller"],"overview":"The harrowing story of a disturbed young man's attempts to win the affections of an unsuspecting young woman. When Doug first sees Amy, he instantly falls for her and begins to watch her every move, going so far as\u2026","poster":"assets/movie-alone-with-her-2006-poster.jpg","backdrop":"assets/movie-alone-with-her-2006-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":18206,"ratings":{"rtCritics":70,"rtCriticsLabel":"Fresh","rtAudience":46,"rtAudienceLabel":"Spilled","imdb":6,"imdbVotes":4359,"tmdb":5.9,"tmdbVotes":94}},{"id":"movie-awake-2007","title":"Awake","year":2007,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Thriller","Crime","Mystery"],"overview":"While undergoing heart surgery, a man experiences a phenomenon called \u2018anesthetic awareness\u2019, which leaves him awake but paralyzed throughout the operation. As various obstacles present themselves, his wife must make\u2026","poster":"assets/movie-awake-2007-poster.jpg","backdrop":"assets/movie-awake-2007-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":13483,"ratings":{"rtCritics":23,"rtCriticsLabel":"Rotten","rtAudience":55,"rtAudienceLabel":"Spilled","imdb":6.5,"imdbVotes":89389,"tmdb":6.586,"tmdbVotes":1649}},{"id":"movie-black-bear-2020","title":"Black Bear","year":2020,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Thriller"],"overview":"At a remote lake house in the Adirondack Mountains, a couple entertains an out-of-town guest looking for inspiration in her filmmaking. The group quickly falls into a calculated game of desire, manipulation, and\u2026","poster":"assets/movie-black-bear-2020-poster.jpg","backdrop":"assets/movie-black-bear-2020-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":624788,"ratings":{"rtCritics":89,"rtCriticsLabel":"Certified Fresh","rtAudience":64,"rtAudienceLabel":"Upright","imdb":6.5,"imdbVotes":18408,"tmdb":6.337,"tmdbVotes":315}},{"id":"movie-butterfly-on-a-wheel-2007","title":"Butterfly on a Wheel","year":2007,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Crime","Drama","Thriller"],"overview":"A sociopathic kidnapper methodically pushes a desperate pair of parents to their absolute breaking point.","poster":"assets/movie-butterfly-on-a-wheel-2007-poster.jpg","backdrop":"assets/movie-butterfly-on-a-wheel-2007-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":13250,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":61,"rtAudienceLabel":"Upright","imdb":6.6,"imdbVotes":35409,"tmdb":6.457,"tmdbVotes":595}},{"id":"movie-careful-what-you-wish-for-2015","title":"Careful What You Wish For","year":2015,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Thriller"],"overview":"A guy gets more than he bargained for after entering into an affair with the wife of an investment banker. Soon, a suspicious death and substantial life insurance policy embroil him in a scandal.","poster":"assets/movie-careful-what-you-wish-for-2015-poster.jpg","backdrop":"assets/movie-careful-what-you-wish-for-2015-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":317744,"ratings":{"rtCritics":17,"rtCriticsLabel":"Rotten","rtAudience":61,"rtAudienceLabel":"Upright","imdb":5.6,"imdbVotes":9452,"tmdb":6.129,"tmdbVotes":446}},{"id":"movie-crime-of-passion-1956","title":"Crime of Passion","year":1956,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Crime","Thriller"],"overview":"Kathy leaves the newspaper business to marry homicide detective Bill, but is frustrated by his lack of ambition and the banality of life in the suburbs. Her drive to advance Bill's career soon takes her down a\u2026","poster":"assets/movie-crime-of-passion-1956-poster.jpg","backdrop":"assets/movie-crime-of-passion-1956-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"center_crop","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1920,"ratings":{"rtCritics":80,"rtCriticsLabel":"Fresh","rtAudience":34,"rtAudienceLabel":"Spilled","imdb":6.4,"imdbVotes":3750,"tmdb":6.1,"tmdbVotes":57}},{"id":"movie-deep-water-2022","title":"Deep Water","year":2022,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Mystery","Thriller"],"overview":"A well-to-do husband who allows his wife to have affairs in order to avoid a divorce becomes a prime suspect in the disappearance of her lovers.","poster":"assets/movie-deep-water-2022-poster.jpg","backdrop":"assets/movie-deep-water-2022-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":619979,"ratings":{"rtCritics":35,"rtCriticsLabel":"Rotten","rtAudience":25,"rtAudienceLabel":"Spilled","imdb":5.5,"imdbVotes":74098,"tmdb":5.834,"tmdbVotes":1755}},{"id":"movie-derailed-2005","title":"Derailed","year":2005,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Thriller"],"overview":"When two married business executives having an affair are blackmailed by a violent criminal, they are forced to turn the tables on him to save their families.","poster":"assets/movie-derailed-2005-poster.jpg","backdrop":"assets/movie-derailed-2005-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":8999,"ratings":{"rtCritics":20,"rtCriticsLabel":"Rotten","rtAudience":58,"rtAudienceLabel":"Spilled","imdb":6.6,"imdbVotes":79563,"tmdb":6.405,"tmdbVotes":1193}},{"id":"movie-die-my-love-2025","title":"Die My Love","year":2025,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama"],"overview":"After inheriting a remote Montana house, Jackson moves there from New York with his partner Grace, and the couple soon welcome a child. As Jackson becomes increasingly absent and rural isolation sets in, Grace\u2026","poster":"assets/movie-die-my-love-2025-poster.jpg","backdrop":"assets/movie-die-my-love-2025-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1033148,"ratings":{"rtCritics":74,"rtCriticsLabel":"Certified Fresh","rtAudience":45,"rtAudienceLabel":"Spilled","imdb":6,"imdbVotes":50664,"tmdb":6.1,"tmdbVotes":683}},{"id":"movie-dream-house-2011","title":"Dream House","year":2011,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Mystery","Drama","Thriller"],"overview":"Publisher Will Atenton quits a lucrative job in New York to relocate his wife, Libby, and their daughters to a quaint town in New England. However, as they settle into their home the Atentons discover that a woman\u2026","poster":"assets/movie-dream-house-2011-poster.jpg","backdrop":"assets/movie-dream-house-2011-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":69668,"ratings":{"rtCritics":7,"rtCriticsLabel":"Rotten","rtAudience":36,"rtAudienceLabel":"Spilled","imdb":6,"imdbVotes":71386,"tmdb":6.212,"tmdbVotes":1480}},{"id":"movie-dream-lover-1994","title":"Dream Lover","year":1994,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Mystery","Thriller"],"overview":"Not long after they cross paths at an art gallery, architect Ray Reardon and hypnotically sensual Lena are married with children. But as strange incidents occur, Ray begins to realize he may not really know the woman\u2026","poster":"assets/movie-dream-lover-1994-poster.jpg","backdrop":"assets/movie-dream-lover-1994-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":18190,"ratings":{"rtCritics":57,"rtCriticsLabel":"Rotten","rtAudience":38,"rtAudienceLabel":"Spilled","imdb":6.2,"imdbVotes":7865,"tmdb":6.844,"tmdbVotes":167}},{"id":"movie-drop-2025","title":"Drop","year":2025,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Mystery","Thriller"],"overview":"Violet, a widowed mother on her first date in years, arrives at an upscale restaurant where she is relieved that her date, Henry, is more charming and handsome than she expected. But their chemistry begins to curdle\u2026","poster":"assets/movie-drop-2025-poster.jpg","backdrop":"assets/movie-drop-2025-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1249213,"ratings":{"rtCritics":83,"rtCriticsLabel":"Certified Fresh","rtAudience":79,"rtAudienceLabel":"Upright","imdb":6.1,"imdbVotes":61018,"tmdb":6.275,"tmdbVotes":1023}},{"id":"movie-eastern-promises-2007","title":"Eastern Promises","year":2007,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Thriller","Crime","Mystery"],"overview":"A Russian teenager living in London dies during childbirth but leaves clues in her diary that could tie her child to a rape involving a violent Russian mob family.","poster":"assets/movie-eastern-promises-2007-poster.jpg","backdrop":"assets/movie-eastern-promises-2007-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":2252,"ratings":{"rtCritics":89,"rtCriticsLabel":"Certified Fresh","rtAudience":83,"rtAudienceLabel":"Upright","imdb":7.6,"imdbVotes":281015,"tmdb":7.349,"tmdbVotes":3900}},{"id":"movie-faces-1968","title":"Faces","year":1968,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama"],"overview":"Middle-aged suburban husband Richard abruptly tells his wife, Maria, that he wants a divorce. As Richard takes up with a younger woman, Maria enjoys a night on the town with her friends and meets a younger man. As\u2026","poster":"assets/movie-faces-1968-poster.jpg","backdrop":"assets/movie-faces-1968-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"center_crop","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":753,"ratings":{"rtCritics":83,"rtCriticsLabel":"Fresh","rtAudience":86,"rtAudienceLabel":"Upright","imdb":7.4,"imdbVotes":12950,"tmdb":7.093,"tmdbVotes":227}},{"id":"movie-fatale-2020","title":"Fatale","year":2020,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Thriller"],"overview":"After a wild one-night stand, successful sports agent Derrick Tyler watches his perfect life slowly disappear when he discovers the sexy and mysterious woman he risked everything for is determined police detective\u2026","poster":"assets/movie-fatale-2020-poster.jpg","backdrop":"assets/movie-fatale-2020-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":549514,"ratings":{"rtCritics":46,"rtCriticsLabel":"Rotten","rtAudience":87,"rtAudienceLabel":"Upright","imdb":5.5,"imdbVotes":16392,"tmdb":6,"tmdbVotes":401}},{"id":"tv-56-days-2026","title":"56 Days","year":2026,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Crime","Mystery"],"overview":"When an unidentified body is found in a luxury apartment linked to Oliver Kennedy and his girlfriend Ciara Wyse, Detectives Lee Reardon and Karl Connolly reconstruct the couple's deadly romance across the past 56 days.","poster":"assets/tv-56-days-2026-poster.jpg","backdrop":"assets/tv-56-days-2026-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":241372,"ratings":{"rtCritics":60,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.388,"tmdbVotes":245}},{"id":"tv-90-day-fiance-before-the-90-days-2017","title":"90 Day Fianc\u00e9: Before the 90 Days","year":2017,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Reality"],"overview":"Follow couples who have an existing relationship online, but haven't met in person. We'll experience their journey as they travel to the other's foreign country for the first time in an attempt to establish an\u2026","poster":"assets/tv-90-day-fiance-before-the-90-days-2017-poster.jpg","backdrop":"assets/tv-90-day-fiance-before-the-90-days-2017-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":73319,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.5,"tmdbVotes":45}},{"id":"tv-90-day-fiance-the-other-way-2019","title":"90 Day Fianc\u00e9: The Other Way","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Reality"],"overview":"Americans move to a foreign country all in the name of love. Will uprooting their lives in the United States pay off, or will they be packing up and moving back to America brokenhearted?","poster":"assets/tv-90-day-fiance-the-other-way-2019-poster.jpg","backdrop":"assets/tv-90-day-fiance-the-other-way-2019-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":90046,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.8,"tmdbVotes":34}},{"id":"tv-absolutely-fabulous-1992","title":"Absolutely Fabulous","year":1992,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy"],"overview":"Set in the world of fashion and PR, immature fun-loving mother Edina Monsoon and her best friend Patsy drive Eddie's sensible daughter, Saffron, up the wall with their constant drug abuse and outrageous selfishness.\u2026","poster":"assets/tv-absolutely-fabulous-1992-poster.jpg","backdrop":"assets/tv-absolutely-fabulous-1992-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":4493,"ratings":{"rtCritics":96,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.6,"tmdbVotes":198}},{"id":"tv-the-afterparty-2022","title":"The Afterparty","year":2022,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Mystery","Comedy","Crime"],"overview":"Nothing is as it seems in this hilarious murder mystery where each suspect's story is told through a different film genre.","poster":"assets/tv-the-afterparty-2022-poster.jpg","backdrop":"assets/tv-the-afterparty-2022-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":106454,"ratings":{"rtCritics":92,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.071,"tmdbVotes":245}},{"id":"tv-agatha-christie-s-marple-2004","title":"Agatha Christie's Marple","year":2004,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Crime","Mystery"],"overview":"The adventures of Miss Jane Marple, an elderly spinster living in the quiet little village of St Mary Mead. During her many visits to friends and relatives in other villages, Miss Marple often stumbles upon\u2026","poster":"assets/tv-agatha-christie-s-marple-2004-poster.jpg","backdrop":"assets/tv-agatha-christie-s-marple-2004-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":6127,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.9,"tmdbVotes":152}},{"id":"tv-all-american-homecoming-2022","title":"All American: Homecoming","year":2022,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama"],"overview":"Follow the journeys of Simone Hicks, a tennis hopeful from Beverly Hills, and elite baseball player Damon Sims from Chicago, as they navigate life at the prestigious HBCU Bringston University.","poster":"assets/tv-all-american-homecoming-2022-poster.jpg","backdrop":"assets/tv-all-american-homecoming-2022-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":153723,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.3,"tmdbVotes":70}},{"id":"tv-and-just-like-that-2021","title":"And Just Like That\u2026","year":2021,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy","Drama"],"overview":"This new chapter of \u201cSex and the City\u201d follows Carrie, Miranda and Charlotte as they navigate the journey from the complicated reality of life and friendship in their 30s to the even more complicated reality of life\u2026","poster":"assets/tv-and-just-like-that-2021-poster.jpg","backdrop":"assets/tv-and-just-like-that-2021-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":116450,"ratings":{"rtCritics":52,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.211,"tmdbVotes":556}},{"id":"tv-anne-with-an-e-2017","title":"Anne with an E","year":2017,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Family"],"overview":"A coming-of-age story about an outsider who, against all odds and numerous challenges, fights for love and acceptance and for her place in the world. The series centers on a young orphaned girl in the late 1890s,\u2026","poster":"assets/tv-anne-with-an-e-2017-poster.jpg","backdrop":"assets/tv-anne-with-an-e-2017-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":70785,"ratings":{"rtCritics":63,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.7,"tmdbVotes":5019}},{"id":"tv-awkward-2011","title":"Awkward.","year":2011,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy","Drama"],"overview":"An irreverent look at the conflict, chaos and humor that defines teenage life through the eyes of 15-year-old Jenna Hamilton whose life begins to change when a simple accident becomes an epic misunderstanding and is\u2026","poster":"assets/tv-awkward-2011-poster.jpg","backdrop":"assets/tv-awkward-2011-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":39859,"ratings":{"rtCritics":78,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.4,"tmdbVotes":427}},{"id":"tv-the-baby-sitters-club-2020","title":"The Baby-Sitters Club","year":2020,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Kids","Drama"],"overview":"In this contemporary take on the beloved book series, five best friends launch a baby-sitting business that's big on fun and adventure.","poster":"assets/tv-the-baby-sitters-club-2020-poster.jpg","backdrop":"assets/tv-the-baby-sitters-club-2020-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":100412,"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.9,"tmdbVotes":506}},{"id":"tv-ballers-2015","title":"Ballers","year":2015,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Comedy"],"overview":"Looking at the lives of former and current football players, the show follows former superstar Spencer Strasmore as he gets his life on track in retirement while mentoring other current and former players through the\u2026","poster":"assets/tv-ballers-2015-poster.jpg","backdrop":"assets/tv-ballers-2015-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":62704,"ratings":{"rtCritics":72,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.809,"tmdbVotes":820}},{"id":"tv-baretta-1975","title":"Baretta","year":1975,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Crime","Drama","Mystery"],"overview":"Baretta is an American detective television series which ran on ABC from 1975 to 1978. The show was a milder version of a successful 1973\u201374 ABC series, Toma, starring Tony Musante as chameleon-like, real-life New\u2026","poster":"assets/tv-baretta-1975-poster.jpg","backdrop":"assets/tv-baretta-1975-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":3216,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.5,"tmdbVotes":43}},{"id":"tv-based-on-a-true-story-2023","title":"Based on a True Story","year":2023,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy","Drama"],"overview":"The lives of a realtor, a plumber and a former tennis star unexpectedly collide, exposing America\u2019s obsession with true crime, murder and the slow-close toilet seat.","poster":"assets/tv-based-on-a-true-story-2023-poster.jpg","backdrop":"assets/tv-based-on-a-true-story-2023-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":197373,"ratings":{"rtCritics":79,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7,"tmdbVotes":160}},{"id":"tv-the-beast-in-me-2025","title":"The Beast in Me","year":2025,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Mystery"],"overview":"A famous author is pulled into a twisted mind game with her rich, powerful new neighbor \u2014 who might be a murderer.","poster":"assets/tv-the-beast-in-me-2025-poster.jpg","backdrop":"assets/tv-the-beast-in-me-2025-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":250504,"ratings":{"rtCritics":85,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.072,"tmdbVotes":334}},{"id":"tv-big-city-greens-2018","title":"Big City Greens","year":2018,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Family","Animation","Comedy"],"overview":"The offbeat adventures of 10-year-old Cricket Green, a mischievous and optimistic country boy who moves to the big city with his wildly out of place family \u2013 older sister Tilly, father Bill and Gramma Alice.","poster":"assets/tv-big-city-greens-2018-poster.jpg","backdrop":"assets/tv-big-city-greens-2018-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":80587,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.555,"tmdbVotes":82}},{"id":"tv-the-bold-type-2017","title":"The Bold Type","year":2017,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Comedy"],"overview":"A glimpse into the outrageous lives of Jane, Kat and Sutton, who are working at the nation's top women's magazine, Scarlet, while navigating their careers, identities and individual voices.","poster":"assets/tv-the-bold-type-2017-poster.jpg","backdrop":"assets/tv-the-bold-type-2017-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":69630,"ratings":{"rtCritics":89,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.7,"tmdbVotes":204}},{"id":"tv-brassic-2019","title":"Brassic","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy","Drama","Crime"],"overview":"A group of working-class friends finding unconventional ways to win at life in suburban northern England. These lads have dealt, scammed, bribed and conned their way through adolescence, but now, their dealing and\u2026","poster":"assets/tv-brassic-2019-poster.jpg","backdrop":"assets/tv-brassic-2019-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":92621,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.336,"tmdbVotes":263}}],"discoverySource":{"state":"materialized_snapshot","rankKnown":false,"selection":"First 18 alphabetically indexed movie stubs and first 18 series stubs, not ranked feed order","observedAt":"2026-11-04T20:42:12.030108+00:00"}},{"key":"shared","name":"Shared","initial":"S","color":"#9be38f","destinations":{"Home":{"kind":"home"},"Movies":{"kind":"library","collection":"movies"},"Shows":{"kind":"library","collection":"shows"},"Discover":{"kind":"discover","collection":"discover"}},"movies":[{"id":"movie-american-gangster-2007","title":"American Gangster","year":2007,"type":"movie","runtimeSeconds":10546,"seasonCount":null,"communityRating":7.595,"criticRating":81,"genres":["Drama","Crime"],"overview":"Loosely based on the criminal career of Frank Lucas, a gangster from La Grange, North Carolina, who smuggled heroin into the United States on American service planes returning from the Vietnam War, before being\u2026","poster":"assets/movie-american-gangster-2007-poster.jpg","backdrop":"assets/movie-american-gangster-2007-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-08-23T10:22:36.0000000Z","lastPlayedAt":"2026-08-30T21:05:39.7952451Z","availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":4982,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":81,"rtCriticsLabel":"Certified Fresh","rtAudience":90,"rtAudienceLabel":"Upright","imdb":7.8,"imdbVotes":495656,"tmdb":7.599,"tmdbVotes":6350}},{"id":"movie-annie-hall-1977","title":"Annie Hall","year":1977,"type":"movie","runtimeSeconds":5604,"seasonCount":null,"communityRating":7.712,"criticRating":97,"genres":["Comedy","Drama","Romance"],"overview":"New York comedian Alvy Singer falls in love with the ditsy Annie Hall.","poster":"assets/movie-annie-hall-1977-poster.jpg","backdrop":"assets/movie-annie-hall-1977-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:24:23.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":703,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":97,"rtCriticsLabel":"Certified Fresh","rtAudience":92,"rtAudienceLabel":"Upright","imdb":7.9,"imdbVotes":293349,"tmdb":7.71,"tmdbVotes":4391}},{"id":"movie-apocalypse-now-1979","title":"Apocalypse Now","year":1979,"type":"movie","runtimeSeconds":8835,"seasonCount":null,"communityRating":8.261,"criticRating":91,"genres":["Drama","War"],"overview":"At the height of the Vietnam war, Captain Benjamin Willard is sent on a dangerous mission that, officially, \"does not exist, nor will it ever exist.\" His goal is to locate - and eliminate - a mysterious Green Beret\u2026","poster":"assets/movie-apocalypse-now-1979-poster.jpg","backdrop":"assets/movie-apocalypse-now-1979-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:22:25.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":28,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":91,"rtCriticsLabel":"Certified Fresh","rtAudience":94,"rtAudienceLabel":"Upright","imdb":8.4,"imdbVotes":781424,"tmdb":8.3,"tmdbVotes":9526}},{"id":"movie-arrival-2016","title":"Arrival","year":2016,"type":"movie","runtimeSeconds":6967,"seasonCount":null,"communityRating":7.636,"criticRating":94,"genres":["Drama","Science Fiction","Mystery"],"overview":"Taking place after alien crafts land around the world, an expert linguist is recruited by the military to determine whether they come in peace or are a threat.","poster":"assets/movie-arrival-2016-poster.jpg","backdrop":"assets/movie-arrival-2016-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-14T19:54:12.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":329865,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":94,"rtCriticsLabel":"Certified Fresh","rtAudience":83,"rtAudienceLabel":"Upright","imdb":7.9,"imdbVotes":883621,"tmdb":7.638,"tmdbVotes":20125}},{"id":"movie-avatar-aang-the-last-airbender-2026","title":"Avatar Aang: The Last Airbender","year":2026,"type":"movie","runtimeSeconds":5930,"seasonCount":null,"communityRating":9.147,"criticRating":90,"genres":["Animation","Adventure","Fantasy"],"overview":"Avatar Aang, the world's last Airbender, learns of an ancient power that could save his culture from extinction. With the help of his friends, he embarks on a global quest to find it before it falls into the wrong\u2026","poster":"assets/movie-avatar-aang-the-last-airbender-2026-poster.jpg","backdrop":"assets/movie-avatar-aang-the-last-airbender-2026-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-25T09:53:09.0000000Z","lastPlayedAt":"2026-08-02T19:22:33.6155383Z","availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":980431,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":90,"rtCriticsLabel":"Certified Fresh","rtAudience":99,"rtAudienceLabel":"Upright","imdb":7.7,"imdbVotes":30792,"tmdb":9,"tmdbVotes":1417}},{"id":"movie-bohemian-rhapsody-2018","title":"Bohemian Rhapsody","year":2018,"type":"movie","runtimeSeconds":8077,"seasonCount":null,"communityRating":7.95,"criticRating":60,"genres":["Music","Drama"],"overview":"Singer Freddie Mercury, guitarist Brian May, drummer Roger Taylor and bass guitarist John Deacon take the music world by storm when they form the rock 'n' roll band Queen in 1970. Hit songs become instant classics.\u2026","poster":"assets/movie-bohemian-rhapsody-2018-poster.jpg","backdrop":"assets/movie-bohemian-rhapsody-2018-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:28:20.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":424694,"artwork":{"posterKind":"center_crop","backdropKind":"backdrop"},"ratings":{"rtCritics":60,"rtCriticsLabel":"Fresh","rtAudience":85,"rtAudienceLabel":"Upright","imdb":7.9,"imdbVotes":655894,"tmdb":7.947,"tmdbVotes":18196}},{"id":"movie-the-boy-and-the-heron-2023","title":"The Boy and the Heron","year":2023,"type":"movie","runtimeSeconds":7437,"seasonCount":null,"communityRating":7.4,"criticRating":96,"genres":["Animation","Fantasy","Drama"],"overview":"While the Second World War rages, the teenage Mahito, haunted by his mother's tragic death, is relocated from Tokyo to the serene rural home of his new stepmother Natsuko, a woman who bears a striking resemblance to\u2026","poster":"assets/movie-the-boy-and-the-heron-2023-poster.jpg","backdrop":"assets/movie-the-boy-and-the-heron-2023-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:25:15.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":508883,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":96,"rtCriticsLabel":"Certified Fresh","rtAudience":88,"rtAudienceLabel":"Upright","imdb":7.3,"imdbVotes":152169,"tmdb":7.387,"tmdbVotes":2893}},{"id":"movie-braveheart-1995","title":"Braveheart","year":1995,"type":"movie","runtimeSeconds":10665,"seasonCount":null,"communityRating":7.945,"criticRating":74,"genres":["Drama","History","War"],"overview":"Enraged at the slaughter of Murron, his new bride and childhood love, Scottish warrior William Wallace slays a platoon of the local English lord's soldiers. This leads the village to revolt and, eventually, the\u2026","poster":"assets/movie-braveheart-1995-poster.jpg","backdrop":"assets/movie-braveheart-1995-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-10T21:24:28.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":197,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":74,"rtCriticsLabel":"Certified Fresh","rtAudience":85,"rtAudienceLabel":"Upright","imdb":8.3,"imdbVotes":1174990,"tmdb":7.947,"tmdbVotes":11584}},{"id":"movie-the-breakfast-club-1985","title":"The Breakfast Club","year":1985,"type":"movie","runtimeSeconds":5833,"seasonCount":null,"communityRating":7.7,"criticRating":87,"genres":["Comedy","Drama"],"overview":"Five high school students from different walks of life endure a Saturday detention under a power-hungry principal. The disparate group includes rebel John, princess Claire, outcast Allison, brainy Brian and Andrew,\u2026","poster":"assets/movie-the-breakfast-club-1985-poster.jpg","backdrop":"assets/movie-the-breakfast-club-1985-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:25:03.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":2108,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":87,"rtCriticsLabel":"Certified Fresh","rtAudience":92,"rtAudienceLabel":"Upright","imdb":7.8,"imdbVotes":478743,"tmdb":7.713,"tmdbVotes":8815}},{"id":"movie-castle-in-the-sky-1986","title":"Castle in the Sky","year":1986,"type":"movie","runtimeSeconds":7474,"seasonCount":null,"communityRating":8,"criticRating":97,"genres":["Adventure","Fantasy","Animation"],"overview":"A young boy and a girl with a magic crystal must race against pirates and foreign agents in a search for a legendary floating castle.","poster":"assets/movie-castle-in-the-sky-1986-poster.jpg","backdrop":"assets/movie-castle-in-the-sky-1986-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:23:09.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":10515,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":96,"rtCriticsLabel":"Fresh","rtAudience":91,"rtAudienceLabel":"Upright","imdb":8,"imdbVotes":201545,"tmdb":7.972,"tmdbVotes":4868}},{"id":"movie-citizen-kane-1941","title":"Citizen Kane","year":1941,"type":"movie","runtimeSeconds":7173,"seasonCount":null,"communityRating":7.966,"criticRating":99,"genres":["Mystery","Drama"],"overview":"Newspaper magnate Charles Foster Kane is taken from his mother as a boy and made the ward of a rich industrialist. As a result, every well-meaning, tyrannical or self-destructive move he makes for the rest of his\u2026","poster":"assets/movie-citizen-kane-1941-poster.jpg","backdrop":"assets/movie-citizen-kane-1941-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:22:16.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":15,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":99,"rtCriticsLabel":"Certified Fresh","rtAudience":98,"rtAudienceLabel":"Upright","imdb":8.2,"imdbVotes":498321,"tmdb":7.962,"tmdbVotes":6324}},{"id":"movie-conclave-2024","title":"Conclave","year":2024,"type":"movie","runtimeSeconds":7230,"seasonCount":null,"communityRating":7.19,"criticRating":93,"genres":["Drama","Thriller"],"overview":"After the unexpected death of the Pope, Cardinal Lawrence is tasked with managing the covert and ancient ritual of electing a new one. Sequestered in the Vatican with the Catholic Church\u2019s most powerful leaders until\u2026","poster":"assets/movie-conclave-2024-poster.jpg","backdrop":"assets/movie-conclave-2024-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:30:41.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":974576,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":93,"rtCriticsLabel":"Certified Fresh","rtAudience":86,"rtAudienceLabel":"Upright","imdb":7.4,"imdbVotes":290498,"tmdb":7.19,"tmdbVotes":3744}},{"id":"movie-the-dry-2021","title":"The Dry","year":2021,"type":"movie","runtimeSeconds":7037,"seasonCount":null,"communityRating":6.779,"criticRating":null,"genres":["Crime","Thriller","Mystery"],"overview":"Aaron Falk returns to his drought-stricken hometown to attend a tragic funeral. But his return opens a decades-old wound - the unsolved death of a teenage girl.","poster":"assets/movie-the-dry-2021-poster.jpg","backdrop":"assets/movie-the-dry-2021-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:29:20.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":567797,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":90,"rtCriticsLabel":"Certified Fresh","rtAudience":89,"rtAudienceLabel":"Upright","imdb":6.8,"imdbVotes":41935,"tmdb":6.8,"tmdbVotes":892}},{"id":"movie-easy-a-2010","title":"Easy A","year":2010,"type":"movie","runtimeSeconds":5545,"seasonCount":null,"communityRating":6.8,"criticRating":85,"genres":["Comedy"],"overview":"Olive, an average high school student, sees her below-the-radar existence turn around overnight once she decides to use the school's gossip grapevine to advance her social standing. Now her classmates are turning\u2026","poster":"assets/movie-easy-a-2010-poster.jpg","backdrop":"assets/movie-easy-a-2010-backdrop.jpg","played":true,"playCount":1,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-17T19:59:04.0000000Z","lastPlayedAt":"2026-10-17T20:02:51.1083337Z","availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":37735,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":85,"rtCriticsLabel":"Certified Fresh","rtAudience":77,"rtAudienceLabel":"Upright","imdb":7,"imdbVotes":448780,"tmdb":6.8,"tmdbVotes":7619}},{"id":"movie-el-camino-a-breaking-bad-movie-2019","title":"El Camino: A Breaking Bad Movie","year":2019,"type":"movie","runtimeSeconds":7362,"seasonCount":null,"communityRating":7.055,"criticRating":92,"genres":["Crime","Drama","Thriller"],"overview":"In the wake of his dramatic escape from captivity, Jesse Pinkman must come to terms with his past in order to forge some kind of future.","poster":"assets/movie-el-camino-a-breaking-bad-movie-2019-poster.jpg","backdrop":"assets/movie-el-camino-a-breaking-bad-movie-2019-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-21T23:31:11.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":559969,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":92,"rtCriticsLabel":"Certified Fresh","rtAudience":81,"rtAudienceLabel":"Upright","imdb":7.3,"imdbVotes":354488,"tmdb":7.056,"tmdbVotes":5950}},{"id":"movie-emancipation-2022","title":"Emancipation","year":2022,"type":"movie","runtimeSeconds":7949,"seasonCount":null,"communityRating":7.7,"criticRating":45,"genres":["Drama","War","History"],"overview":"Inspired by the gripping true story of a man who would do anything for his family\u2014and for freedom. When Peter, an enslaved man, risks his life to escape and return to his family, he embarks on a perilous journey of\u2026","poster":"assets/movie-emancipation-2022-poster.jpg","backdrop":"assets/movie-emancipation-2022-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-10T20:37:34.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":715931,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":45,"rtCriticsLabel":"Rotten","rtAudience":58,"rtAudienceLabel":"Spilled","imdb":6.3,"imdbVotes":32079,"tmdb":7.744,"tmdbVotes":1319}},{"id":"movie-fighting-with-my-family-2019","title":"Fighting with My Family","year":2019,"type":"movie","runtimeSeconds":6509,"seasonCount":null,"communityRating":6.84,"criticRating":93,"genres":["Comedy"],"overview":"Born into a tight-knit wrestling family, Paige and her brother Zak are ecstatic when they get the once-in-a-lifetime opportunity to try out for the WWE. But when only Paige earns a spot in the competitive training\u2026","poster":"assets/movie-fighting-with-my-family-2019-poster.jpg","backdrop":"assets/movie-fighting-with-my-family-2019-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-22T22:10:59.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":445629,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":93,"rtCriticsLabel":"Certified Fresh","rtAudience":86,"rtAudienceLabel":"Upright","imdb":7,"imdbVotes":94576,"tmdb":6.837,"tmdbVotes":1952}},{"id":"movie-force-of-nature-the-dry-2-2024","title":"Force of Nature: The Dry 2","year":2024,"type":"movie","runtimeSeconds":6753,"seasonCount":null,"communityRating":6.3,"criticRating":66,"genres":["Mystery","Thriller"],"overview":"When five women take part in a corporate hiking retreat and only four come out on the other side, Federal Agents Aaron Falk and Carmen Cooper head deep into the Victorian mountain ranges to investigate in the hopes\u2026","poster":"assets/movie-force-of-nature-the-dry-2-2024-poster.jpg","backdrop":"assets/movie-force-of-nature-the-dry-2-2024-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:29:49.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":832262,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":66,"rtCriticsLabel":"Fresh","rtAudience":43,"rtAudienceLabel":"Spilled","imdb":5.9,"imdbVotes":10343,"tmdb":6.269,"tmdbVotes":305}},{"id":"movie-free-state-of-jones-2016","title":"Free State of Jones","year":2016,"type":"movie","runtimeSeconds":8376,"seasonCount":null,"communityRating":6.79,"criticRating":48,"genres":["Action","Drama","History"],"overview":"In 1863, Mississippi farmer Newt Knight serves as a medic for the Confederate Army. Opposed to slavery, Knight would rather help the wounded than fight the Union. After his nephew dies in battle, Newt returns home to\u2026","poster":"assets/movie-free-state-of-jones-2016-poster.jpg","backdrop":"assets/movie-free-state-of-jones-2016-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-11T17:56:53.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":316152,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":48,"rtCriticsLabel":"Rotten","rtAudience":64,"rtAudienceLabel":"Upright","imdb":6.9,"imdbVotes":68931,"tmdb":6.788,"tmdbVotes":1730}},{"id":"movie-from-up-on-poppy-hill-2011","title":"From Up on Poppy Hill","year":2011,"type":"movie","runtimeSeconds":5482,"seasonCount":null,"communityRating":7.5,"criticRating":87,"genres":["Animation","Drama"],"overview":"Yokohama, 1963. Japan is picking itself up from the devastation of World War II and preparing to host the 1964 Olympics\u2014and the mood is one of both optimism and conflict as the young generation struggles to throw off\u2026","poster":"assets/movie-from-up-on-poppy-hill-2011-poster.jpg","backdrop":"assets/movie-from-up-on-poppy-hill-2011-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-07T14:41:03.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":83389,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":87,"rtCriticsLabel":"Certified Fresh","rtAudience":80,"rtAudienceLabel":"Upright","imdb":7.4,"imdbVotes":60769,"tmdb":7.509,"tmdbVotes":2026}},{"id":"movie-ghost-in-the-shell-1995","title":"Ghost in the Shell","year":1995,"type":"movie","runtimeSeconds":4959,"seasonCount":null,"communityRating":7.929,"criticRating":95,"genres":["Action","Animation","Science Fiction"],"overview":"In the year 2029, the barriers of our world have been broken down by the net and by cybernetics, but this brings new vulnerability to humans in the form of brain-hacking. When a highly-wanted hacker known as 'The\u2026","poster":"assets/movie-ghost-in-the-shell-1995-poster.jpg","backdrop":"assets/movie-ghost-in-the-shell-1995-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:22:57.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":9323,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":97,"rtCriticsLabel":"Certified Fresh","rtAudience":90,"rtAudienceLabel":"Upright","imdb":7.9,"imdbVotes":178061,"tmdb":7.928,"tmdbVotes":4130}},{"id":"movie-ghost-in-the-shell-2-innocence-2004","title":"Ghost in the Shell 2: Innocence","year":2004,"type":"movie","runtimeSeconds":5950,"seasonCount":null,"communityRating":7.352,"criticRating":65,"genres":["Animation","Drama","Science Fiction"],"overview":"Cyborg detective Batou is assigned to investigate a series of murders committed by gynoids\u2014doll-like cyborgs, which all malfunctioned, killed, then self-destructed afterwards. The brains of the gynoids initialize in\u2026","poster":"assets/movie-ghost-in-the-shell-2-innocence-2004-poster.jpg","backdrop":"assets/movie-ghost-in-the-shell-2-innocence-2004-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:23:38.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":12140,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":65,"rtCriticsLabel":"Fresh","rtAudience":80,"rtAudienceLabel":"Upright","imdb":7.4,"imdbVotes":43280,"tmdb":7.356,"tmdbVotes":1049}},{"id":"movie-the-godfather-1972","title":"The Godfather","year":1972,"type":"movie","runtimeSeconds":10603,"seasonCount":null,"communityRating":8.687,"criticRating":97,"genres":["Drama","Crime"],"overview":"Spanning the years 1945 to 1955, a chronicle of the fictional Italian-American Corleone crime family. When organized crime family patriarch, Vito Corleone barely survives an attempt on his life, his youngest son,\u2026","poster":"assets/movie-the-godfather-1972-poster.jpg","backdrop":"assets/movie-the-godfather-1972-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:24:12.0000000Z","lastPlayedAt":"2026-09-18T19:24:44.9855867Z","availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":238,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":97,"rtCriticsLabel":"Certified Fresh","rtAudience":98,"rtAudienceLabel":"Upright","imdb":9.2,"imdbVotes":2262024,"tmdb":8.688,"tmdbVotes":23907}},{"id":"movie-the-godfather-part-ii-1974","title":"The Godfather Part II","year":1974,"type":"movie","runtimeSeconds":12031,"seasonCount":null,"communityRating":8.573,"criticRating":96,"genres":["Drama","Crime"],"overview":"In the continuing saga of the Corleone crime family, a young Vito Corleone grows up in Sicily and in 1910s New York. In the 1950s, Michael Corleone attempts to expand the family business into Las Vegas, Hollywood and\u2026","poster":"assets/movie-the-godfather-part-ii-1974-poster.jpg","backdrop":"assets/movie-the-godfather-part-ii-1974-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:24:18.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":240,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":96,"rtCriticsLabel":"Certified Fresh","rtAudience":97,"rtAudienceLabel":"Upright","imdb":9,"imdbVotes":1521308,"tmdb":8.571,"tmdbVotes":14559}},{"id":"movie-the-godfather-part-iii-1990","title":"The Godfather Part III","year":1990,"type":"movie","runtimeSeconds":9476,"seasonCount":null,"communityRating":7.416,"criticRating":67,"genres":["Crime","Drama","Thriller"],"overview":"In the midst of trying to legitimize his business dealings in 1979 New York and Italy, aging mafia don, Michael Corleone seeks forgiveness for his sins while taking a young protege under his wing.","poster":"assets/movie-the-godfather-part-iii-1990-poster.jpg","backdrop":"assets/movie-the-godfather-part-iii-1990-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:26:29.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":242,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":68,"rtCriticsLabel":"Fresh","rtAudience":68,"rtAudienceLabel":"Upright","imdb":7.5,"imdbVotes":462448,"tmdb":7.413,"tmdbVotes":7159}},{"id":"movie-gosford-park-2001","title":"Gosford Park","year":2001,"type":"movie","runtimeSeconds":8247,"seasonCount":null,"communityRating":6.815,"criticRating":87,"genres":["Drama","Mystery","Thriller"],"overview":"In 1930s England, a group of pretentious rich and famous gather together for a weekend of relaxation at a hunting resort. But when a murder occurs, each one of these interesting characters becomes a suspect.","poster":"assets/movie-gosford-park-2001-poster.jpg","backdrop":"assets/movie-gosford-park-2001-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:25:49.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":5279,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":87,"rtCriticsLabel":"Certified Fresh","rtAudience":78,"rtAudienceLabel":"Upright","imdb":7.2,"imdbVotes":103883,"tmdb":6.822,"tmdbVotes":1317}},{"id":"movie-grave-of-the-fireflies-1988","title":"Grave of the Fireflies","year":1988,"type":"movie","runtimeSeconds":5313,"seasonCount":null,"communityRating":8.45,"criticRating":100,"genres":["Animation","Drama","War"],"overview":"In the final months of World War II, 14-year-old Seita and his sister Setsuko are orphaned when their mother is killed during an air raid in Kobe, Japan. After a falling out with their aunt, they move into an\u2026","poster":"assets/movie-grave-of-the-fireflies-1988-poster.jpg","backdrop":"assets/movie-grave-of-the-fireflies-1988-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:24:14.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":12477,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Certified Fresh","rtAudience":95,"rtAudienceLabel":"Upright","imdb":8.5,"imdbVotes":399802,"tmdb":8.45,"tmdbVotes":6938}},{"id":"movie-the-great-gatsby-2013","title":"The Great Gatsby","year":2013,"type":"movie","runtimeSeconds":8525,"seasonCount":null,"communityRating":7.346,"criticRating":49,"genres":["Drama","Romance"],"overview":"Nick Carraway arrives in New York in 1922, an era of loose morals, glittering jazz and bootleg kings. Chasing his own American Dream, Nick encounters the mysterious millionaire Gatsby and his bewitching cousin Daisy.\u2026","poster":"assets/movie-the-great-gatsby-2013-poster.jpg","backdrop":"assets/movie-the-great-gatsby-2013-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:26:50.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":64682,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":48,"rtCriticsLabel":"Rotten","rtAudience":67,"rtAudienceLabel":"Upright","imdb":7.2,"imdbVotes":651882,"tmdb":7.346,"tmdbVotes":13290}},{"id":"movie-the-hours-2002","title":"The Hours","year":2002,"type":"movie","runtimeSeconds":6887,"seasonCount":null,"communityRating":7.25,"criticRating":79,"genres":["Drama"],"overview":"The story of three women searching for more potent, meaningful lives. Each is alive at a different time and place, all are linked by their yearnings and their fears. Their stories intertwine, and finally come\u2026","poster":"assets/movie-the-hours-2002-poster.jpg","backdrop":"assets/movie-the-hours-2002-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:23:27.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":590,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":79,"rtCriticsLabel":"Certified Fresh","rtAudience":84,"rtAudienceLabel":"Upright","imdb":7.5,"imdbVotes":148367,"tmdb":7.249,"tmdbVotes":1931}},{"id":"movie-howl-s-moving-castle-2004","title":"Howl's Moving Castle","year":2004,"type":"movie","runtimeSeconds":7149,"seasonCount":null,"communityRating":8.4,"criticRating":88,"genres":["Fantasy","Animation","Adventure"],"overview":"Sophie, a young milliner, is turned into an elderly woman by a witch who enters her shop and curses her. She encounters a wizard named Howl and gets caught up in his resistance to fighting for the king.","poster":"assets/movie-howl-s-moving-castle-2004-poster.jpg","backdrop":"assets/movie-howl-s-moving-castle-2004-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:22:47.0000000Z","lastPlayedAt":"2026-05-21T18:46:08.0000000Z","availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":4935,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":87,"rtCriticsLabel":"Certified Fresh","rtAudience":93,"rtAudienceLabel":"Upright","imdb":8.2,"imdbVotes":524520,"tmdb":8.391,"tmdbVotes":11642}},{"id":"movie-in-the-heights-2021","title":"In the Heights","year":2021,"type":"movie","runtimeSeconds":8579,"seasonCount":null,"communityRating":7.111,"criticRating":null,"genres":["Drama","Romance"],"overview":"The story of Usnavi, a bodega owner who has mixed feelings about closing his store and retiring to the Dominican Republic or staying in Washington Heights.","poster":"assets/movie-in-the-heights-2021-poster.jpg","backdrop":"assets/movie-in-the-heights-2021-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:29:11.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":467909,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":94,"rtCriticsLabel":"Certified Fresh","rtAudience":94,"rtAudienceLabel":"Upright","imdb":7.2,"imdbVotes":56513,"tmdb":7.104,"tmdbVotes":826}},{"id":"movie-jennifer-s-body-2009","title":"Jennifer's Body","year":2009,"type":"movie","runtimeSeconds":6450,"seasonCount":null,"communityRating":6.012,"criticRating":47,"genres":["Horror","Comedy"],"overview":"Jennifer, a gorgeous, seductive cheerleader takes evil to a whole new level after she's possessed by a sinister demon. Now it's up to her best friend to stop Jennifer's reign of terror before it's too late.","poster":"assets/movie-jennifer-s-body-2009-poster.jpg","backdrop":"assets/movie-jennifer-s-body-2009-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-30T03:37:04.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":19994,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":47,"rtCriticsLabel":"Rotten","rtAudience":36,"rtAudienceLabel":"Spilled","imdb":5.6,"imdbVotes":179710,"tmdb":6.013,"tmdbVotes":4481}},{"id":"movie-kiki-s-delivery-service-1989","title":"Kiki's Delivery Service","year":1989,"type":"movie","runtimeSeconds":6183,"seasonCount":null,"communityRating":7.839,"criticRating":null,"genres":["Animation","Family","Fantasy"],"overview":"A young witch, on her mandatory year of independent life, finds fitting into a new community difficult while she supports herself by running an air courier service.","poster":"assets/movie-kiki-s-delivery-service-1989-poster.jpg","backdrop":"assets/movie-kiki-s-delivery-service-1989-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:24:20.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":16859,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":98,"rtCriticsLabel":"Certified Fresh","rtAudience":89,"rtAudienceLabel":"Upright","imdb":7.8,"imdbVotes":192477,"tmdb":7.839,"tmdbVotes":4811}},{"id":"movie-the-last-of-the-mohicans-1992","title":"The Last of the Mohicans","year":1992,"type":"movie","runtimeSeconds":6874,"seasonCount":null,"communityRating":7.388,"criticRating":88,"genres":["History","War","Drama"],"overview":"In war-torn colonial America, in the midst of a bloody battle between British, the French and Native American allies, the aristocratic daughter of a British Colonel and her party are captured by a group of Huron\u2026","poster":"assets/movie-the-last-of-the-mohicans-1992-poster.jpg","backdrop":"assets/movie-the-last-of-the-mohicans-1992-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-10T20:59:22.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":9361,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":88,"rtCriticsLabel":"Certified Fresh","rtAudience":88,"rtAudienceLabel":"Upright","imdb":7.6,"imdbVotes":210791,"tmdb":7.39,"tmdbVotes":3593}},{"id":"movie-the-last-samurai-2003","title":"The Last Samurai","year":2003,"type":"movie","runtimeSeconds":9251,"seasonCount":null,"communityRating":7.61,"criticRating":65,"genres":["Drama","Action","War"],"overview":"Nathan Algren is an American hired to instruct the Japanese army in the ways of modern warfare, which finds him learning to respect the samurai and the honorable principles that rule them. Pressed to destroy the\u2026","poster":"assets/movie-the-last-samurai-2003-poster.jpg","backdrop":"assets/movie-the-last-samurai-2003-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-26T05:25:10.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":616,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":66,"rtCriticsLabel":"Fresh","rtAudience":83,"rtAudienceLabel":"Upright","imdb":7.8,"imdbVotes":512982,"tmdb":7.614,"tmdbVotes":7887}},{"id":"movie-lemony-snicket-s-a-series-of-unfortunate-events-2004","title":"Lemony Snicket's A Series of Unfortunate Events","year":2004,"type":"movie","runtimeSeconds":6479,"seasonCount":null,"communityRating":6.8,"criticRating":72,"genres":["Adventure","Comedy","Family"],"overview":"Three wealthy children's parents are killed in a fire. When they are sent to a distant relative, they find out that he is plotting to kill them and seize their fortune.","poster":"assets/movie-lemony-snicket-s-a-series-of-unfortunate-events-2004-poster.jpg","backdrop":"assets/movie-lemony-snicket-s-a-series-of-unfortunate-events-2004-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:26:09.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":11774,"artwork":{"posterKind":"center_crop","backdropKind":"backdrop"},"ratings":{"rtCritics":72,"rtCriticsLabel":"Fresh","rtAudience":63,"rtAudienceLabel":"Upright","imdb":6.8,"imdbVotes":233636,"tmdb":6.82,"tmdbVotes":5447}},{"id":"movie-the-lighthouse-2019","title":"The Lighthouse","year":2019,"type":"movie","runtimeSeconds":6549,"seasonCount":null,"communityRating":7.463,"criticRating":90,"genres":["Drama","Fantasy","Thriller"],"overview":"Two lighthouse keepers try to maintain their sanity while living on a remote and mysterious New England island in the 1890s.","poster":"assets/movie-the-lighthouse-2019-poster.jpg","backdrop":"assets/movie-the-lighthouse-2019-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:29:01.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":503919,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":90,"rtCriticsLabel":"Certified Fresh","rtAudience":72,"rtAudienceLabel":"Upright","imdb":7.3,"imdbVotes":312344,"tmdb":7.46,"tmdbVotes":5895}},{"id":"movie-locke-2014","title":"Locke","year":2014,"type":"movie","runtimeSeconds":5090,"seasonCount":null,"communityRating":6.888,"criticRating":91,"genres":["Drama","Thriller"],"overview":"Ivan Locke has worked hard to craft a good life for himself. Tonight, that life will collapse around him. On the eve of the biggest challenge of his career, Ivan receives a phone call that sets in motion a series of\u2026","poster":"assets/movie-locke-2014-poster.jpg","backdrop":"assets/movie-locke-2014-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T17:38:48.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":210479,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":90,"rtCriticsLabel":"Certified Fresh","rtAudience":72,"rtAudienceLabel":"Upright","imdb":7.1,"imdbVotes":171265,"tmdb":6.889,"tmdbVotes":3088}},{"id":"movie-the-matrix-1999","title":"The Matrix","year":1999,"type":"movie","runtimeSeconds":8179,"seasonCount":null,"communityRating":8.259,"criticRating":83,"genres":["Action","Science Fiction"],"overview":"Set in the 22nd century, The Matrix tells the story of a computer hacker who joins a group of underground insurgents fighting the vast and powerful computers who now rule the earth.","poster":"assets/movie-the-matrix-1999-poster.jpg","backdrop":"assets/movie-the-matrix-1999-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:18:12.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":603,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":83,"rtCriticsLabel":"Certified Fresh","rtAudience":85,"rtAudienceLabel":"Upright","imdb":8.7,"imdbVotes":2289808,"tmdb":8.262,"tmdbVotes":29153}},{"id":"movie-the-matrix-reloaded-2003","title":"The Matrix Reloaded","year":2003,"type":"movie","runtimeSeconds":8298,"seasonCount":null,"communityRating":7.085,"criticRating":74,"genres":["Adventure","Action","Thriller"],"overview":"The Resistance builds in numbers as humans are freed from the Matrix and brought to the city of Zion. Neo discovers his superpowers, including the ability to see the code inside the Matrix. With machine sentinels\u2026","poster":"assets/movie-the-matrix-reloaded-2003-poster.jpg","backdrop":"assets/movie-the-matrix-reloaded-2003-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:24:03.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":604,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":73,"rtCriticsLabel":"Certified Fresh","rtAudience":72,"rtAudienceLabel":"Upright","imdb":7.2,"imdbVotes":678013,"tmdb":7.087,"tmdbVotes":12504}},{"id":"movie-the-matrix-resurrections-2021","title":"The Matrix Resurrections","year":2021,"type":"movie","runtimeSeconds":8875,"seasonCount":null,"communityRating":6.303,"criticRating":63,"genres":["Science Fiction","Action","Adventure"],"overview":"Plagued by strange memories, Neo's life takes an unexpected turn when he finds himself back inside the Matrix.","poster":"assets/movie-the-matrix-resurrections-2021-poster.jpg","backdrop":"assets/movie-the-matrix-resurrections-2021-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:31:22.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":624860,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":63,"rtCriticsLabel":"Fresh","rtAudience":63,"rtAudienceLabel":"Upright","imdb":5.6,"imdbVotes":307780,"tmdb":6.294,"tmdbVotes":6842}},{"id":"movie-the-matrix-revolutions-2003","title":"The Matrix Revolutions","year":2003,"type":"movie","runtimeSeconds":7756,"seasonCount":null,"communityRating":6.758,"criticRating":33,"genres":["Adventure","Action","Thriller"],"overview":"The human city of Zion defends itself against the massive invasion of the machines as Neo fights to end the war at another front while also opposing the rogue Agent Smith.","poster":"assets/movie-the-matrix-revolutions-2003-poster.jpg","backdrop":"assets/movie-the-matrix-revolutions-2003-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:25:47.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":605,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":34,"rtCriticsLabel":"Rotten","rtAudience":60,"rtAudienceLabel":"Upright","imdb":6.8,"imdbVotes":581553,"tmdb":6.762,"tmdbVotes":11292}},{"id":"movie-mercy-2026","title":"Mercy","year":2026,"type":"movie","runtimeSeconds":5968,"seasonCount":null,"communityRating":7.077,"criticRating":null,"genres":["Science Fiction","Thriller","Crime"],"overview":"In the near future, a detective stands on trial accused of murdering his wife. He has ninety minutes to prove his innocence to the advanced AI Judge he once championed, before it determines his fate.","poster":"assets/movie-mercy-2026-poster.jpg","backdrop":"assets/movie-mercy-2026-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:31:40.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":1236153,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":24,"rtCriticsLabel":"Rotten","rtAudience":81,"rtAudienceLabel":"Upright","imdb":6.2,"imdbVotes":83878,"tmdb":7.054,"tmdbVotes":1812}},{"id":"movie-normal-2026","title":"Normal","year":2026,"type":"movie","runtimeSeconds":5514,"seasonCount":null,"communityRating":7.267,"criticRating":77,"genres":["Action","Crime","Thriller"],"overview":"An unassuming substitute sheriff with a troubled past responds to a bank robbery in a small, sleepy town and unknowingly uncovers something far more explosive.","poster":"assets/movie-normal-2026-poster.jpg","backdrop":"assets/movie-normal-2026-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-08-21T08:33:18.0000000Z","lastPlayedAt":"2026-09-24T23:07:52.1161581Z","availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":1242332,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":78,"rtCriticsLabel":"Certified Fresh","rtAudience":75,"rtAudienceLabel":"Upright","imdb":6.3,"imdbVotes":37501,"tmdb":7.241,"tmdbVotes":786}},{"id":"movie-outlaw-king-2018","title":"Outlaw King","year":2018,"type":"movie","runtimeSeconds":7297,"seasonCount":null,"communityRating":6.829,"criticRating":63,"genres":["Action","History","War"],"overview":"Forced into exile by the English after being crowned King of Scotland, legendary warrior Robert the Bruce fights to reclaim the throne.","poster":"assets/movie-outlaw-king-2018-poster.jpg","backdrop":"assets/movie-outlaw-king-2018-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:28:32.0000000Z","lastPlayedAt":"2026-07-26T22:35:35.0000000Z","availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":454227,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":63,"rtCriticsLabel":"Fresh","rtAudience":69,"rtAudienceLabel":"Upright","imdb":6.9,"imdbVotes":89876,"tmdb":6.844,"tmdbVotes":1780}},{"id":"movie-panic-room-2002","title":"Panic Room","year":2002,"type":"movie","runtimeSeconds":6717,"seasonCount":null,"communityRating":6.794,"criticRating":76,"genres":["Crime","Drama","Thriller"],"overview":"Trapped in their New York brownstone's panic room, a hidden chamber built as a sanctuary in the event of break-ins, newly divorced Meg Altman and her young daughter Sarah play a deadly game of cat-and-mouse with\u2026","poster":"assets/movie-panic-room-2002-poster.jpg","backdrop":"assets/movie-panic-room-2002-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-19T20:50:01.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":4547,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":76,"rtCriticsLabel":"Certified Fresh","rtAudience":64,"rtAudienceLabel":"Upright","imdb":6.8,"imdbVotes":317468,"tmdb":6.796,"tmdbVotes":5653}},{"id":"movie-the-patriot-2000","title":"The Patriot","year":2000,"type":"movie","runtimeSeconds":9887,"seasonCount":null,"communityRating":7.214,"criticRating":61,"genres":["Drama","History","War"],"overview":"After proving himself on the field of battle in the French and Indian War, Benjamin Martin wants nothing more to do with such things, preferring the simple life of a farmer. But when his son Gabriel enlists in the\u2026","poster":"assets/movie-the-patriot-2000-poster.jpg","backdrop":"assets/movie-the-patriot-2000-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-10T20:50:00.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":2024,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":61,"rtCriticsLabel":"Fresh","rtAudience":81,"rtAudienceLabel":"Upright","imdb":7.2,"imdbVotes":317639,"tmdb":7.215,"tmdbVotes":4535}},{"id":"movie-peaky-blinders-the-immortal-man-2026","title":"Peaky Blinders: The Immortal Man","year":2026,"type":"movie","runtimeSeconds":6844,"seasonCount":null,"communityRating":7.187,"criticRating":90,"genres":["Crime","Drama"],"overview":"After his estranged son gets embroiled in a Nazi plot, self-exiled gangster Tommy Shelby must return to Birmingham to save his family \u2014 and his nation.","poster":"assets/movie-peaky-blinders-the-immortal-man-2026-poster.jpg","backdrop":"assets/movie-peaky-blinders-the-immortal-man-2026-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:30:01.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":875828,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":90,"rtCriticsLabel":"Certified Fresh","rtAudience":87,"rtAudienceLabel":"Upright","imdb":6.5,"imdbVotes":92130,"tmdb":7.189,"tmdbVotes":1304}},{"id":"movie-ponyo-2008","title":"Ponyo","year":2008,"type":"movie","runtimeSeconds":6530,"seasonCount":null,"communityRating":7.763,"criticRating":91,"genres":["Animation","Fantasy","Family"],"overview":"When Sosuke, a young boy who lives on a clifftop overlooking the sea, rescues a stranded goldfish named Ponyo, he discovers more than he bargained for. Ponyo is a curious, energetic young creature who yearns to be\u2026","poster":"assets/movie-ponyo-2008-poster.jpg","backdrop":"assets/movie-ponyo-2008-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:23:53.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":12429,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":91,"rtCriticsLabel":"Certified Fresh","rtAudience":84,"rtAudienceLabel":"Upright","imdb":7.6,"imdbVotes":190294,"tmdb":7.759,"tmdbVotes":5050}},{"id":"movie-porco-rosso-1992","title":"Porco Rosso","year":1992,"type":"movie","runtimeSeconds":5600,"seasonCount":null,"communityRating":7.794,"criticRating":96,"genres":["Animation","Adventure","Fantasy"],"overview":"In Italy in the 1930s, sky pirates in biplanes terrorize wealthy cruise ships as they sail the Adriatic Sea. The only pilot brave enough to stop the scourge is the mysterious Porco Rosso, a former World War I flying\u2026","poster":"assets/movie-porco-rosso-1992-poster.jpg","backdrop":"assets/movie-porco-rosso-1992-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:23:22.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":11621,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":96,"rtCriticsLabel":"Fresh","rtAudience":87,"rtAudienceLabel":"Upright","imdb":7.7,"imdbVotes":119396,"tmdb":7.789,"tmdbVotes":3879}},{"id":"movie-princess-mononoke-1997","title":"Princess Mononoke","year":1997,"type":"movie","runtimeSeconds":8003,"seasonCount":null,"communityRating":8.321,"criticRating":93,"genres":["Adventure","Fantasy","Animation"],"overview":"Ashitaka, a prince of the disappearing Emishi people, is cursed by a demonized boar god and must journey to the west to find a cure. Along the way, he encounters San, a young human woman fighting to protect the\u2026","poster":"assets/movie-princess-mononoke-1997-poster.jpg","backdrop":"assets/movie-princess-mononoke-1997-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:22:28.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":128,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":94,"rtCriticsLabel":"Certified Fresh","rtAudience":99,"rtAudienceLabel":"Upright","imdb":8.3,"imdbVotes":493735,"tmdb":8.321,"tmdbVotes":9438}},{"id":"movie-prisoners-2013","title":"Prisoners","year":2013,"type":"movie","runtimeSeconds":9192,"seasonCount":null,"communityRating":8.106,"criticRating":81,"genres":["Drama","Thriller","Crime"],"overview":"After his six-year-old daughter is abducted, a desperate father takes justice into his own hands when he loses faith in the detective leading the investigation, setting both men on a collision course as the search\u2026","poster":"assets/movie-prisoners-2013-poster.jpg","backdrop":"assets/movie-prisoners-2013-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:27:33.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":146233,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":82,"rtCriticsLabel":"Certified Fresh","rtAudience":87,"rtAudienceLabel":"Upright","imdb":8.2,"imdbVotes":963062,"tmdb":8.105,"tmdbVotes":13722}},{"id":"movie-racing-stripes-2005","title":"Racing Stripes","year":2005,"type":"movie","runtimeSeconds":6117,"seasonCount":null,"communityRating":5.945,"criticRating":35,"genres":["Comedy","Family"],"overview":"Shattered illusions are hard to repair -- especially for a good-hearted zebra named Stripes who's spent his life on a Kentucky farm amidst the sorely mistaken notion that he's a debonair thoroughbred. Once he faces\u2026","poster":"assets/movie-racing-stripes-2005-poster.jpg","backdrop":"assets/movie-racing-stripes-2005-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:26:02.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":6439,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":35,"rtCriticsLabel":"Rotten","rtAudience":42,"rtAudienceLabel":"Spilled","imdb":5.3,"imdbVotes":19569,"tmdb":5.962,"tmdbVotes":705}},{"id":"movie-requiem-for-a-dream-2000","title":"Requiem for a Dream","year":2000,"type":"movie","runtimeSeconds":6086,"seasonCount":null,"communityRating":8.005,"criticRating":80,"genres":["Crime","Drama"],"overview":"The drug-induced utopias of four Coney Island residents are shattered when their addictions run deep.","poster":"assets/movie-requiem-for-a-dream-2000-poster.jpg","backdrop":"assets/movie-requiem-for-a-dream-2000-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:24:15.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":641,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":81,"rtCriticsLabel":"Certified Fresh","rtAudience":93,"rtAudienceLabel":"Upright","imdb":8.3,"imdbVotes":989090,"tmdb":8,"tmdbVotes":11454}},{"id":"movie-rogue-one-a-star-wars-story-2016","title":"Rogue One: A Star Wars Story","year":2016,"type":"movie","runtimeSeconds":8038,"seasonCount":null,"communityRating":7.51,"criticRating":84,"genres":["Action","Adventure","Science Fiction"],"overview":"A rogue band of resistance fighters unite for a mission to steal the Death Star plans and bring a new hope to the galaxy.","poster":"assets/movie-rogue-one-a-star-wars-story-2016-poster.jpg","backdrop":"assets/movie-rogue-one-a-star-wars-story-2016-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:28:00.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":330459,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":84,"rtCriticsLabel":"Certified Fresh","rtAudience":87,"rtAudienceLabel":"Upright","imdb":7.8,"imdbVotes":768365,"tmdb":7.512,"tmdbVotes":16937}},{"id":"movie-secondhand-lions-2003","title":"Secondhand Lions","year":2003,"type":"movie","runtimeSeconds":6547,"seasonCount":null,"communityRating":7.237,"criticRating":60,"genres":["Family","Comedy","Drama"],"overview":"The comedic adventures of an introverted boy left on the doorstep of a pair of reluctant, eccentric great-uncles, whose exotic remembrances stir the boy's spirit and re-ignite the men's lives.","poster":"assets/movie-secondhand-lions-2003-poster.jpg","backdrop":"assets/movie-secondhand-lions-2003-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-12T07:16:13.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":13156,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":59,"rtCriticsLabel":"Rotten","rtAudience":84,"rtAudienceLabel":"Upright","imdb":7.5,"imdbVotes":66911,"tmdb":7.242,"tmdbVotes":872}},{"id":"movie-the-secret-life-of-pets-2-2019","title":"The Secret Life of Pets 2","year":2019,"type":"movie","runtimeSeconds":5164,"seasonCount":null,"communityRating":6.95,"criticRating":60,"genres":["Animation","Comedy","Family"],"overview":"Max the terrier must cope with some major life changes when his owner gets married and has a baby. When the family takes a trip to the countryside, nervous Max has numerous run-ins with canine-intolerant cows,\u2026","poster":"assets/movie-the-secret-life-of-pets-2-2019-poster.jpg","backdrop":"assets/movie-the-secret-life-of-pets-2-2019-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-05T07:00:53.0000000Z","lastPlayedAt":"2026-09-17T18:07:00.7024231Z","availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":412117,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":60,"rtCriticsLabel":"Fresh","rtAudience":90,"rtAudienceLabel":"Upright","imdb":6.4,"imdbVotes":80464,"tmdb":6.948,"tmdbVotes":3450}},{"id":"movie-self-reliance-2024","title":"Self Reliance","year":2024,"type":"movie","runtimeSeconds":5461,"seasonCount":null,"communityRating":5.888,"criticRating":73,"genres":["Comedy","Thriller"],"overview":"When a man is offered a million dollars to play a game in which hunters try to kill him, he thinks he has found the perfect loophole: they can only attack when he\u2019s alone. His only problem is that none of his friends\u2026","poster":"assets/movie-self-reliance-2024-poster.jpg","backdrop":"assets/movie-self-reliance-2024-backdrop.jpg","played":false,"playCount":1,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:31:00.0000000Z","lastPlayedAt":"2026-10-02T19:59:16.9286868Z","availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":1072876,"artwork":{"posterKind":"center_crop","backdropKind":"backdrop"},"ratings":{"rtCritics":73,"rtCriticsLabel":"Certified Fresh","rtAudience":56,"rtAudienceLabel":"Spilled","imdb":6,"imdbVotes":23771,"tmdb":5.866,"tmdbVotes":346}},{"id":"movie-serpico-1973","title":"Serpico","year":1973,"type":"movie","runtimeSeconds":7805,"seasonCount":null,"communityRating":7.5,"criticRating":93,"genres":["Crime","Drama","History"],"overview":"New York cop Frank Serpico blows the whistle on the rampant corruption in the force only to have his comrades turn against him.","poster":"assets/movie-serpico-1973-poster.jpg","backdrop":"assets/movie-serpico-1973-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-10T21:45:02.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":9040,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":93,"rtCriticsLabel":"Certified Fresh","rtAudience":88,"rtAudienceLabel":"Upright","imdb":7.7,"imdbVotes":149750,"tmdb":7.525,"tmdbVotes":2323}},{"id":"movie-shaft-2000","title":"Shaft","year":2000,"type":"movie","runtimeSeconds":5960,"seasonCount":null,"communityRating":6.026,"criticRating":67,"genres":["Action","Adventure","Crime"],"overview":"New York police detective John Shaft arrests Walter Wade Jr. for a racially motivated slaying. But the only eyewitness disappears, and Wade jumps bail for Switzerland. Two years later Wade returns to face trial,\u2026","poster":"assets/movie-shaft-2000-poster.jpg","backdrop":"assets/movie-shaft-2000-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-10T21:30:40.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":479,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":68,"rtCriticsLabel":"Fresh","rtAudience":40,"rtAudienceLabel":"Spilled","imdb":6,"imdbVotes":86257,"tmdb":6.024,"tmdbVotes":1531}},{"id":"movie-a-silent-voice-the-movie-2016","title":"A Silent Voice: The Movie","year":2016,"type":"movie","runtimeSeconds":7804,"seasonCount":null,"communityRating":8.398,"criticRating":null,"genres":["Animation","Drama","Romance"],"overview":"Shouya Ishida starts bullying the new girl in class, Shouko Nishimiya, because she is deaf. But as the teasing continues, the rest of the class starts to turn on Shouya for his lack of compassion. When they leave\u2026","poster":"assets/movie-a-silent-voice-the-movie-2016-poster.jpg","backdrop":"assets/movie-a-silent-voice-the-movie-2016-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T17:39:46.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":378064,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":95,"rtCriticsLabel":"Fresh","rtAudience":94,"rtAudienceLabel":"Upright","imdb":8.2,"imdbVotes":151926,"tmdb":8.396,"tmdbVotes":4764}},{"id":"movie-sinbad-legend-of-the-seven-seas-2003","title":"Sinbad: Legend of the Seven Seas","year":2003,"type":"movie","runtimeSeconds":5143,"seasonCount":null,"communityRating":7.067,"criticRating":44,"genres":["Action","Adventure","Animation"],"overview":"The sailor of legend is framed by the goddess Eris for the theft of the Book of Peace, and must travel to her realm at the end of the world to retrieve it and save the life of his childhood friend Prince Proteus.","poster":"assets/movie-sinbad-legend-of-the-seven-seas-2003-poster.jpg","backdrop":"assets/movie-sinbad-legend-of-the-seven-seas-2003-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:26:25.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":14411,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":46,"rtCriticsLabel":"Rotten","rtAudience":57,"rtAudienceLabel":"Spilled","imdb":6.8,"imdbVotes":65298,"tmdb":7.071,"tmdbVotes":2323}},{"id":"movie-sleeping-with-other-people-2015","title":"Sleeping with Other People","year":2015,"type":"movie","runtimeSeconds":6076,"seasonCount":null,"communityRating":6.274,"criticRating":64,"genres":["Comedy","Romance"],"overview":"Can two serial cheaters get a second chance at love? After a one-night stand in college, New Yorkers Lainey and Jake meet by chance twelve years later and discover they each have the same problem: because of their\u2026","poster":"assets/movie-sleeping-with-other-people-2015-poster.jpg","backdrop":"assets/movie-sleeping-with-other-people-2015-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:27:42.0000000Z","lastPlayedAt":"2026-07-17T17:50:44.0000000Z","availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":288036,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":64,"rtCriticsLabel":"Fresh","rtAudience":56,"rtAudienceLabel":"Spilled","imdb":6.5,"imdbVotes":52275,"tmdb":6.275,"tmdbVotes":1020}},{"id":"movie-snowpiercer-2013","title":"Snowpiercer","year":2013,"type":"movie","runtimeSeconds":7573,"seasonCount":null,"communityRating":6.909,"criticRating":94,"genres":["Action","Science Fiction","Drama"],"overview":"In a future where a failed global-warming experiment kills off most life on the planet, a class system evolves aboard the Snowpiercer; a train that travels around the globe via a perpetual-motion engine.","poster":"assets/movie-snowpiercer-2013-poster.jpg","backdrop":"assets/movie-snowpiercer-2013-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:27:07.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":110415,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":94,"rtCriticsLabel":"Certified Fresh","rtAudience":72,"rtAudienceLabel":"Upright","imdb":7.1,"imdbVotes":426976,"tmdb":6.9,"tmdbVotes":10807}},{"id":"movie-spider-man-brand-new-day-2026","title":"Spider-Man: Brand New Day","year":2026,"type":"movie","runtimeSeconds":8701,"seasonCount":null,"communityRating":8.374,"criticRating":90,"genres":["Science Fiction","Action","Adventure"],"overview":"Fighting crime full-time as Spider-Man in a world that doesn't remember him\u2014and the pressure of seeing his old friends move on without him\u2014sparks a change in Peter Parker he may not have the power to control. But\u2026","poster":"assets/movie-spider-man-brand-new-day-2026-poster.jpg","backdrop":"assets/movie-spider-man-brand-new-day-2026-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-10T14:14:27.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":969681,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":90,"rtCriticsLabel":"Certified Fresh","rtAudience":97,"rtAudienceLabel":"Upright","imdb":7.9,"imdbVotes":366886,"tmdb":8.5,"tmdbVotes":6537}},{"id":"movie-spider-man-far-from-home-2019","title":"Spider-Man: Far From Home","year":2019,"type":"movie","runtimeSeconds":7762,"seasonCount":null,"communityRating":7.389,"criticRating":91,"genres":["Action","Adventure","Science Fiction"],"overview":"Peter Parker and his friends go on a summer trip to Europe. However, they will hardly be able to rest - Peter will have to agree to help Nick Fury uncover the mystery of creatures that cause natural disasters and\u2026","poster":"assets/movie-spider-man-far-from-home-2019-poster.jpg","backdrop":"assets/movie-spider-man-far-from-home-2019-backdrop.jpg","played":true,"playCount":1,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-10T14:25:47.0000000Z","lastPlayedAt":"2026-10-10T17:50:35.6193119Z","availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":429617,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":91,"rtCriticsLabel":"Certified Fresh","rtAudience":95,"rtAudienceLabel":"Upright","imdb":7.3,"imdbVotes":682887,"tmdb":7.387,"tmdbVotes":17847}},{"id":"movie-spider-man-homecoming-2017","title":"Spider-Man: Homecoming","year":2017,"type":"movie","runtimeSeconds":8008,"seasonCount":null,"communityRating":7.333,"criticRating":92,"genres":["Action","Adventure","Science Fiction"],"overview":"Following the events of Captain America: Civil War, Peter Parker, with the help of his mentor Tony Stark, tries to balance his life as an ordinary high school student in Queens, New York City, with fighting crime as\u2026","poster":"assets/movie-spider-man-homecoming-2017-poster.jpg","backdrop":"assets/movie-spider-man-homecoming-2017-backdrop.jpg","played":true,"playCount":1,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-10T14:33:13.0000000Z","lastPlayedAt":"2026-10-10T20:31:23.4444213Z","availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":315635,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":92,"rtCriticsLabel":"Certified Fresh","rtAudience":87,"rtAudienceLabel":"Upright","imdb":7.4,"imdbVotes":840974,"tmdb":7.332,"tmdbVotes":24183}},{"id":"movie-spider-man-no-way-home-2021","title":"Spider-Man: No Way Home","year":2021,"type":"movie","runtimeSeconds":8890,"seasonCount":null,"communityRating":7.947,"criticRating":93,"genres":["Action","Adventure","Science Fiction"],"overview":"Peter Parker is unmasked and no longer able to separate his normal life from the high-stakes of being a super-hero. When he asks for help from Doctor Strange the stakes become even more dangerous, forcing him to\u2026","poster":"assets/movie-spider-man-no-way-home-2021-poster.jpg","backdrop":"assets/movie-spider-man-no-way-home-2021-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-10T14:21:05.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":634649,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":93,"rtCriticsLabel":"Certified Fresh","rtAudience":97,"rtAudienceLabel":"Upright","imdb":8.1,"imdbVotes":1082660,"tmdb":7.947,"tmdbVotes":23505}},{"id":"movie-spirited-away-2001","title":"Spirited Away","year":2001,"type":"movie","runtimeSeconds":7472,"seasonCount":null,"communityRating":8.535,"criticRating":96,"genres":["Animation","Family","Fantasy"],"overview":"A young girl, Chihiro, becomes trapped in a strange new world of spirits. When her parents undergo a mysterious transformation, she must call upon the courage she never knew she had to free her family.","poster":"assets/movie-spirited-away-2001-poster.jpg","backdrop":"assets/movie-spirited-away-2001-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:22:42.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":129,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":96,"rtCriticsLabel":"Certified Fresh","rtAudience":99,"rtAudienceLabel":"Upright","imdb":8.6,"imdbVotes":987658,"tmdb":8.536,"tmdbVotes":19176}},{"id":"movie-the-substance-2024","title":"The Substance","year":2024,"type":"movie","runtimeSeconds":8531,"seasonCount":null,"communityRating":7.135,"criticRating":89,"genres":["Horror","Science Fiction"],"overview":"A fading celebrity decides to use a black market drug, a cell-replicating substance that temporarily creates a younger, better version of herself.","poster":"assets/movie-the-substance-2024-poster.jpg","backdrop":"assets/movie-the-substance-2024-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:30:22.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":933260,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":89,"rtCriticsLabel":"Certified Fresh","rtAudience":76,"rtAudienceLabel":"Upright","imdb":7.2,"imdbVotes":466542,"tmdb":7.13,"tmdbVotes":6746}},{"id":"movie-the-tale-of-the-princess-kaguya-2013","title":"The Tale of The Princess Kaguya","year":2013,"type":"movie","runtimeSeconds":8218,"seasonCount":null,"communityRating":8.1,"criticRating":100,"genres":["Animation","Drama","Fantasy"],"overview":"Found inside a shining stalk of bamboo by an old bamboo cutter and his wife, a tiny girl grows rapidly into an exquisite young lady. The mysterious young princess enthrals all who encounter her. But, ultimately, she\u2026","poster":"assets/movie-the-tale-of-the-princess-kaguya-2013-poster.jpg","backdrop":"assets/movie-the-tale-of-the-princess-kaguya-2013-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-07T13:40:15.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":149871,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Certified Fresh","rtAudience":90,"rtAudienceLabel":"Upright","imdb":8,"imdbVotes":63574,"tmdb":8.083,"tmdbVotes":2079}},{"id":"movie-taxi-driver-1976","title":"Taxi Driver","year":1976,"type":"movie","runtimeSeconds":6831,"seasonCount":null,"communityRating":8.121,"criticRating":89,"genres":["Crime","Drama"],"overview":"Suffering from insomnia, disturbed loner Travis Bickle takes a job as a New York City cabbie, haunting the streets nightly, growing increasingly detached from reality as he dreams of cleaning up the filthy city.","poster":"assets/movie-taxi-driver-1976-poster.jpg","backdrop":"assets/movie-taxi-driver-1976-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:23:04.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":103,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":89,"rtCriticsLabel":"Certified Fresh","rtAudience":93,"rtAudienceLabel":"Upright","imdb":8.2,"imdbVotes":1046700,"tmdb":8.116,"tmdbVotes":13973}},{"id":"movie-triangle-of-sadness-2022","title":"Triangle of Sadness","year":2022,"type":"movie","runtimeSeconds":8833,"seasonCount":null,"communityRating":7.005,"criticRating":71,"genres":["Comedy","Drama"],"overview":"A celebrity model couple are invited on a luxury cruise for the uber-rich, helmed by an unhinged, alcoholic captain. What first appears Instagrammable ends catastrophically, leaving the survivors stranded on a desert\u2026","poster":"assets/movie-triangle-of-sadness-2022-poster.jpg","backdrop":"assets/movie-triangle-of-sadness-2022-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:29:00.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":497828,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":72,"rtCriticsLabel":"Fresh","rtAudience":80,"rtAudienceLabel":"Upright","imdb":7.2,"imdbVotes":221069,"tmdb":7,"tmdbVotes":3104}},{"id":"movie-tsotsi-2005","title":"Tsotsi","year":2005,"type":"movie","runtimeSeconds":5663,"seasonCount":null,"communityRating":6.937,"criticRating":82,"genres":["Crime","Drama"],"overview":"A young South African boy from the Johannesburg ghetto named Tsotsi, meaning Gangster, leaves home as a child to get away from his helpless parents. Now a teenage thug, Tsotsi finds a baby in the back seat of a car\u2026","poster":"assets/movie-tsotsi-2005-poster.jpg","backdrop":"assets/movie-tsotsi-2005-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:24:58.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":868,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":82,"rtCriticsLabel":"Certified Fresh","rtAudience":86,"rtAudienceLabel":"Upright","imdb":7.2,"imdbVotes":32526,"tmdb":6.941,"tmdbVotes":372}},{"id":"movie-unknown-number-the-high-school-catfish-2025","title":"Unknown Number: The High School Catfish","year":2025,"type":"movie","runtimeSeconds":5691,"seasonCount":null,"communityRating":6.746,"criticRating":85,"genres":["Documentary"],"overview":"Vulgar, taunting texts blow up the phones of a teen and her boyfriend. Who's sending them \u2014 and why? This twisty documentary reveals the shocking answer.","poster":"assets/movie-unknown-number-the-high-school-catfish-2025-poster.jpg","backdrop":"assets/movie-unknown-number-the-high-school-catfish-2025-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:32:10.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":1517772,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":85,"rtCriticsLabel":"Fresh","rtAudience":69,"rtAudienceLabel":"Upright","imdb":6.7,"imdbVotes":23039,"tmdb":6.737,"tmdbVotes":257}},{"id":"movie-the-uprising-2026","title":"The Uprising","year":2026,"type":"movie","runtimeSeconds":7684,"seasonCount":null,"communityRating":7.846,"criticRating":55,"genres":["Action","Drama","History"],"overview":"As war and plague devastate 14th-century England, a humble peasant ignites a rebellion, uniting an army of commoners to defy the King\u2019s might in a desperate fight for justice and survival.","poster":"assets/movie-the-uprising-2026-poster.jpg","backdrop":"assets/movie-the-uprising-2026-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-11-02T16:37:03.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":977942,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":57,"rtCriticsLabel":"Rotten","rtAudience":65,"rtAudienceLabel":"Upright","imdb":6.2,"imdbVotes":6622,"tmdb":7.8,"tmdbVotes":404}},{"id":"movie-vice-2018","title":"Vice","year":2018,"type":"movie","runtimeSeconds":7948,"seasonCount":null,"communityRating":7.013,"criticRating":64,"genres":["Drama","Comedy","History"],"overview":"George W. Bush picks Dick Cheney, the CEO of Halliburton Co., to be his Republican running mate in the 2000 presidential election. No stranger to politics, Cheney's impressive r\u00e9sum\u00e9 includes stints as White House\u2026","poster":"assets/movie-vice-2018-poster.jpg","backdrop":"assets/movie-vice-2018-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:28:30.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":429197,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":64,"rtCriticsLabel":"Fresh","rtAudience":61,"rtAudienceLabel":"Upright","imdb":7.2,"imdbVotes":177299,"tmdb":7.014,"tmdbVotes":3723}},{"id":"movie-warriors-of-the-wind-1984","title":"Warriors of the Wind","year":1984,"type":"movie","runtimeSeconds":7022,"seasonCount":null,"communityRating":7.941,"criticRating":87,"genres":["Adventure","Animation","Fantasy"],"overview":"After a global war, the seaside kingdom known as the Valley of the Wind remains one of the last strongholds on Earth untouched by a poisonous jungle and the powerful insects that guard it. Led by the courageous\u2026","poster":"assets/movie-warriors-of-the-wind-1984-poster.jpg","backdrop":"assets/movie-warriors-of-the-wind-1984-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:22:20.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":81,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":87,"rtCriticsLabel":"Fresh","rtAudience":91,"rtAudienceLabel":"Upright","imdb":8,"imdbVotes":200154,"tmdb":7.94,"tmdbVotes":4260}},{"id":"movie-we-bury-the-dead-2026","title":"We Bury the Dead","year":2026,"type":"movie","runtimeSeconds":5693,"seasonCount":null,"communityRating":6.153,"criticRating":87,"genres":["Horror","Thriller"],"overview":"After a catastrophic military disaster reanimates the dead, Ava searches for her missing husband amidst an increasingly hostile world.","poster":"assets/movie-we-bury-the-dead-2026-poster.jpg","backdrop":"assets/movie-we-bury-the-dead-2026-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-08-26T05:36:00.4272328Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":1198984,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":87,"rtCriticsLabel":"Certified Fresh","rtAudience":45,"rtAudienceLabel":"Spilled","imdb":5.6,"imdbVotes":20693,"tmdb":6.137,"tmdbVotes":433}},{"id":"movie-white-hot-the-rise-fall-of-abercrombie-fitch-2022","title":"White Hot: The Rise & Fall of Abercrombie & Fitch","year":2022,"type":"movie","runtimeSeconds":5187,"seasonCount":null,"communityRating":5.663,"criticRating":66,"genres":["Documentary"],"overview":"All the cool kids were wearing it. This documentary explores A&F's pop culture reign in the late '90s and early 2000s and how it thrived on exclusion.","poster":"assets/movie-white-hot-the-rise-fall-of-abercrombie-fitch-2022-poster.jpg","backdrop":"assets/movie-white-hot-the-rise-fall-of-abercrombie-fitch-2022-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:30:34.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":953371,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":66,"rtCriticsLabel":"Fresh","rtAudience":29,"rtAudienceLabel":"Spilled","imdb":5.8,"imdbVotes":5655,"tmdb":5.7,"tmdbVotes":102}},{"id":"movie-the-wild-robot-2024","title":"The Wild Robot","year":2024,"type":"movie","runtimeSeconds":6101,"seasonCount":null,"communityRating":8.308,"criticRating":97,"genres":["Family","Animation","Science Fiction"],"overview":"After a shipwreck, an intelligent robot called Roz is stranded on an uninhabited island. To survive the harsh environment, Roz bonds with the island's animals and cares for an orphaned baby goose.","poster":"assets/movie-the-wild-robot-2024-poster.jpg","backdrop":"assets/movie-the-wild-robot-2024-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:31:49.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":1184918,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":97,"rtCriticsLabel":"Certified Fresh","rtAudience":98,"rtAudienceLabel":"Upright","imdb":8.1,"imdbVotes":241134,"tmdb":8.309,"tmdbVotes":6819}},{"id":"movie-the-wind-rises-2013","title":"The Wind Rises","year":2013,"type":"movie","runtimeSeconds":8031,"seasonCount":null,"communityRating":7.784,"criticRating":88,"genres":["Animation","Drama","History"],"overview":"A lifelong love of flight inspires Japanese aviation engineer Jiro Horikoshi, whose storied career includes the creation of the A-6M World War II fighter plane.","poster":"assets/movie-the-wind-rises-2013-poster.jpg","backdrop":"assets/movie-the-wind-rises-2013-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:24:38.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":149870,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":89,"rtCriticsLabel":"Certified Fresh","rtAudience":85,"rtAudienceLabel":"Upright","imdb":7.8,"imdbVotes":115756,"tmdb":7.783,"tmdbVotes":3536}},{"id":"movie-the-witcher-nightmare-of-the-wolf-2021","title":"The Witcher: Nightmare of the Wolf","year":2021,"type":"movie","runtimeSeconds":5015,"seasonCount":null,"communityRating":7.422,"criticRating":100,"genres":["Animation","Action","Fantasy"],"overview":"Escaping from poverty to become a witcher, Vesemir slays monsters for coin and glory, but when a new menace rises, he must face the demons of his past.","poster":"assets/movie-the-witcher-nightmare-of-the-wolf-2021-poster.jpg","backdrop":"assets/movie-the-witcher-nightmare-of-the-wolf-2021-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-26T04:42:03.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":666243,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":83,"rtAudienceLabel":"Upright","imdb":7.2,"imdbVotes":55759,"tmdb":7.407,"tmdbVotes":1159}},{"id":"movie-the-witcher-sirens-of-the-deep-2025","title":"The Witcher: Sirens of the Deep","year":2025,"type":"movie","runtimeSeconds":5517,"seasonCount":null,"communityRating":6.8,"criticRating":60,"genres":["Animation","Fantasy","Action"],"overview":"When human sailors are attacked by mysterious creatures of the deep, only one person can stop the war between land and sea: the Witcher, Geralt of Rivia.","poster":"assets/movie-the-witcher-sirens-of-the-deep-2025-poster.jpg","backdrop":"assets/movie-the-witcher-sirens-of-the-deep-2025-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-26T05:03:26.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":1203329,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":60,"rtCriticsLabel":"Fresh","rtAudience":37,"rtAudienceLabel":"Spilled","imdb":6.1,"imdbVotes":11799,"tmdb":6.741,"tmdbVotes":303}}],"shows":[{"id":"tv-adults-2025","title":"Adults","year":2025,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":6.495,"criticRating":null,"genres":["Comedy"],"overview":"A group of twenty-somethings in New York trying to be good people, despite being neither \"good\" nor \"people\" yet.","poster":"assets/tv-adults-2025-poster.jpg","backdrop":"assets/tv-adults-2025-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-23T21:01:41.1814765Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":260458,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":88,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.5,"tmdbVotes":102}},{"id":"tv-american-crime-story-2016","title":"American Crime Story","year":2016,"type":"tv","runtimeSeconds":null,"seasonCount":3,"communityRating":7.573,"criticRating":null,"genres":["Crime","Drama"],"overview":"An anthology series centered around some of history's most famous criminal investigations.","poster":"assets/tv-american-crime-story-2016-poster.jpg","backdrop":"assets/tv-american-crime-story-2016-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0490488Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":64513,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":84,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.585,"tmdbVotes":1094}},{"id":"tv-american-primeval-2025","title":"American Primeval","year":2025,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":7.691,"criticRating":null,"genres":["Western","Drama","Action & Adventure"],"overview":"A mother and son fleeing from their past form a found family while confronting a harsh landscape of freedom and cruelty in the American West.","poster":"assets/tv-american-primeval-2025-poster.jpg","backdrop":"assets/tv-american-primeval-2025-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0573221Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":215866,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":71,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.741,"tmdbVotes":538}},{"id":"tv-arrested-development-2003","title":"Arrested Development","year":2003,"type":"tv","runtimeSeconds":null,"seasonCount":5,"communityRating":7.925,"criticRating":null,"genres":["Comedy"],"overview":"The story of a wealthy family that lost everything, and the one son who had no choice but to keep them all together.","poster":"assets/tv-arrested-development-2003-poster.jpg","backdrop":"assets/tv-arrested-development-2003-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0513048Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":4589,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":75,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.906,"tmdbVotes":1793}},{"id":"tv-avatar-the-last-airbender-2005","title":"Avatar: The Last Airbender","year":2005,"type":"tv","runtimeSeconds":1440,"seasonCount":3,"communityRating":8.78,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"In a war-torn world of elemental magic, a young boy reawakens to undertake a dangerous mystic quest to fulfill his destiny as the Avatar, and bring peace to the world.","poster":"assets/tv-avatar-the-last-airbender-2005-poster.jpg","backdrop":"assets/tv-avatar-the-last-airbender-2005-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0504536Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":246,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.787,"tmdbVotes":5215}},{"id":"tv-b-b-vol-liefde-2021","title":"B&B Vol Liefde","year":2021,"type":"tv","runtimeSeconds":3720,"seasonCount":1,"communityRating":7.2,"criticRating":null,"genres":["Reality"],"overview":"B&B Vol Liefde is a heartwarming adventure, full of romance, excitement, and unforgettable moments. Adventurous Dutch B&B owners abroad throw their doors wide open and let their hearts speak, determined to find that\u2026","poster":"assets/tv-b-b-vol-liefde-2021-poster.jpg","backdrop":"assets/tv-b-b-vol-liefde-2021-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-31T22:30:11.129657Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":124428,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.2,"tmdbVotes":10}},{"id":"tv-the-bear-2022","title":"The Bear","year":2022,"type":"tv","runtimeSeconds":null,"seasonCount":5,"communityRating":8.139,"criticRating":null,"genres":["Drama","Comedy"],"overview":"Carmy, a young fine-dining chef, comes home to Chicago to run his family sandwich shop. As he fights to transform the shop and himself, he works alongside a rough-around-the-edges crew that ultimately reveal\u2026","poster":"assets/tv-the-bear-2022-poster.jpg","backdrop":"assets/tv-the-bear-2022-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0467371Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":136315,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":93,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.158,"tmdbVotes":2025}},{"id":"tv-blue-planet-ii-2017","title":"Blue Planet II","year":2017,"type":"tv","runtimeSeconds":3600,"seasonCount":1,"communityRating":8.64,"criticRating":null,"genres":["Documentary","Family"],"overview":"There is nowhere more powerful and unforgiving yet more beautiful and compelling than the ocean. Join us and explore the greatest yet least known parts of our planet.","poster":"assets/tv-blue-planet-ii-2017-poster.jpg","backdrop":"assets/tv-blue-planet-ii-2017-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0634849Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":74313,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":97,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.6,"tmdbVotes":380}},{"id":"tv-breeders-2020","title":"Breeders","year":2020,"type":"tv","runtimeSeconds":1500,"seasonCount":4,"communityRating":6.8,"criticRating":null,"genres":["Comedy"],"overview":"Exposing the parental-paradox that it is possible, in the very same moment, to love your child to the horizon of the universe, while being apoplectically angry enough to want to send them there.","poster":"assets/tv-breeders-2020-poster.jpg","backdrop":"assets/tv-breeders-2020-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-28T18:54:21.8885435Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":93290,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":92,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.8,"tmdbVotes":104}},{"id":"tv-chernobyl-2019","title":"Chernobyl","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":8.718,"criticRating":null,"genres":["Drama"],"overview":"The true story of one of the worst man-made catastrophes in history: the catastrophic nuclear accident at Chernobyl. A tale of the brave men and women who sacrificed to save Europe from unimaginable disaster.","poster":"assets/tv-chernobyl-2019-poster.jpg","backdrop":"assets/tv-chernobyl-2019-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0469903Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":87108,"artwork":{"posterKind":"poster","backdropKind":"center_crop"},"ratings":{"rtCritics":95,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.731,"tmdbVotes":8496}},{"id":"tv-community-2009","title":"Community","year":2009,"type":"tv","runtimeSeconds":null,"seasonCount":6,"communityRating":7.997,"criticRating":null,"genres":["Comedy"],"overview":"Follow the lives of a group of students at what is possibly the world\u2019s worst community college in the fictional locale of Greendale, Colorado.","poster":"assets/tv-community-2009-poster.jpg","backdrop":"assets/tv-community-2009-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0531416Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":18347,"artwork":{"posterKind":"center_crop","backdropKind":"backdrop"},"ratings":{"rtCritics":88,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.994,"tmdbVotes":2226}},{"id":"tv-dead-end-job-2026","title":"Dead-End Job","year":2026,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":7.7,"criticRating":null,"genres":["Mystery"],"overview":"Drowning in debt, a young man takes lucrative part-time jobs from a mysterious agency \u2014 only to find his hustle for more money turning nightmarish.","poster":"assets/tv-dead-end-job-2026-poster.jpg","backdrop":"assets/tv-dead-end-job-2026-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-11-04T18:58:01.8352857Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":289517,"artwork":{"posterKind":"center_crop","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.7,"tmdbVotes":38}},{"id":"tv-dopesick-2021","title":"Dopesick","year":2021,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":8.015,"criticRating":null,"genres":["Crime","Drama"],"overview":"The story of how one company triggered the worst drug epidemic in American history. Look into the epicenter of America's struggle with opioid addiction, from a distressed Virginia mining community, to the hallways of\u2026","poster":"assets/tv-dopesick-2021-poster.jpg","backdrop":"assets/tv-dopesick-2021-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0580168Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":110695,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":89,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.035,"tmdbVotes":565}},{"id":"tv-dune-prophecy-2024","title":"Dune: Prophecy","year":2024,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":7.213,"criticRating":null,"genres":["Sci-Fi & Fantasy","Drama","Action & Adventure"],"overview":"Ten thousand years before the ascension of Paul Atreides, sisters Valya and Tula Harkonnen establish the fabled sect and female order that would become known as the Bene Gesserit to control the future of humankind.","poster":"assets/tv-dune-prophecy-2024-poster.jpg","backdrop":"assets/tv-dune-prophecy-2024-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-11-04T18:23:01.2908568Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":90228,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":64,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.213,"tmdbVotes":677}},{"id":"tv-east-of-eden-2026","title":"East of Eden","year":2026,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":7.931,"criticRating":null,"genres":["Drama","Crime"],"overview":"In the early 1900s, a fiercely independent woman drives a rift between two brothers, igniting a saga that unfolds across two generations.","poster":"assets/tv-east-of-eden-2026-poster.jpg","backdrop":"assets/tv-east-of-eden-2026-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-23T18:07:11.3965096Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":258165,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":88,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.982,"tmdbVotes":139}},{"id":"tv-fallout-2024","title":"Fallout","year":2024,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":8.124,"criticRating":null,"genres":["Action & Adventure","Sci-Fi & Fantasy","Drama"],"overview":"The story of haves and have-nots in a world in which there's almost nothing left to have. 200 years after the apocalypse, the gentle denizens of luxury fallout shelters are forced to return to the irradiated\u2026","poster":"assets/tv-fallout-2024-poster.jpg","backdrop":"assets/tv-fallout-2024-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0669262Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":106379,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":94,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.106,"tmdbVotes":3233}},{"id":"tv-fawlty-towers-1975","title":"Fawlty Towers","year":1975,"type":"tv","runtimeSeconds":1800,"seasonCount":2,"communityRating":8.295,"criticRating":null,"genres":["Comedy"],"overview":"Owner Basil Fawlty, his wife Sybil, a chambermaid Polly, and Spanish waiter Manuel attempt to run their hotel amidst farcical situations and an array of demanding guests.","poster":"assets/tv-fawlty-towers-1975-poster.jpg","backdrop":"assets/tv-fawlty-towers-1975-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-19T23:26:39.7658344Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":2207,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.296,"tmdbVotes":867}},{"id":"tv-the-final-problem-2026","title":"The Final Problem","year":2026,"type":"tv","runtimeSeconds":3420,"seasonCount":1,"communityRating":7.041,"criticRating":null,"genres":["Crime","Mystery"],"overview":"In the spring of 1959, a retired actor, who previously played Sherlock Holmes, must investigate a murder at a small hotel on a tiny island near Mallorca.","poster":"assets/tv-the-final-problem-2026-poster.jpg","backdrop":"assets/tv-the-final-problem-2026-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-11-04T19:16:12.4822791Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":290720,"artwork":{"posterKind":"center_crop","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.041,"tmdbVotes":49}},{"id":"tv-the-four-seasons-2025","title":"The Four Seasons","year":2025,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":6.879,"criticRating":null,"genres":["Comedy"],"overview":"The decades-long friendship between three married couples is tested when one divorces, complicating their tradition of quarterly weekend getaways.","poster":"assets/tv-the-four-seasons-2025-poster.jpg","backdrop":"assets/tv-the-four-seasons-2025-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-28T18:36:42.5326384Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":243316,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":81,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.892,"tmdbVotes":204}},{"id":"tv-the-get-down-2016","title":"The Get Down","year":2016,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":7.3,"criticRating":null,"genres":["Drama"],"overview":"In 1977 New York City, the talented and soulful youth of the South Bronx chase dreams and breakneck beats to transform music history.","poster":"assets/tv-the-get-down-2016-poster.jpg","backdrop":"assets/tv-the-get-down-2016-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0497737Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":65345,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":81,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.3,"tmdbVotes":196}},{"id":"tv-how-to-change-your-mind-2022","title":"How to Change Your Mind","year":2022,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":7.76,"criticRating":null,"genres":["Documentary","Mystery"],"overview":"Author Michael Pollan leads the way in this docuseries exploring the history and uses of psychedelics, including LSD, psilocybin, MDMA and mescaline.","poster":"assets/tv-how-to-change-your-mind-2022-poster.jpg","backdrop":"assets/tv-how-to-change-your-mind-2022-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0601399Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":204304,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.8,"tmdbVotes":53}},{"id":"tv-interrogation-2020","title":"Interrogation","year":2020,"type":"tv","runtimeSeconds":2700,"seasonCount":1,"communityRating":6.788,"criticRating":null,"genres":["Drama","Crime"],"overview":"Based on a true story that spanned more than 30 years in which a young man was charged and convicted of brutally murdering his mother. Each episode is structured around an interrogation taken directly from the real\u2026","poster":"assets/tv-interrogation-2020-poster.jpg","backdrop":"assets/tv-interrogation-2020-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-26T05:52:06.1068207Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":96488,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":57,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.9,"tmdbVotes":54}},{"id":"tv-it-s-always-sunny-in-philadelphia-2005","title":"It's Always Sunny in Philadelphia","year":2005,"type":"tv","runtimeSeconds":null,"seasonCount":18,"communityRating":8.2,"criticRating":null,"genres":["Comedy"],"overview":"Four egocentric friends run a neighborhood Irish pub in Philadelphia and try to find their way through the adult world of work and relationships. Unfortunately, their warped views and precarious judgments often lead\u2026","poster":"assets/tv-it-s-always-sunny-in-philadelphia-2005-poster.jpg","backdrop":"assets/tv-it-s-always-sunny-in-philadelphia-2005-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0485774Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":2710,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":94,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.253,"tmdbVotes":1457}},{"id":"tv-a-knight-of-the-seven-kingdoms-2026","title":"A Knight of the Seven Kingdoms","year":2026,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":8.431,"criticRating":null,"genres":["Drama","Sci-Fi & Fantasy","Action & Adventure"],"overview":"A century before the events of Game of Thrones, two unlikely heroes wandered Westeros: a young, naive but courageous knight, Ser Duncan the Tall, and his diminutive squire, Egg. Set in an age when the Targaryen line\u2026","poster":"assets/tv-a-knight-of-the-seven-kingdoms-2026-poster.jpg","backdrop":"assets/tv-a-knight-of-the-seven-kingdoms-2026-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0493344Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":224372,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":94,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.4,"tmdbVotes":1266}},{"id":"tv-landman-2024","title":"Landman","year":2024,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":8.194,"criticRating":null,"genres":["Drama"],"overview":"Set in the proverbial boomtowns of West-Texas and a modern-day tale of fortune-seeking in the world of oil rigs, the series is an upstairs/downstairs story of roughnecks and wildcat billionaires that are fueling a\u2026","poster":"assets/tv-landman-2024-poster.jpg","backdrop":"assets/tv-landman-2024-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-22T21:38:18.0973875Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":157741,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":80,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.209,"tmdbVotes":668}},{"id":"tv-the-last-of-us-2023","title":"The Last of Us","year":2023,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":8.419,"criticRating":null,"genres":["Drama"],"overview":"Twenty years after modern civilization has been destroyed, Joel, a hardened survivor, is hired to smuggle Ellie, a 14-year-old girl, out of an oppressive quarantine zone. What starts as a small job soon becomes a\u2026","poster":"assets/tv-the-last-of-us-2023-poster.jpg","backdrop":"assets/tv-the-last-of-us-2023-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0640955Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":100088,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":94,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.4,"tmdbVotes":7485}},{"id":"tv-last-samurai-standing-2025","title":"Last Samurai Standing","year":2025,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":7.805,"criticRating":null,"genres":["Action & Adventure","Drama"],"overview":"In the early Meiji era, Shujiro, once known as an undefeated samurai, decides to participate in a deadly survival game to save his family and villagers.","poster":"assets/tv-last-samurai-standing-2025-poster.jpg","backdrop":"assets/tv-last-samurai-standing-2025-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0622526Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":252193,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.812,"tmdbVotes":271}},{"id":"tv-lord-of-the-flies-2026","title":"Lord of the Flies","year":2026,"type":"tv","runtimeSeconds":3480,"seasonCount":1,"communityRating":7.571,"criticRating":null,"genres":["Drama","Action & Adventure"],"overview":"After a plane crash, a group of schoolboys find themselves stranded on a tropical island without adults. Ralph is elected leader and, with the help of the intelligent Piggy, strives to maintain order and\u2026","poster":"assets/tv-lord-of-the-flies-2026-poster.jpg","backdrop":"assets/tv-lord-of-the-flies-2026-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0645648Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":270572,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":91,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.58,"tmdbVotes":138}},{"id":"tv-the-lord-of-the-rings-the-rings-of-power-2022","title":"The Lord of the Rings: The Rings of Power","year":2022,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":7.233,"criticRating":null,"genres":["Action & Adventure","Sci-Fi & Fantasy","Drama"],"overview":"Beginning in a time of relative peace, we follow an ensemble cast of characters as they confront the re-emergence of evil to Middle-earth. From the darkest depths of the Misty Mountains, to the majestic forests of\u2026","poster":"assets/tv-the-lord-of-the-rings-the-rings-of-power-2022-poster.jpg","backdrop":"assets/tv-the-lord-of-the-rings-the-rings-of-power-2022-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0618904Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":84773,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":84,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.211,"tmdbVotes":4003}},{"id":"tv-love-death-robots-2019","title":"Love, Death & Robots","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":4,"communityRating":8.21,"criticRating":null,"genres":["Animation","Sci-Fi & Fantasy"],"overview":"Terrifying creatures, wicked surprises and dark comedy converge in this NSFW anthology of animated stories presented by Tim Miller and David Fincher.","poster":"assets/tv-love-death-robots-2019-poster.jpg","backdrop":"assets/tv-love-death-robots-2019-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0460964Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":86831,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":89,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.203,"tmdbVotes":4238}},{"id":"tv-maniac-2018","title":"Maniac","year":2018,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":7.338,"criticRating":null,"genres":["Comedy","Drama","Sci-Fi & Fantasy"],"overview":"Two strangers are drawn to a mysterious pharmaceutical trial that will, they're assured, with no complications or side-effects whatsoever, solve all of their problems, permanently. Things do not go as planned.","poster":"assets/tv-maniac-2018-poster.jpg","backdrop":"assets/tv-maniac-2018-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-20T19:42:30.955548Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":73411,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":84,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.323,"tmdbVotes":1073}},{"id":"tv-mussolini-son-of-the-century-2024","title":"Mussolini: Son of the Century","year":2024,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":8.135,"criticRating":null,"genres":["Drama","War & Politics"],"overview":"The rise of Benito Mussolini and the birth of fascism in Italy, chronicling a country\u2019s surrender to dictatorship and the relentless ascent of a man who rose from his ashes time and again.","poster":"assets/tv-mussolini-son-of-the-century-2024-poster.jpg","backdrop":"assets/tv-mussolini-son-of-the-century-2024-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0586588Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":212333,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":96,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.1,"tmdbVotes":179}},{"id":"tv-the-night-manager-2016","title":"The Night Manager","year":2016,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":7.74,"criticRating":null,"genres":["Drama","Mystery","Crime"],"overview":"Former British soldier Jonathan Pine navigates the shadowy recesses of Whitehall and Washington where an unholy alliance operates between the intelligence community and the secret arms trade. To infiltrate the inner\u2026","poster":"assets/tv-the-night-manager-2016-poster.jpg","backdrop":"assets/tv-the-night-manager-2016-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0663672Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":61859,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":88,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.7,"tmdbVotes":1422}},{"id":"tv-one-piece-2023","title":"ONE PIECE","year":2023,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":8.118,"criticRating":null,"genres":["Action & Adventure","Sci-Fi & Fantasy"],"overview":"With his straw hat and ragtag crew, young pirate Monkey D. Luffy goes on an epic voyage for treasure.","poster":"assets/tv-one-piece-2023-poster.jpg","backdrop":"assets/tv-one-piece-2023-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0439378Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":111110,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":93,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.104,"tmdbVotes":1988}},{"id":"tv-only-murders-in-the-building-2021","title":"Only Murders in the Building","year":2021,"type":"tv","runtimeSeconds":null,"seasonCount":5,"communityRating":8.438,"criticRating":null,"genres":["Comedy","Mystery","Crime"],"overview":"Three strangers share an obsession with true crime and suddenly find themselves wrapped up in one.","poster":"assets/tv-only-murders-in-the-building-2021-poster.jpg","backdrop":"assets/tv-only-murders-in-the-building-2021-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0594614Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":107113,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":95,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.398,"tmdbVotes":2333}},{"id":"tv-over-the-garden-wall-2014","title":"Over the Garden Wall","year":2014,"type":"tv","runtimeSeconds":720,"seasonCount":1,"communityRating":8.6,"criticRating":null,"genres":["Mystery","Sci-Fi & Fantasy","Animation"],"overview":"Two brothers, Wirt and Greg, find themselves lost in the Unknown; a strange forest adrift in time. With the help of a wise old Woodsman and a foul-tempered bluebird named Beatrice, Wirt and Greg must travel across\u2026","poster":"assets/tv-over-the-garden-wall-2014-poster.jpg","backdrop":"assets/tv-over-the-garden-wall-2014-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0455757Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":61617,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.6,"tmdbVotes":1854}},{"id":"tv-peaky-blinders-2013","title":"Peaky Blinders","year":2013,"type":"tv","runtimeSeconds":null,"seasonCount":6,"communityRating":8.5,"criticRating":null,"genres":["Drama","Crime"],"overview":"A gangster family epic set in 1919 Birmingham, England and centered on a gang who sew razor blades in the peaks of their caps, and their fierce boss Tommy Shelby, who means to move up in the world.","poster":"assets/tv-peaky-blinders-2013-poster.jpg","backdrop":"assets/tv-peaky-blinders-2013-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0539185Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":60574,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":93,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.5,"tmdbVotes":11506}},{"id":"tv-the-pitt-2025","title":"The Pitt","year":2025,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":8.729,"criticRating":null,"genres":["Drama"],"overview":"The staff of Pittsburgh's Trauma Medical Center work around the clock to save lives in an overcrowded and underfunded emergency department.","poster":"assets/tv-the-pitt-2025-poster.jpg","backdrop":"assets/tv-the-pitt-2025-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0582942Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":250307,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":96,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.731,"tmdbVotes":1046}},{"id":"tv-pluribus-2025","title":"Pluribus","year":2025,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":7.936,"criticRating":null,"genres":["Drama","Sci-Fi & Fantasy"],"overview":"The most miserable person on Earth must save the world from happiness.","poster":"assets/tv-pluribus-2025-poster.jpg","backdrop":"assets/tv-pluribus-2025-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0674462Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":225171,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":99,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.921,"tmdbVotes":1191}},{"id":"tv-ripley-2024","title":"RIPLEY","year":2024,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":7.911,"criticRating":null,"genres":["Drama"],"overview":"A grifter in 1960s New York is hired to convince a wealthy man's son to return home from Italy and begins a life of deceit, fraud and murder.","poster":"assets/tv-ripley-2024-poster.jpg","backdrop":"assets/tv-ripley-2024-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0658942Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":94028,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":86,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.909,"tmdbVotes":453}},{"id":"tv-say-nothing-2024","title":"Say Nothing","year":2024,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":7.462,"criticRating":null,"genres":["Drama","Crime"],"overview":"Through the eyes of various Irish Republican Army (IRA) members, explore the extremes some people will go to in the name of their beliefs, the way a deeply divided society can suddenly tip over into armed conflict,\u2026","poster":"assets/tv-say-nothing-2024-poster.jpg","backdrop":"assets/tv-say-nothing-2024-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0499752Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":245256,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":94,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.475,"tmdbVotes":122}},{"id":"tv-severance-2022","title":"Severance","year":2022,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":8.396,"criticRating":null,"genres":["Drama","Mystery","Sci-Fi & Fantasy"],"overview":"Mark leads a team of office workers whose memories have been surgically divided between their work and personal lives. When a mysterious colleague appears outside of work, it begins a journey to discover the truth\u2026","poster":"assets/tv-severance-2022-poster.jpg","backdrop":"assets/tv-severance-2022-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0598478Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":95396,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":95,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.389,"tmdbVotes":3095}},{"id":"tv-six-feet-under-2001","title":"Six Feet Under","year":2001,"type":"tv","runtimeSeconds":null,"seasonCount":5,"communityRating":8.115,"criticRating":null,"genres":["Drama"],"overview":"When death is your business, what is your life? For the Fisher family, the world outside of their family-owned funeral home continues to be at least as challenging as\u2014and far less predictable than\u2014the one inside.","poster":"assets/tv-six-feet-under-2001-poster.jpg","backdrop":"assets/tv-six-feet-under-2001-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-26T04:04:05.108787Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":1274,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":81,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.1,"tmdbVotes":1192}},{"id":"tv-undercover-2019","title":"Undercover","year":2019,"type":"tv","runtimeSeconds":3000,"seasonCount":3,"communityRating":7.5,"criticRating":null,"genres":["Crime","Drama"],"overview":"Undercover agents infiltrate a drug kingpin's operation by posing as a couple at the campground where he spends his weekends. Inspired by real events.","poster":"assets/tv-undercover-2019-poster.jpg","backdrop":"assets/tv-undercover-2019-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0570153Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":86942,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.5,"tmdbVotes":186}},{"id":"tv-upload-2020","title":"Upload","year":2020,"type":"tv","runtimeSeconds":null,"seasonCount":4,"communityRating":7.781,"criticRating":null,"genres":["Comedy","Sci-Fi & Fantasy","Drama"],"overview":"In 2033, people who are near death can be \u201cuploaded\u201d into virtual reality hotels run by 6 tech firms. Cash-strapped Nora lives in Brooklyn and works customer service for the luxurious \u201cLakeview\u201d digital afterlife.\u2026","poster":"assets/tv-upload-2020-poster.jpg","backdrop":"assets/tv-upload-2020-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0566967Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":86248,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":87,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.757,"tmdbVotes":1511}},{"id":"tv-the-walk-in-2022","title":"The Walk-In","year":2022,"type":"tv","runtimeSeconds":2760,"seasonCount":1,"communityRating":6.9,"criticRating":null,"genres":["Drama","Crime"],"overview":"Forced to flee the UK and go into hiding in the 1990s, when he became a mole from within the BNP, Matthew Collins returned to Britain to make a new life for himself, working with young white men in the fight against\u2026","poster":"assets/tv-the-walk-in-2022-poster.jpg","backdrop":"assets/tv-the-walk-in-2022-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0654569Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":210664,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":80,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7,"tmdbVotes":50}},{"id":"tv-the-white-lotus-2021","title":"The White Lotus","year":2021,"type":"tv","runtimeSeconds":null,"seasonCount":3,"communityRating":7.596,"criticRating":null,"genres":["Comedy","Drama","Mystery"],"overview":"Follow the exploits of various guests and employees at an exclusive tropical resort over the span of a week as with each passing day, a darker complexity emerges in these picture-perfect travelers, the hotel\u2019s\u2026","poster":"assets/tv-the-white-lotus-2021-poster.jpg","backdrop":"assets/tv-the-white-lotus-2021-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0546438Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":111803,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":90,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.599,"tmdbVotes":1604}},{"id":"tv-widow-s-bay-2026","title":"Widow's Bay","year":2026,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":8.172,"criticRating":null,"genres":["Drama","Comedy","Mystery"],"overview":"The mayor of a New England town resolves to turn it into the next tourist hot spot, despite local warnings that it's cursed.","poster":"assets/tv-widow-s-bay-2026-poster.jpg","backdrop":"assets/tv-widow-s-bay-2026-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-20T10:27:12.7003979Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":270476,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":98,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8,"tmdbVotes":585}},{"id":"tv-the-witcher-2019","title":"The Witcher","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":4,"communityRating":7.905,"criticRating":null,"genres":["Drama","Action & Adventure"],"overview":"Geralt of Rivia, a mutated monster-hunter for hire, journeys toward his destiny in a turbulent world where people often prove more wicked than beasts.","poster":"assets/tv-the-witcher-2019-poster.jpg","backdrop":"assets/tv-the-witcher-2019-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0552369Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":71912,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":75,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.88,"tmdbVotes":6997}},{"id":"tv-yellowjackets-2021","title":"Yellowjackets","year":2021,"type":"tv","runtimeSeconds":null,"seasonCount":3,"communityRating":7.449,"criticRating":null,"genres":["Drama","Mystery"],"overview":"This equal parts survival epic, psychological horror story and coming-of-age drama tells the saga of a team of wildly talented high school girls soccer players who become the (un)lucky survivors of a plane crash deep\u2026","poster":"assets/tv-yellowjackets-2021-poster.jpg","backdrop":"assets/tv-yellowjackets-2021-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0577612Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":117488,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":92,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.431,"tmdbVotes":1070}}],"anime":[],"resume":[{"id":"episode-episode-1-2025-s1e1","title":"Episode 1","year":2025,"type":"episode","runtimeSeconds":3618,"seasonCount":null,"communityRating":7.357,"criticRating":null,"genres":["Biography","Drama","History"],"overview":"Mussolini had just founded the Fasci di Combattimento when D'Annunzio took Fiume. Mussolini hoped to capitalize on the poet's achievement in the electoral arena.","poster":"assets/episode-episode-1-2025-s1e1-poster.jpg","backdrop":"assets/episode-episode-1-2025-s1e1-backdrop.jpg","played":false,"playCount":1,"resumeSeconds":489.55,"progress":0.1353,"addedAt":"2026-07-17T13:52:48.0000000Z","lastPlayedAt":"2026-11-04T19:01:49.9731435Z","availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","seriesTitle":"Mussolini: Son of the Century","seasonNumber":1,"episodeNumber":1,"artwork":{"posterKind":"center_crop","backdropKind":"backdrop"}}],"nextUp":[{"id":"episode-no-honeymoon-2020-s1e8","title":"No Honeymoon","year":2020,"type":"episode","runtimeSeconds":1499,"seasonCount":null,"communityRating":6.7,"criticRating":null,"genres":["Comedy","Drama"],"overview":"Paul attempts to focus on his upcoming wedding but is constantly thwarted by his family; Ally is distracted by work, Luke is misbehaving at school and Leah (Stella Gonet) doesn\u2019t understand why they are even\u2026","poster":"assets/episode-no-honeymoon-2020-s1e8-poster.jpg","backdrop":"assets/episode-no-honeymoon-2020-s1e8-backdrop.jpg","played":false,"playCount":1,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-28T19:00:50.0000000Z","lastPlayedAt":"2026-11-03T20:57:58.3314947Z","availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","seriesTitle":"Breeders","seasonNumber":1,"episodeNumber":8,"artwork":{"posterKind":"poster","backdropKind":"backdrop"}},{"id":"episode-notapusy-2005-s3e4","title":"Notapusy","year":2005,"type":"episode","runtimeSeconds":1334,"seasonCount":null,"communityRating":8.125,"criticRating":null,"genres":["Comedy"],"overview":"To prove he's a man to Rita, Michael and his nephew Steve Holt compete in the Church And State Fair's annual triathlon. George Sr. tries to scare some at-risk youth, and Tobias tries to help George-Michael's\u2026","poster":"assets/episode-notapusy-2005-s3e4-poster.jpg","backdrop":"assets/episode-notapusy-2005-s3e4-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T12:17:58.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","seriesTitle":"Arrested Development","seasonNumber":3,"episodeNumber":4,"artwork":{"posterKind":"poster","backdropKind":"backdrop"}},{"id":"episode-the-man-who-would-be-vogue-2018-s2e1","title":"The Man Who Would Be Vogue","year":2018,"type":"episode","runtimeSeconds":3203,"seasonCount":null,"communityRating":7.459,"criticRating":null,"genres":["Biography","Crime","Drama"],"overview":"The murder of Gianni Versace turns the eyes of the world onto Miami Beach.","poster":"assets/episode-the-man-who-would-be-vogue-2018-s2e1-poster.jpg","backdrop":"assets/episode-the-man-who-would-be-vogue-2018-s2e1-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T13:29:35.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","seriesTitle":"American Crime Story","seasonNumber":2,"episodeNumber":1,"artwork":{"posterKind":"poster","backdropKind":"backdrop"}},{"id":"episode-tomorrow-2024-s3e1","title":"Tomorrow","year":2024,"type":"episode","runtimeSeconds":2207,"seasonCount":null,"communityRating":7.6,"criticRating":null,"genres":["Comedy","Drama"],"overview":"The next day and the days that led to it.","poster":"assets/episode-tomorrow-2024-s3e1-poster.jpg","backdrop":"assets/episode-tomorrow-2024-s3e1-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T13:46:39.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","seriesTitle":"The Bear","seasonNumber":3,"episodeNumber":1,"artwork":{"posterKind":"poster","backdropKind":"backdrop"}},{"id":"episode-episode-1-2025-s1e1","title":"Episode 1","year":2025,"type":"episode","runtimeSeconds":3618,"seasonCount":null,"communityRating":7.357,"criticRating":null,"genres":["Biography","Drama","History"],"overview":"Mussolini had just founded the Fasci di Combattimento when D'Annunzio took Fiume. Mussolini hoped to capitalize on the poet's achievement in the electoral arena.","poster":"assets/episode-episode-1-2025-s1e1-poster.jpg","backdrop":"assets/episode-episode-1-2025-s1e1-backdrop.jpg","played":false,"playCount":1,"resumeSeconds":489.55,"progress":0.1353,"addedAt":"2026-07-17T13:52:48.0000000Z","lastPlayedAt":"2026-11-04T19:01:49.9731435Z","availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","seriesTitle":"Mussolini: Son of the Century","seasonNumber":1,"episodeNumber":1,"artwork":{"posterKind":"center_crop","backdropKind":"backdrop"}}],"recentlyAdded":[{"id":"tv-the-final-problem-2026","title":"The Final Problem","year":2026,"type":"tv","runtimeSeconds":3420,"seasonCount":1,"communityRating":7.041,"criticRating":null,"genres":["Crime","Mystery"],"overview":"In the spring of 1959, a retired actor, who previously played Sherlock Holmes, must investigate a murder at a small hotel on a tiny island near Mallorca.","poster":"assets/tv-the-final-problem-2026-poster.jpg","backdrop":"assets/tv-the-final-problem-2026-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-11-04T19:16:12.4822791Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":290720,"artwork":{"posterKind":"center_crop","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.041,"tmdbVotes":49}},{"id":"tv-dead-end-job-2026","title":"Dead-End Job","year":2026,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":7.7,"criticRating":null,"genres":["Mystery"],"overview":"Drowning in debt, a young man takes lucrative part-time jobs from a mysterious agency \u2014 only to find his hustle for more money turning nightmarish.","poster":"assets/tv-dead-end-job-2026-poster.jpg","backdrop":"assets/tv-dead-end-job-2026-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-11-04T18:58:01.8352857Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":289517,"artwork":{"posterKind":"center_crop","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.7,"tmdbVotes":38}},{"id":"tv-dune-prophecy-2024","title":"Dune: Prophecy","year":2024,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":7.213,"criticRating":null,"genres":["Sci-Fi & Fantasy","Drama","Action & Adventure"],"overview":"Ten thousand years before the ascension of Paul Atreides, sisters Valya and Tula Harkonnen establish the fabled sect and female order that would become known as the Bene Gesserit to control the future of humankind.","poster":"assets/tv-dune-prophecy-2024-poster.jpg","backdrop":"assets/tv-dune-prophecy-2024-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-11-04T18:23:01.2908568Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":90228,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":64,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.213,"tmdbVotes":677}},{"id":"movie-the-uprising-2026","title":"The Uprising","year":2026,"type":"movie","runtimeSeconds":7684,"seasonCount":null,"communityRating":7.846,"criticRating":55,"genres":["Action","Drama","History"],"overview":"As war and plague devastate 14th-century England, a humble peasant ignites a rebellion, uniting an army of commoners to defy the King\u2019s might in a desperate fight for justice and survival.","poster":"assets/movie-the-uprising-2026-poster.jpg","backdrop":"assets/movie-the-uprising-2026-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-11-02T16:37:03.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":977942,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":57,"rtCriticsLabel":"Rotten","rtAudience":65,"rtAudienceLabel":"Upright","imdb":6.2,"imdbVotes":6622,"tmdb":7.8,"tmdbVotes":404}},{"id":"movie-jennifer-s-body-2009","title":"Jennifer's Body","year":2009,"type":"movie","runtimeSeconds":6450,"seasonCount":null,"communityRating":6.012,"criticRating":47,"genres":["Horror","Comedy"],"overview":"Jennifer, a gorgeous, seductive cheerleader takes evil to a whole new level after she's possessed by a sinister demon. Now it's up to her best friend to stop Jennifer's reign of terror before it's too late.","poster":"assets/movie-jennifer-s-body-2009-poster.jpg","backdrop":"assets/movie-jennifer-s-body-2009-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-30T03:37:04.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":19994,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":47,"rtCriticsLabel":"Rotten","rtAudience":36,"rtAudienceLabel":"Spilled","imdb":5.6,"imdbVotes":179710,"tmdb":6.013,"tmdbVotes":4481}},{"id":"tv-breeders-2020","title":"Breeders","year":2020,"type":"tv","runtimeSeconds":1500,"seasonCount":4,"communityRating":6.8,"criticRating":null,"genres":["Comedy"],"overview":"Exposing the parental-paradox that it is possible, in the very same moment, to love your child to the horizon of the universe, while being apoplectically angry enough to want to send them there.","poster":"assets/tv-breeders-2020-poster.jpg","backdrop":"assets/tv-breeders-2020-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-28T18:54:21.8885435Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":93290,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":92,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.8,"tmdbVotes":104}},{"id":"tv-the-four-seasons-2025","title":"The Four Seasons","year":2025,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":6.879,"criticRating":null,"genres":["Comedy"],"overview":"The decades-long friendship between three married couples is tested when one divorces, complicating their tradition of quarterly weekend getaways.","poster":"assets/tv-the-four-seasons-2025-poster.jpg","backdrop":"assets/tv-the-four-seasons-2025-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-28T18:36:42.5326384Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":243316,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":81,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.892,"tmdbVotes":204}},{"id":"tv-adults-2025","title":"Adults","year":2025,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":6.495,"criticRating":null,"genres":["Comedy"],"overview":"A group of twenty-somethings in New York trying to be good people, despite being neither \"good\" nor \"people\" yet.","poster":"assets/tv-adults-2025-poster.jpg","backdrop":"assets/tv-adults-2025-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-23T21:01:41.1814765Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":260458,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":88,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.5,"tmdbVotes":102}},{"id":"tv-east-of-eden-2026","title":"East of Eden","year":2026,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":7.931,"criticRating":null,"genres":["Drama","Crime"],"overview":"In the early 1900s, a fiercely independent woman drives a rift between two brothers, igniting a saga that unfolds across two generations.","poster":"assets/tv-east-of-eden-2026-poster.jpg","backdrop":"assets/tv-east-of-eden-2026-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-23T18:07:11.3965096Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":258165,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":88,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.982,"tmdbVotes":139}},{"id":"movie-fighting-with-my-family-2019","title":"Fighting with My Family","year":2019,"type":"movie","runtimeSeconds":6509,"seasonCount":null,"communityRating":6.84,"criticRating":93,"genres":["Comedy"],"overview":"Born into a tight-knit wrestling family, Paige and her brother Zak are ecstatic when they get the once-in-a-lifetime opportunity to try out for the WWE. But when only Paige earns a spot in the competitive training\u2026","poster":"assets/movie-fighting-with-my-family-2019-poster.jpg","backdrop":"assets/movie-fighting-with-my-family-2019-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-22T22:10:59.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":445629,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":93,"rtCriticsLabel":"Certified Fresh","rtAudience":86,"rtAudienceLabel":"Upright","imdb":7,"imdbVotes":94576,"tmdb":6.837,"tmdbVotes":1952}},{"id":"tv-landman-2024","title":"Landman","year":2024,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":8.194,"criticRating":null,"genres":["Drama"],"overview":"Set in the proverbial boomtowns of West-Texas and a modern-day tale of fortune-seeking in the world of oil rigs, the series is an upstairs/downstairs story of roughnecks and wildcat billionaires that are fueling a\u2026","poster":"assets/tv-landman-2024-poster.jpg","backdrop":"assets/tv-landman-2024-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-22T21:38:18.0973875Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":157741,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":80,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.209,"tmdbVotes":668}},{"id":"tv-fawlty-towers-1975","title":"Fawlty Towers","year":1975,"type":"tv","runtimeSeconds":1800,"seasonCount":2,"communityRating":8.295,"criticRating":null,"genres":["Comedy"],"overview":"Owner Basil Fawlty, his wife Sybil, a chambermaid Polly, and Spanish waiter Manuel attempt to run their hotel amidst farcical situations and an array of demanding guests.","poster":"assets/tv-fawlty-towers-1975-poster.jpg","backdrop":"assets/tv-fawlty-towers-1975-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-19T23:26:39.7658344Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":2207,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.296,"tmdbVotes":867}}],"discover":[{"id":"movie-12-years-a-slave-2013","title":"12 Years a Slave","year":2013,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","History"],"overview":"In the pre-Civil War United States, Solomon Northup, a free black man from upstate New York, is abducted and sold into slavery. Facing cruelty as well as unexpected kindnesses Solomon struggles not only to stay\u2026","poster":"assets/movie-12-years-a-slave-2013-poster.jpg","backdrop":"assets/movie-12-years-a-slave-2013-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":76203,"ratings":{"rtCritics":95,"rtCriticsLabel":"Certified Fresh","rtAudience":90,"rtAudienceLabel":"Upright","imdb":8.1,"imdbVotes":796313,"tmdb":7.927,"tmdbVotes":12335}},{"id":"movie-101-dalmatians-ii-patch-s-london-adventure-2003","title":"101 Dalmatians II: Patch's London Adventure","year":2003,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Family","Animation","Adventure"],"overview":"Being one of 101 takes its toll on Patch, who doesn't feel unique. When he's accidentally left behind on moving day, he meets his idol, Thunderbolt, who enlists him on a publicity campaign.","poster":"assets/movie-101-dalmatians-ii-patch-s-london-adventure-2003-poster.jpg","backdrop":"assets/movie-101-dalmatians-ii-patch-s-london-adventure-2003-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":13654,"ratings":{"rtCritics":67,"rtCriticsLabel":"Fresh","rtAudience":41,"rtAudienceLabel":"Spilled","imdb":5.7,"imdbVotes":12343,"tmdb":6.025,"tmdbVotes":1274}},{"id":"movie-absolution-2024","title":"Absolution","year":2024,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Crime","Thriller"],"overview":"An aging ex-boxer gangster working as muscle for a Boston crime boss receives an upsetting diagnosis. Despite a faltering memory, he attempts to rectify the sins of his past and reconnect with his estranged\u2026","poster":"assets/movie-absolution-2024-poster.jpg","backdrop":"assets/movie-absolution-2024-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":974453,"ratings":{"rtCritics":56,"rtCriticsLabel":"Rotten","rtAudience":32,"rtAudienceLabel":"Spilled","imdb":5.2,"imdbVotes":11413,"tmdb":5.906,"tmdbVotes":564}},{"id":"movie-addicted-2014","title":"Addicted","year":2014,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Thriller"],"overview":"A gallerist risks her family and flourishing career when she enters into an affair with a talented painter and slowly loses control of her life.","poster":"assets/movie-addicted-2014-poster.jpg","backdrop":"assets/movie-addicted-2014-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":235271,"ratings":{"rtCritics":7,"rtCriticsLabel":"Rotten","rtAudience":51,"rtAudienceLabel":"Spilled","imdb":5,"imdbVotes":13131,"tmdb":5.928,"tmdbVotes":466}},{"id":"movie-all-the-money-in-the-world-2017","title":"All the Money in the World","year":2017,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Crime","History","Thriller"],"overview":"The story of the kidnapping of 16-year-old John Paul Getty III and the desperate attempt by his devoted mother to convince his billionaire grandfather Jean Paul Getty to pay the ransom.","poster":"assets/movie-all-the-money-in-the-world-2017-poster.jpg","backdrop":"assets/movie-all-the-money-in-the-world-2017-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":446791,"ratings":{"rtCritics":79,"rtCriticsLabel":"Certified Fresh","rtAudience":66,"rtAudienceLabel":"Upright","imdb":6.8,"imdbVotes":97448,"tmdb":6.493,"tmdbVotes":2493}},{"id":"movie-the-alto-knights-2025","title":"The Alto Knights","year":2025,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Crime","Drama"],"overview":"Two of New York's most notorious organized crime bosses, Frank Costello and Vito Genovese, vie for control of the city's streets. Once the best of friends, petty jealousies and a series of betrayals place them on a\u2026","poster":"assets/movie-the-alto-knights-2025-poster.jpg","backdrop":"assets/movie-the-alto-knights-2025-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1013601,"ratings":{"rtCritics":39,"rtCriticsLabel":"Rotten","rtAudience":71,"rtAudienceLabel":"Upright","imdb":5.9,"imdbVotes":23017,"tmdb":6.223,"tmdbVotes":485}},{"id":"movie-the-amazing-spider-man-2-2014","title":"The Amazing Spider-Man 2","year":2014,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"For Peter Parker, life is busy. Between taking out the bad guys as Spider-Man and spending time with the person he loves, Gwen Stacy, high school graduation cannot come quickly enough. Peter has not forgotten about\u2026","poster":"assets/movie-the-amazing-spider-man-2-2014-poster.jpg","backdrop":"assets/movie-the-amazing-spider-man-2-2014-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":102382,"ratings":{"rtCritics":51,"rtCriticsLabel":"Rotten","rtAudience":64,"rtAudienceLabel":"Upright","imdb":6.6,"imdbVotes":611981,"tmdb":6.567,"tmdbVotes":14919}},{"id":"movie-ant-man-and-the-wasp-quantumania-2023","title":"Ant-Man and the Wasp: Quantumania","year":2023,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"Super-Hero partners Scott Lang and Hope van Dyne, along with with Hope's parents Janet van Dyne and Hank Pym, and Scott's daughter Cassie Lang, find themselves exploring the Quantum Realm, interacting with strange\u2026","poster":"assets/movie-ant-man-and-the-wasp-quantumania-2023-poster.jpg","backdrop":"assets/movie-ant-man-and-the-wasp-quantumania-2023-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":640146,"ratings":{"rtCritics":46,"rtCriticsLabel":"Rotten","rtAudience":81,"rtAudienceLabel":"Upright","imdb":6,"imdbVotes":281738,"tmdb":6.197,"tmdbVotes":6236}},{"id":"movie-arctic-dogs-2019","title":"Arctic Dogs","year":2019,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Adventure","Comedy"],"overview":"Animals band together to save the day when the evil Otto Von Walrus hatches a sinister scheme to accelerate global warming and melt the Arctic Circle.","poster":"assets/movie-arctic-dogs-2019-poster.jpg","backdrop":"assets/movie-arctic-dogs-2019-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":416153,"ratings":{"rtCritics":13,"rtCriticsLabel":"Rotten","rtAudience":60,"rtAudienceLabel":"Upright","imdb":4.9,"imdbVotes":2580,"tmdb":5.9,"tmdbVotes":148}},{"id":"movie-the-avengers-2012","title":"The Avengers","year":2012,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Science Fiction","Action","Adventure"],"overview":"When an unexpected enemy emerges and threatens global safety and security, Nick Fury, director of the international peacekeeping agency known as S.H.I.E.L.D., finds himself in need of a team to pull the world back\u2026","poster":"assets/movie-the-avengers-2012-poster.jpg","backdrop":"assets/movie-the-avengers-2012-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":24428,"ratings":{"rtCritics":91,"rtCriticsLabel":"Certified Fresh","rtAudience":91,"rtAudienceLabel":"Upright","imdb":8,"imdbVotes":1590693,"tmdb":8.084,"tmdbVotes":40262}},{"id":"movie-black-bear-2020","title":"Black Bear","year":2020,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Thriller"],"overview":"At a remote lake house in the Adirondack Mountains, a couple entertains an out-of-town guest looking for inspiration in her filmmaking. The group quickly falls into a calculated game of desire, manipulation, and\u2026","poster":"assets/movie-black-bear-2020-poster.jpg","backdrop":"assets/movie-black-bear-2020-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":624788,"ratings":{"rtCritics":89,"rtCriticsLabel":"Certified Fresh","rtAudience":64,"rtAudienceLabel":"Upright","imdb":6.5,"imdbVotes":18408,"tmdb":6.337,"tmdbVotes":315}},{"id":"movie-black-panther-2018","title":"Black Panther","year":2018,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"King T'Challa returns home to the reclusive, technologically advanced African nation of Wakanda to serve as his country's new leader. However, T'Challa soon finds that he is challenged for the throne by factions\u2026","poster":"assets/movie-black-panther-2018-poster.jpg","backdrop":"assets/movie-black-panther-2018-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":284054,"ratings":{"rtCritics":96,"rtCriticsLabel":"Certified Fresh","rtAudience":null,"rtAudienceLabel":"Spilled","imdb":7.3,"imdbVotes":931120,"tmdb":7.36,"tmdbVotes":24190}},{"id":"movie-a-bronx-tale-1993","title":"A Bronx Tale","year":1993,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Crime"],"overview":"Set in the Bronx during the tumultuous 1960s, an adolescent boy is torn between his honest, working-class father and a violent yet charismatic crime boss. Complicating matters is the youngster's growing attraction -\u2026","poster":"assets/movie-a-bronx-tale-1993-poster.jpg","backdrop":"assets/movie-a-bronx-tale-1993-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1607,"ratings":{"rtCritics":97,"rtCriticsLabel":"Fresh","rtAudience":92,"rtAudienceLabel":"Upright","imdb":7.8,"imdbVotes":191930,"tmdb":7.913,"tmdbVotes":3075}},{"id":"movie-by-any-means-2026","title":"By Any Means","year":2026,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Thriller","History","Crime"],"overview":"In 1960s Mississippi, a young Black FBI agent is forced to partner with a notorious mafia hitman to investigate a wave of brutal civil rights murders.","poster":"assets/movie-by-any-means-2026-poster.jpg","backdrop":"assets/movie-by-any-means-2026-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1380417,"ratings":{"rtCritics":49,"rtCriticsLabel":"Rotten","rtAudience":88,"rtAudienceLabel":"Upright","imdb":6.8,"imdbVotes":3534,"tmdb":6.6,"tmdbVotes":92}},{"id":"movie-captain-america-civil-war-2016","title":"Captain America: Civil War","year":2016,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Adventure","Action","Science Fiction"],"overview":"Following the events of Age of Ultron, the collective governments of the world pass an act designed to regulate all superhuman activity. This polarizes opinion amongst the Avengers, causing two factions to side with\u2026","poster":"assets/movie-captain-america-civil-war-2016-poster.jpg","backdrop":"assets/movie-captain-america-civil-war-2016-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":271110,"ratings":{"rtCritics":90,"rtCriticsLabel":"Certified Fresh","rtAudience":89,"rtAudienceLabel":"Upright","imdb":7.8,"imdbVotes":954943,"tmdb":7.455,"tmdbVotes":24808}},{"id":"movie-captain-america-the-first-avenger-2011","title":"Captain America: The First Avenger","year":2011,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"During World War II, Steve Rogers is a sickly man from Brooklyn who's transformed into super-soldier Captain America to aid in the war effort. Rogers must stop the Red Skull \u2013 Adolf Hitler's ruthless head of\u2026","poster":"assets/movie-captain-america-the-first-avenger-2011-poster.jpg","backdrop":"assets/movie-captain-america-the-first-avenger-2011-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1771,"ratings":{"rtCritics":80,"rtCriticsLabel":"Certified Fresh","rtAudience":75,"rtAudienceLabel":"Upright","imdb":6.9,"imdbVotes":993453,"tmdb":7.012,"tmdbVotes":23473}},{"id":"movie-captain-america-the-winter-soldier-2014","title":"Captain America: The Winter Soldier","year":2014,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"After the cataclysmic events in New York with The Avengers, Steve Rogers, aka Captain America is living quietly in Washington, D.C. and trying to adjust to the modern world. But when a S.H.I.E.L.D. colleague comes\u2026","poster":"assets/movie-captain-america-the-winter-soldier-2014-poster.jpg","backdrop":"assets/movie-captain-america-the-winter-soldier-2014-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":100402,"ratings":{"rtCritics":90,"rtCriticsLabel":"Certified Fresh","rtAudience":92,"rtAudienceLabel":"Upright","imdb":7.7,"imdbVotes":995514,"tmdb":7.654,"tmdbVotes":20688}},{"id":"movie-careful-what-you-wish-for-2015","title":"Careful What You Wish For","year":2015,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Thriller"],"overview":"A guy gets more than he bargained for after entering into an affair with the wife of an investment banker. Soon, a suspicious death and substantial life insurance policy embroil him in a scandal.","poster":"assets/movie-careful-what-you-wish-for-2015-poster.jpg","backdrop":"assets/movie-careful-what-you-wish-for-2015-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":317744,"ratings":{"rtCritics":17,"rtCriticsLabel":"Rotten","rtAudience":61,"rtAudienceLabel":"Upright","imdb":5.6,"imdbVotes":9452,"tmdb":6.129,"tmdbVotes":446}},{"id":"tv-12-monkeys-2015","title":"12 Monkeys","year":2015,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Sci-Fi & Fantasy","Drama"],"overview":"The provocative story of Cole, a time traveler from a decimated future in a high-stakes race against the clock. Utilizing a dangerous and untested method of time travel, he journeys from 2043 to the present day on a\u2026","poster":"assets/tv-12-monkeys-2015-poster.jpg","backdrop":"assets/tv-12-monkeys-2015-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":60948,"ratings":{"rtCritics":88,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.441,"tmdbVotes":1245}},{"id":"tv-90-day-fiance-before-the-90-days-2017","title":"90 Day Fianc\u00e9: Before the 90 Days","year":2017,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Reality"],"overview":"Follow couples who have an existing relationship online, but haven't met in person. We'll experience their journey as they travel to the other's foreign country for the first time in an attempt to establish an\u2026","poster":"assets/tv-90-day-fiance-before-the-90-days-2017-poster.jpg","backdrop":"assets/tv-90-day-fiance-before-the-90-days-2017-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":73319,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.5,"tmdbVotes":45}},{"id":"tv-90-day-fiance-the-other-way-2019","title":"90 Day Fianc\u00e9: The Other Way","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Reality"],"overview":"Americans move to a foreign country all in the name of love. Will uprooting their lives in the United States pay off, or will they be packing up and moving back to America brokenhearted?","poster":"assets/tv-90-day-fiance-the-other-way-2019-poster.jpg","backdrop":"assets/tv-90-day-fiance-the-other-way-2019-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":90046,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.8,"tmdbVotes":34}},{"id":"tv-the-100-2014","title":"The 100","year":2014,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Sci-Fi & Fantasy","Action & Adventure","Drama"],"overview":"100 years in the future, when the Earth has been abandoned due to radioactivity, the last surviving humans live on an ark orbiting the planet \u2014 but the ark won't last forever. So the repressive regime picks 100\u2026","poster":"assets/tv-the-100-2014-poster.jpg","backdrop":"assets/tv-the-100-2014-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":48866,"ratings":{"rtCritics":93,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.878,"tmdbVotes":8855}},{"id":"tv-accused-2023","title":"Accused","year":2023,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Crime","Drama"],"overview":"In this crime anthology series, viewers discover how an ordinary person got caught up in an extraordinary situation, ultimately revealing how one wrong turn leads to another, until it\u2019s too late to turn back. Told\u2026","poster":"assets/tv-accused-2023-poster.jpg","backdrop":"assets/tv-accused-2023-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":202097,"ratings":{"rtCritics":61,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.851,"tmdbVotes":87}},{"id":"tv-after-life-2019","title":"After Life","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy","Drama"],"overview":"Tony had a perfect life. But after his wife Lisa suddenly dies, Tony changes. After contemplating taking his own life, he decides instead to live long enough to punish the world by saying and doing whatever he likes\u2026","poster":"assets/tv-after-life-2019-poster.jpg","backdrop":"assets/tv-after-life-2019-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":79410,"ratings":{"rtCritics":72,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.902,"tmdbVotes":1169}},{"id":"tv-all-creatures-great-and-small-1978","title":"All Creatures Great and Small","year":1978,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy","Drama"],"overview":"The trials and misadventures of the staff at a country veterinary office in Yorkshire. James Herriot, a young animal surgeon, moves to a small Yorkshire town to begin his first job.","poster":"assets/tv-all-creatures-great-and-small-1978-poster.jpg","backdrop":"assets/tv-all-creatures-great-and-small-1978-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"center_crop","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":7406,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.8,"tmdbVotes":50}},{"id":"tv-american-housewife-2016","title":"American Housewife","year":2016,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy"],"overview":"A family comedy narrated by Katie, a strong-willed mother, raising her flawed family in a wealthy town filled with perfect wives and their perfect offspring.","poster":"assets/tv-american-housewife-2016-poster.jpg","backdrop":"assets/tv-american-housewife-2016-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":67117,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.7,"tmdbVotes":187}},{"id":"tv-atlantis-2013","title":"Atlantis","year":2013,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action & Adventure","Sci-Fi & Fantasy"],"overview":"A fantasy drama set in a world of legendary heroes and mythical creatures. Far from home and desperate for answers, Jason washes up on the shores of an ancient land. A mysterious place; a world of bull leaping, of\u2026","poster":"assets/tv-atlantis-2013-poster.jpg","backdrop":"assets/tv-atlantis-2013-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":47054,"ratings":{"rtCritics":62,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.4,"tmdbVotes":155}},{"id":"tv-avatar-the-last-airbender-2024","title":"Avatar: The Last Airbender","year":2024,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action & Adventure","Sci-Fi & Fantasy","Drama"],"overview":"A young boy known as the Avatar must master the four elemental powers to save a world at war \u2014 and fight a ruthless enemy bent on stopping him.","poster":"assets/tv-avatar-the-last-airbender-2024-poster.jpg","backdrop":"assets/tv-avatar-the-last-airbender-2024-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":82452,"ratings":{"rtCritics":66,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.8,"tmdbVotes":1406}},{"id":"tv-avatar-seven-havens-2026","title":"Avatar: Seven Havens","year":2026,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"In a world shattered by a devastating cataclysm, a young Earthbender discovers she's the new Avatar after Korra. But in this dangerous era, that title marks her as humanity's destroyer, not its savior. Hunted by both\u2026","poster":"assets/tv-avatar-seven-havens-2026-poster.jpg","backdrop":"assets/tv-avatar-seven-havens-2026-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":284833,"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.9,"tmdbVotes":183}},{"id":"tv-batman-the-brave-and-the-bold-2008","title":"Batman: The Brave and the Bold","year":2008,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"The Caped Crusader is teamed up with Blue Beetle, Green Arrow, Aquaman and countless others in his quest to uphold justice.","poster":"assets/tv-batman-the-brave-and-the-bold-2008-poster.jpg","backdrop":"assets/tv-batman-the-brave-and-the-bold-2008-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":15804,"ratings":{"rtCritics":96,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.6,"tmdbVotes":295}},{"id":"tv-beat-bobby-flay-2013","title":"Beat Bobby Flay","year":2013,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Reality"],"overview":"Two talented chefs go head-to-head for the chance to Beat Bobby Flay. To get to Bobby the chefs must first face off against each other, creating a spectacular dish with a secret ingredient of Bobby's choice. Judges\u2026","poster":"assets/tv-beat-bobby-flay-2013-poster.jpg","backdrop":"assets/tv-beat-bobby-flay-2013-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":62481,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.5,"tmdbVotes":31}},{"id":"tv-benson-1979","title":"Benson","year":1979,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy"],"overview":"A butler deals with life at the governor's mansion.","poster":"assets/tv-benson-1979-poster.jpg","backdrop":"assets/tv-benson-1979-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1849,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7,"tmdbVotes":46}},{"id":"tv-black-rabbit-2025","title":"Black Rabbit","year":2025,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Crime"],"overview":"A rising-star restaurateur is forced into New York's criminal underworld when his chaotic brother returns to town with loan sharks on his trail.","poster":"assets/tv-black-rabbit-2025-poster.jpg","backdrop":"assets/tv-black-rabbit-2025-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":249039,"ratings":{"rtCritics":66,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.983,"tmdbVotes":240}},{"id":"tv-black-ish-2014","title":"black-ish","year":2014,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy"],"overview":"A family man struggles to gain a sense of cultural identity while raising his kids in a predominantly white, upper-middle-class neighborhood.","poster":"assets/tv-black-ish-2014-poster.jpg","backdrop":"assets/tv-black-ish-2014-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":61381,"ratings":{"rtCritics":92,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.1,"tmdbVotes":352}},{"id":"tv-breaking-bad-2008","title":"Breaking Bad","year":2008,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Crime"],"overview":"Walter White, a New Mexico chemistry teacher, is diagnosed with Stage III cancer and given a prognosis of only two years left to live. He becomes filled with a sense of fearlessness and an unrelenting desire to\u2026","poster":"assets/tv-breaking-bad-2008-poster.jpg","backdrop":"assets/tv-breaking-bad-2008-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"center_crop","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1396,"ratings":{"rtCritics":96,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.959,"tmdbVotes":19030}},{"id":"tv-the-capture-2019","title":"The Capture","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Crime","Drama","Mystery"],"overview":"When soldier Shaun Emery's conviction for a murder in Afghanistan is overturned due to flawed video evidence, he returns to life as a free man with his young daughter. But when damning CCTV footage from a night out\u2026","poster":"assets/tv-the-capture-2019-poster.jpg","backdrop":"assets/tv-the-capture-2019-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":93166,"ratings":{"rtCritics":97,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.634,"tmdbVotes":361}}],"discoverySource":{"state":"materialized_snapshot","rankKnown":false,"selection":"First 18 alphabetically indexed movie stubs and first 18 series stubs, not ranked feed order","observedAt":"2026-11-04T20:42:12.030108+00:00"}}],"cast":{"movie:14069":[{"name":"Riisa Naka","character":"Makoto Konno (voice)","img":"tqFHQiJUycuob3ytvilaAWDlbQ8.jpg","order":0},{"name":"Takuya Ishida","character":"Chiaki Mamiya (voice)","img":"aHQk6XxqyJinfvrVRADEIg31nOk.jpg","order":1},{"name":"Mitsutaka Itakura","character":"Kousuke Tsuda (voice)","img":"mnKYU7HIsuRkx3YjdRO5FLXCdX5.jpg","order":2},{"name":"Ayami Kakiuchi","character":"Yuri Hayakawa (voice)","img":"lUhVV9u5VGMCNdCAVhGzg8GFSdo.jpg","order":3},{"name":"Mitsuki Tanimura","character":"Kaho Fujitani (voice)","img":"xV9UrP8kZdxOiTI2efDFhp3t4iA.jpg","order":4},{"name":"Yuki Sekido","character":"Miyuki Konno (voice)","img":"7LVYeFTgUpjYDrxnU7Wm5ZQUX9t.jpg","order":5},{"name":"Utawaka Katsura","character":"Makoto's Father (voice)","img":"j0GXzLelO1dOzI7d1WVIwQXhLz8.jpg","order":6},{"name":"Midori Ando","character":"Makoto's Mother (voice)","img":"26R1LBiSOkkP08saSsz6LmVTY16.jpg","order":7},{"name":"Fumihiko Tachiki","character":"Fukushima (voice)","img":null,"order":8},{"name":"Keiko Yamamoto","character":"Auntie (voice)","img":null,"order":9},{"name":"Shiori Yokohari","character":"Moriko Uesugi (voice)","img":null,"order":10},{"name":"Sonoka Matsuoka","character":"Sekimi Nowake (voice)","img":null,"order":11},{"name":"Takayuki Handa","character":"Kato (voice)","img":null,"order":12},{"name":"Maho Kurashima","character":"Female Newscaster A (voice)","img":null,"order":13},{"name":"Keiko Aizawa","character":"School Nurse / Answering Machine (voice)","img":null,"order":14}],"movie:210479":[{"name":"Tom Hardy","character":"Ivan Locke","img":"d81K0RH8UX7tZj49tZaQhZ9ewH.jpg","order":0},{"name":"Ruth Wilson","character":"Katrina (voice)","img":"fdFVatb9pt5dfT9tDK8tikKWafS.jpg","order":1},{"name":"Andrew Scott","character":"Donal (voice)","img":"4F8XpjyQCvtuu21WFm5d8RF5Rl.jpg","order":2},{"name":"Olivia Colman","character":"Bethan (voice)","img":"lawJUdbLb1YW0niaYjiVGR9IBG8.jpg","order":3},{"name":"Tom Holland","character":"Eddie (voice)","img":"xKBAaPIa1c7tzZD3Y0MhBLv4hPE.jpg","order":4},{"name":"Ben Daniels","character":"Gareth (voice)","img":"phEIvq0Ay2KjI5ewmVvpQ1a29GJ.jpg","order":5},{"name":"Bill Milner","character":"Sean (voice)","img":"bLgmpSFgEiSFNshqmdl3EIZkRZm.jpg","order":6},{"name":"Alice Lowe","character":"Sister Margaret (voice)","img":"v4sRxLpRpHEd9vbk43wm9VL0v0K.jpg","order":7},{"name":"Danny Webb","character":"Cassidy (voice)","img":null,"order":8},{"name":"Lee Ross","character":"PC Davids (voice)","img":null,"order":9},{"name":"Silas Carson","character":"Dr. Gullu (voice)","img":null,"order":10},{"name":"Kirsty Dillon","character":"Gareth's Wife (voice)","img":null,"order":11}],"movie:318917":[{"name":"Oliver Masucci","character":"Adolf Hitler","img":"fjJc03z1cOlMxLZbC1qihsq3C37.jpg","order":0},{"name":"Fabian Busch","character":"Fabian Sawatzki","img":"lpEs9yDsMQlsbm0RVsvDIleCXcI.jpg","order":1},{"name":"Christoph Maria Herbst","character":"Christoph Sensenbrink","img":"8v3lDa0QCJlDtOx9flqlMNIA3uf.jpg","order":2},{"name":"Katja Riemann","character":"Bellini","img":"waayy0jpNbxLDQ8JO1uRDng8SLF.jpg","order":3},{"name":"Franziska Wulf","character":"Kr\u00f6meier","img":"yxGsAKnrJZs2g6q4unNgkfm7NAA.jpg","order":4},{"name":"Lars Rudolph","character":"Shop Owner","img":"qiWu2gphSg64igYl3Nx0hEIOQF3.jpg","order":5},{"name":"Michael Kessler","character":"Michael Witzigmann","img":"sh4ANkKoIHgmHtkKQbJvF8y0Fjq.jpg","order":6},{"name":"Thomas Thieme","character":"K\u00e4rrner","img":"omWXGbeRR32MWuYhpnLOSqJ6xkO.jpg","order":7},{"name":"Frank Plasberg","character":"Frank Plasberg","img":null,"order":8},{"name":"Thomas M. K\u00f6ppl","character":"Etiquette Coach","img":null,"order":9},{"name":"Marc-Marvin Israel","character":"Football Boy","img":null,"order":10},{"name":"David Gebigke","character":"Football Boy","img":null,"order":11},{"name":"Paul Busche","character":"Football Boy","img":null,"order":12},{"name":"Gerdy Zint","character":"Pantomime","img":null,"order":13},{"name":"Nancy Maria Br\u00fcning","character":"Mother with Stroller","img":null,"order":14}],"movie:42994":[{"name":"Tsutomu Isobe","character":"Heinz Beckner (voice)","img":"qP5vQMIbLNvSsSFkEMLZRVt4ZW5.jpg","order":0},{"name":"Koichi Yamadera","character":"Miguel Costrela (voice)","img":"biov5jENp2XYfehkcdnRvi796Wi.jpg","order":1},{"name":"Shozo Iizuka","character":"Ivanov (voice)","img":"msqe5A1q5YUUND0RhzB9dw1AEAO.jpg","order":2},{"name":"Shigeru Chiba","character":"Aoshima (voice)","img":"mF5YJxApTYKBVFJDrEC9IrJ5ooV.jpg","order":3},{"name":"Gara Takashima","character":"Eva Friedel (voice)","img":"5L0kzTVITmOQdQ94NhicKM8ecCX.jpg","order":4},{"name":"Ami Hasegawa","character":"Emily (voice)","img":null,"order":5},{"name":"Hideyuki Hori","character":"Nobuo Tanaka (voice)","img":"fbWWkhe7GVSlhBljY89rJd01OnA.jpg","order":6},{"name":"Kenichi Ogata","character":"Oomaeda (voice)","img":"iQLEawIP2593yrGy22GzLSpnfgl.jpg","order":7},{"name":"Osamu Saka","character":"Kamata (voice)","img":null,"order":8},{"name":"Hisako Kyoda","character":"Grandma (voice)","img":null,"order":9},{"name":"Michio Hazama","character":"Nirasaki (voice)","img":null,"order":10},{"name":"Kayoko Fujii","character":"Sakiko (voice)","img":null,"order":11},{"name":"Ryoichi Tanaka","character":"General Officer (voice)","img":null,"order":12},{"name":"Tetsuya Iwanaga","character":"Nobuo's Brother (voice)","img":null,"order":13},{"name":"Yuu Hayashi","character":"Boy (voice)","img":null,"order":14}],"movie:123431":[{"name":"Snoop Dogg","character":"Self","img":"rbxBK2m6fEq0oHeMoBUMVYkJEdJ.jpg","order":0},{"name":"Dr. Dre","character":"Self","img":"xm2pYFBggiXSkFBV2I612i3fDd3.jpg","order":1},{"name":"Daz Dillinger","character":"Self","img":"nAxS5l9vb1C8ltCp9yAa0f6lazu.jpg","order":2},{"name":"Angela Hunte","character":"Self","img":null,"order":3},{"name":"Ariel Rechtshaid","character":"Self","img":"lF06PTNYrlXeJ3DYApvOcPXJr87.jpg","order":4},{"name":"Dre Skull","character":"Self","img":null,"order":5},{"name":"Jahdan Blakkamoore","character":"Self","img":null,"order":6},{"name":"Bunny Wailer","character":"Self","img":"oMHMLhoV3ry8aOfdvs1kxyowhNq.jpg","order":7},{"name":"Damian Marley","character":"Self","img":null,"order":8},{"name":"Louis Farrakhan","character":"Self","img":null,"order":9},{"name":"Shante Broadus","character":"Self","img":null,"order":10},{"name":"Cori Broadus","character":"Self","img":null,"order":11},{"name":"Maxine Stowe","character":"Self","img":null,"order":12},{"name":"Stewart Copeland","character":"Self","img":null,"order":13},{"name":"Diplo","character":"Self","img":null,"order":14}],"movie:1715492":[{"name":"John Scimone","character":"Self","img":null,"order":0},{"name":"Meghan Scimone","character":"Self","img":null,"order":1},{"name":"Patricia Sandoval","character":"Self","img":null,"order":2},{"name":"Nicholas Taliaferro","character":"Self","img":null,"order":3},{"name":"Stefania Vincenzi","character":"Self","img":null,"order":4},{"name":"Manrico Giampedroni","character":"Self","img":null,"order":5},{"name":"Rose Metcalf","character":"Self","img":null,"order":6},{"name":"Francesco Schettino","character":"Self (Archive Footage)","img":null,"order":7},{"name":"Manoj Singh","character":"Self","img":null,"order":8},{"name":"Francesco Boaria","character":"Self","img":null,"order":9},{"name":"Pier Luigi Foschi","character":"Self","img":null,"order":10},{"name":"Alessandro Cantelli-Forti","character":"Self","img":null,"order":11},{"name":"Barbie Latza Nadeau","character":"Self","img":null,"order":12}],"tv:83867":[{"name":"Diego Luna","character":"Cassian Andor","img":"qwbjcyDN37OHiln4a6P4LP31o7F.jpg","order":0},{"name":"Anton Lesser","character":"Major Partagaz","img":"x0lmqgkmphvOCSTHk2oxsaxA9Ra.jpg","order":3},{"name":"Muhannad Bhaier","character":"Wilmon","img":"5hn7WeXi6wguwxTPTSmcmzHAs9.jpg","order":4},{"name":"Stellan Skarsg\u00e5rd","character":"Luthen Rael","img":"mW7xmtGV4y79kQGn0zkKVGDMAmw.jpg","order":5},{"name":"Denise Gough","character":"Dedra Meero","img":"wWcby4ARYqr8d92ZdjyQcfaiJBW.jpg","order":6},{"name":"Kyle Soller","character":"Syril Karn","img":"rLzduQpYJnZJKkXv3jRc7MDHwoI.jpg","order":7},{"name":"Adria Arjona","character":"Bix Caleen","img":"hzu7OqTmNCT1xdCdmwBSf2yJvaO.jpg","order":8},{"name":"Genevieve O'Reilly","character":"Mon Mothma","img":"4eOoW1PNBZfxRW0g8RmYH8bL6mq.jpg","order":9},{"name":"Faye Marsay","character":"Vel Sartha","img":null,"order":10},{"name":"Elizabeth Dulau","character":"Kleya Marki","img":null,"order":11},{"name":"Alastair Mackenzie","character":"Perrin Fertha","img":null,"order":501},{"name":"Dave Chapman","character":"B2EMO (voice)","img":null,"order":509},{"name":"Robert Emms","character":"Supervisor Lonni Jung","img":null,"order":538},{"name":"Michael Jenn","character":"Supervisor Lagret","img":null,"order":539},{"name":"Jacob James Beswick","character":"Attendant Heert","img":null,"order":619}],"tv:76479":[{"name":"Karl Urban","character":"Billy Butcher","img":"7Y96dAfg0HcFrcLjlD5eD9N0uj4.jpg","order":0},{"name":"Jack Quaid","character":"Hugh 'Hughie' Campbell","img":"320qW5yEbxpmyxQ3evmClJbtKag.jpg","order":1},{"name":"Antony Starr","character":"Homelander","img":"xx3As5SWcE8vYOKZgtjDjqmT3jc.jpg","order":2},{"name":"Erin Moriarty","character":"Annie January / Starlight","img":"2tFblvjBRUYwcVT1V1i79Ppd6wG.jpg","order":3},{"name":"Jessie T. Usher","character":"Reggie Franklin / A-Train","img":null,"order":5},{"name":"Laz Alonso","character":"Marvin T. 'Mother's Milk' Milk / M.M.","img":"nmgOd3X2Xn3jIp9OLCRJzLExRWN.jpg","order":6},{"name":"Chace Crawford","character":"Kevin Moskowitz / The Deep","img":"yWZILsr2mBQBCG1LOcCYYshIbts.jpg","order":7},{"name":"Tomer Capone","character":"Serge / Frenchie","img":"r6s7dkYZUJpd00C7p9itT6Gp8XB.jpg","order":8},{"name":"Karen Fukuhara","character":"Kimiko Miyashiro","img":"sG6CWLdENCtzukNFkFYyPxqyRmS.jpg","order":9},{"name":"Nathan Mitchell","character":"Earving / Black Noir","img":null,"order":10},{"name":"Colby Minifie","character":"Ashley Barrett","img":null,"order":13},{"name":"Claudia Doumit","character":"Victoria 'Vic' Neuman","img":null,"order":14},{"name":"Cameron Crovetti","character":"Ryan","img":null,"order":16},{"name":"Dominique McElligott","character":"Maggie Shaw / Queen Maeve","img":null,"order":242},{"name":"Nneka Elliott","character":"Nneka Elliott","img":null,"order":894}],"tv:1215":[{"name":"David Duchovny","character":"Hank Moody","img":"fD8GuLHOOSSAG98VjwN3NhAmqAJ.jpg","order":0},{"name":"Natascha McElhone","character":"Karen van der Beek","img":"9pxaoasotR1pdCXYSfN1pkm0geO.jpg","order":1},{"name":"Evan Handler","character":"Charlie Runkle","img":"yU0OXeZ0K1ppe1o9SpHiAMHy1rc.jpg","order":2},{"name":"Pamela Adlon","character":"Marcy Runkle","img":"5eIRHUbNOH7ibXa0IfUfFvj5I5L.jpg","order":3},{"name":"Rachel Miner","character":"Dani","img":null,"order":4},{"name":"Madeleine Martin","character":"Becca Moody","img":"hOntuFYAMwn9QaXT0AwLCPU79ce.jpg","order":5},{"name":"Madeline Zima","character":"Mia Lewis","img":"6hmUs5Q1EETapn32yKNt3c3i1sn.jpg","order":6},{"name":"Callum Keith Rennie","character":"Lew Ashby","img":null,"order":7},{"name":"Carla Gallo","character":"Daisy","img":null,"order":513},{"name":"Embeth Davidtz","character":"Felicia Koons","img":null,"order":514},{"name":"Kathleen Turner","character":"Sue Collini","img":null,"order":522},{"name":"Jason Beghe","character":"Richard Bates","img":"hrTwOPWek7nkPJgFhh6inFu7vSS.jpg","order":534},{"name":"Stephen Tobolowsky","character":"Stu Beggs","img":"uL8yfcm0dCFYFQt052kczVQVvac.jpg","order":671},{"name":"Michael Imperioli","character":"Rick Rath","img":null,"order":843},{"name":"Oliver Cooper","character":"Levon","img":null,"order":844}],"tv:1437":[{"name":"Nathan Fillion","character":"Mal Reynolds","img":"aW6vCxkUZtwb6iH2Wf88Uq0XNVv.jpg","order":0},{"name":"Gina Torres","character":"Zo\u00eb Washburne","img":"ukDNHgvEgdU95eaw6pngiAPucv4.jpg","order":1},{"name":"Alan Tudyk","character":"Hoban Washburne","img":"jUuUbPuMGonFT5E2pcs4alfqaCN.jpg","order":2},{"name":"Morena Baccarin","character":"Inara Serra","img":"4gyHyg6FJ1oFczOm5pmMkdEEo2J.jpg","order":3},{"name":"Adam Baldwin","character":"Jayne Cobb","img":"lfbyJWNWGbiYfU0Yr1tjn6Trd2V.jpg","order":4},{"name":"Jewel Staite","character":"Kaylee Frye","img":"ztxDIZvuPreUixO6ZPxwkCg2UlO.jpg","order":5},{"name":"Sean Maher","character":"Simon Tam","img":"o7splcOIVAdbHnwohJOUAvXWVlk.jpg","order":6},{"name":"Michael Fairman","character":"Adelai Niska","img":null,"order":7},{"name":"Summer Glau","character":"River Tam","img":"rDTxblyw0AwU5oSeksgP7GwMyrF.jpg","order":8},{"name":"Ron Glass","character":"Derrial Book","img":null,"order":9},{"name":"Gregory Itzin","character":"Magistrate Higgins","img":null,"order":10},{"name":"Isabella Hofmann","character":"Regan Tam","img":null,"order":11},{"name":"Jeff Ricketts","character":"Man","img":null,"order":540},{"name":"Dennis Cockrum","character":"Other Man","img":null,"order":541},{"name":"Mark Sheppard","character":"Badger","img":null,"order":613}],"tv:67070":[{"name":"Phoebe Waller-Bridge","character":"Fleabag","img":"5VbadQsYCKdiJysP01LJFPmYB8A.jpg","order":0},{"name":"Sian Clifford","character":"Claire","img":"rIqcwewXdkrDTMTwX56QPa7MNTC.jpg","order":1},{"name":"Jenny Rainsford","character":"Boo","img":"pVwR9hsEiHzVTo9giCjR3vIfa8W.jpg","order":2},{"name":"Andrew Scott","character":"The Priest","img":"4F8XpjyQCvtuu21WFm5d8RF5Rl.jpg","order":3},{"name":"Ben Aldridge","character":"Arsehole Guy","img":null,"order":507},{"name":"Jo Martin","character":"Pam","img":null,"order":509},{"name":"Olivia Colman","character":"Godmother","img":"lawJUdbLb1YW0niaYjiVGR9IBG8.jpg","order":510},{"name":"Bill Paterson","character":"Dad","img":"mk5vpYLmER7asqOhEwVKXD3P3YE.jpg","order":511},{"name":"Jamie Demetriou","character":"Bus Rodent","img":null,"order":512},{"name":"Hugh Skinner","character":"Harry","img":"7MHdNxS1gRnx0ZQGPrfS5eRjMe3.jpg","order":513},{"name":"Hugh Dennis","character":"Bank Manager","img":null,"order":514},{"name":"Brett Gelman","character":"Martin","img":"ub2IuMWFNQGYghHTPq0lpmn2Ue0.jpg","order":515},{"name":"Anthony Welsh","character":"Jack","img":null,"order":516},{"name":"Kae Alexander","character":"Elaine","img":null,"order":523},{"name":"David Hargreaves","character":"Chatty Joe","img":null,"order":530}],"tv:40075":[{"name":"Jason Ritter","character":"Dipper Pines (voice)","img":null,"order":0},{"name":"Kristen Schaal","character":"Mabel Pines (voice)","img":null,"order":1},{"name":"Alex Hirsch","character":"Grunkle Stan / Soos Ramirez / Bill Cipher / Old Man McGucket (voice)","img":null,"order":2},{"name":"Linda Cardellini","character":"Wendy Corduroy (voice)","img":null,"order":3},{"name":"Will Forte","character":"Tyler Cutebiker (voice)","img":null,"order":13},{"name":"Gregg Turkington","character":"Young Toby Determined (voice)","img":null,"order":166},{"name":"Carl Faruolo","character":"Grenda (voice)","img":null,"order":170},{"name":"Jennifer Coolidge","character":"Lazy Susan (voice)","img":null,"order":175},{"name":"Dee Bradley Baker","character":"Waddles (voice) / Additional Voices (voice)","img":null,"order":399},{"name":"John DiMaggio","character":"Manly Dan / Pinball Cowboy Skeleton (voice)","img":null,"order":469},{"name":"Kevin Michael Richardson","character":"Sheriff Blubs / Ghost / Ancient Heads / Basketball Player / Manly Dan (voice)","img":null,"order":561},{"name":"Grey DeLisle","character":"Mrs. Gleeful (voice)","img":null,"order":582},{"name":"Matt Chapman","character":"Mermando / Additional Voices (voice)","img":null,"order":591},{"name":"Niki Yang","character":"Candy Chiu (voice)","img":null,"order":650},{"name":"T.J. Miller","character":"Robbie Valentino (voice)","img":null,"order":664}],"tv:95557":[{"name":"Steven Yeun","character":"Mark Grayson / Invincible (voice)","img":null,"order":0},{"name":"Sandra Oh","character":"Debbie Grayson (voice)","img":null,"order":1},{"name":"J.K. Simmons","character":"Nolan Grayson / Omni-Man (voice)","img":null,"order":2},{"name":"Dan Navarro","character":"Hazmat Responder / Additional Voices (voice)","img":null,"order":547},{"name":"Ami Shukla","character":"Additional Voices (voice)","img":null,"order":548},{"name":"Nyima Funk","character":"Additional Voices (voice)","img":null,"order":558},{"name":"Zazie Beetz","character":"Amber (voice)","img":null,"order":567},{"name":"Walton Goggins","character":"Cecil (voice)","img":null,"order":568},{"name":"Gillian Jacobs","character":"Eve (voice)","img":null,"order":574},{"name":"Jason Mantzoukas","character":"Rex / Zombie #2 (voice)","img":null,"order":588},{"name":"Chris Diamantopoulos","character":"Pete / Donald / Todd (voice)","img":null,"order":596},{"name":"Khary Payton","character":"Black Samson / Martian (voice)","img":null,"order":601},{"name":"Ross Marquand","character":"Immortal / Rudy / Kursk (voice)","img":null,"order":628},{"name":"Grey DeLisle","character":"Monster Girl / Thula / Woman (voice)","img":null,"order":656},{"name":"Bobby Kesselman","character":"Additional Voices (voice)","img":null,"order":734}],"tv:33880":[{"name":"Janet Varney","character":"Korra (voice)","img":null,"order":0},{"name":"David Faustino","character":"Mako (voice)","img":null,"order":1},{"name":"P.J. Byrne","character":"Bolin (voice)","img":null,"order":2},{"name":"Seychelle Gabriel","character":"Asami Sato (voice)","img":null,"order":3},{"name":"Mindy Sterling","character":"Lin Beifong (voice)","img":null,"order":6},{"name":"Adrian LaTourelle","character":"Unalaq (voice)","img":null,"order":9},{"name":"J.K. Simmons","character":"Mushi (voice)","img":null,"order":68},{"name":"Dee Bradley Baker","character":"Juicy (voice)","img":null,"order":324},{"name":"Kiernan Shipka","character":"Jinora (voice)","img":null,"order":500},{"name":"Darcy Rose Byrnes","character":"Ikki (voice)","img":null,"order":503},{"name":"Logan Wells","character":"Meelo (voice)","img":null,"order":504},{"name":"John Michael Higgins","character":"Varrick (voice)","img":null,"order":549},{"name":"Richard Riehle","character":"Bumi (voice)","img":null,"order":551},{"name":"Maria Bamford","character":"Pema (voice)","img":null,"order":556},{"name":"Jeff Bennett","character":"Shiro Shinobi / Fishmonger / Ring Announcer (voice)","img":null,"order":568}],"tv:86831":[{"name":"Josh Brener","character":"K-VRC (voice)","img":null,"order":237},{"name":"Matthew Yang King","character":"Host (voice)","img":null,"order":520},{"name":"Nolan North","character":"Vladimir (voice)","img":null,"order":555},{"name":"Ike Amadi","character":"Platoon Sergeant (voice)","img":null,"order":566},{"name":"Time Winters","character":"Dicko (voice)","img":null,"order":584},{"name":"Emily O'Brien","character":"Eve (voice)","img":null,"order":592},{"name":"Chris Cox","character":"Male Backgound (voice)","img":null,"order":592},{"name":"Noshir Dalal","character":"Beaumont (voice)","img":null,"order":599},{"name":"Michelle C. Bonilla","character":"Commander / Pilot (voice)","img":null,"order":599},{"name":"Stanton Lee","character":"Sergeant Howard (voice)","img":null,"order":602},{"name":"Fred Tatasciore","character":"Creature / TV Santa (voice)","img":null,"order":608},{"name":"Scott Whyte","character":"Trot (voice)","img":null,"order":618},{"name":"Caitlin McKenna","character":"Additional Voices (voice)","img":null,"order":622},{"name":"Piotr Michael","character":"Investor (voice)","img":null,"order":636},{"name":"Chris Parnell","character":"The Cat (voice)","img":null,"order":653}],"tv:68126":[{"name":"Trond Fausa Aurv\u00e5g","character":"Rufus","img":null,"order":0},{"name":"Jon \u00d8igarden","character":"Jarl Varg","img":null,"order":1},{"name":"K\u00e5re Conradi","character":"Orm","img":null,"order":2},{"name":"Silje Torp","character":"Fr\u00f8ya","img":null,"order":3},{"name":"Mikkel Bratt Silset","character":"Ragnar","img":null,"order":4},{"name":"Nils J\u00f8rgen Kaalstad","character":"Arvid","img":null,"order":5},{"name":"Kristine Riis","character":"Liv","img":null,"order":6},{"name":"Bj\u00f8rn Hallgeir Myrene","character":"Torstein Hund","img":null,"order":7},{"name":"Marian Saastad Ottesen","character":"Hildur","img":null,"order":8},{"name":"Nikis Theophilakis","character":"Olvar / Eigil","img":null,"order":9},{"name":"\u00d8ystein Martinsen","character":"Kark","img":null,"order":10},{"name":"Christian Skolmen","character":"H\u00e5kon","img":null,"order":11},{"name":"Erik Aleksander Schjerven","character":"Magnus","img":null,"order":12},{"name":"Ingar Helge Gimle","character":"Nomadeh\u00f8vding","img":null,"order":13},{"name":"Finn Schau","character":"Lovgiveren","img":null,"order":14}],"tv:60625":[{"name":"Justin Roiland","character":"Rick Sanchez / Morty Smith (voice)","img":null,"order":0},{"name":"Chris Parnell","character":"Jerry Smith (voice)","img":null,"order":1},{"name":"Spencer Grammer","character":"Summer Smith (voice)","img":null,"order":2},{"name":"Sarah Chalke","character":"Beth Smith (voice)","img":null,"order":3},{"name":"Ian Cardoni","character":"Rick Sanchez (voice)","img":null,"order":4},{"name":"Harry Belden","character":"Morty Smith (voice)","img":null,"order":6},{"name":"Dan Harmon","character":"Alejandro (voice)","img":null,"order":688},{"name":"Kari Wahlgren","character":"Roy's Wife (voice)","img":null,"order":715},{"name":"Maurice LaMarche","character":"Roy's Teacher / Gromflamite Fed (voice)","img":null,"order":743},{"name":"Tom Kenny","character":"Conroy / Federation Admiral / Additional Voices (voice)","img":null,"order":750},{"name":"Ryan Ridley","character":"Head Vampire (voice)","img":null,"order":752},{"name":"Brandon Johnson","character":"Mr. Goldenfold / Black Mailman (voice)","img":null,"order":755},{"name":"Nolan North","character":"Jerry's High School Friend (voice)","img":null,"order":757},{"name":"Rob Schrab","character":"Town Resident (voice)","img":null,"order":768},{"name":"Nick Reczynski","character":"Snake Humanoid (voice)","img":null,"order":815}],"tv:261579":[{"name":"Keanu Reeves","character":"Pilot (voice)","img":null,"order":500},{"name":"Parry Shen","character":"MC (young) (voice)","img":null,"order":501},{"name":"Ping Wu","character":"MC (Old) (voice)","img":null,"order":502},{"name":"Lydia Look","character":"Li (voice)","img":null,"order":503},{"name":"Nelson Lee","character":"Sean (voice)","img":null,"order":504},{"name":"Feodor Chin","character":"Thug (voice)","img":null,"order":505},{"name":"Rae Lim","character":"MC (Child) (voice)","img":null,"order":506},{"name":"Erin Yvette","character":"The Voice (voice)","img":null,"order":507},{"name":"Temuera Morrison","character":"Old Salt (voice)","img":null,"order":508},{"name":"Patrick Schwarzenegger","character":"The Kid (voice)","img":null,"order":509},{"name":"Steve Blum","character":"Dispatch / Mechanic (voice)","img":null,"order":510},{"name":"Noah Manzoor","character":"Solon (voice)","img":null,"order":511},{"name":"Madeleine Knight","character":"Mora (voice)","img":null,"order":512},{"name":"Aleks Le","character":"Yi Xing (voice)","img":null,"order":556},{"name":"Fred Tatasciore","character":"Helldiver (voice)","img":null,"order":558}],"tv:125988":[{"name":"Rebecca Ferguson","character":"Juliette Nichols","img":null,"order":0},{"name":"Common","character":"Robert Sims","img":null,"order":1},{"name":"Chinaza Uche","character":"Paul Billings","img":null,"order":2},{"name":"Shane McRae","character":"Knox","img":null,"order":4},{"name":"Remmie Milner","character":"Shirley Campbell","img":null,"order":6},{"name":"Alexandria Riley","character":"Camille Sims","img":null,"order":7},{"name":"Billy Postlethwaite","character":"Hank Murphy","img":null,"order":12},{"name":"Tim Robbins","character":"Bernard Holland","img":null,"order":15},{"name":"Clare Perkins","character":"Carla McLain","img":null,"order":17},{"name":"Harriet Walter","character":"Martha Walker","img":null,"order":18},{"name":"Avi Nash","character":"Lukas Kyle","img":null,"order":20},{"name":"Rick Gomez","character":"Patrick Kennedy","img":null,"order":21},{"name":"Olatunji Ayofe","character":"Teddy","img":null,"order":502},{"name":"Chipo Chung","character":"Sandy","img":null,"order":506},{"name":"Caitlin Zoz","character":"Kathleen Billings","img":null,"order":542}],"tv:2190":[{"name":"Isaac Hayes","character":"Chef (voice)","img":null,"order":2},{"name":"Mary Kay Bergman","character":"Liane Cartman / Wendy Testaburger / Sharon Marsh / Sheila Broflovski (voice)","img":null,"order":3},{"name":"Mona Marshall","character":"Sheila Broflovski (voice)","img":null,"order":4},{"name":"Sebastian Yu","character":"Ike Broflovski (voice)","img":null,"order":7},{"name":"Jessie Jo Thomas","character":"","img":null,"order":8},{"name":"Milan Agnone","character":"Ike Broflovski (voice)","img":null,"order":9},{"name":"Trey Parker","character":"Eric Cartman / Stan Marsh / Randy Marsh / Mr. Garrison (voice)","img":null,"order":10},{"name":"Matt Stone","character":"Kyle Broflovski / Kenny McCormick / Butters Stotch (voice)","img":null,"order":11},{"name":"Jennifer Howell","character":"Bebe Stevens (voice)","img":null,"order":11},{"name":"April Stewart","character":"Wendy Testaburger / Liane Cartman / Dora M\u00e1rquez (voice)","img":null,"order":65},{"name":"Eliza Schneider","character":"Liane Cartman (voice)","img":null,"order":79},{"name":"Kyle McCulloch","character":"Excalibur Hotel Employee (voice)","img":null,"order":512},{"name":"Jonathan Kimmel","character":"","img":null,"order":528},{"name":"John Hansen","character":"","img":null,"order":534},{"name":"Adrien Beard","character":"Tolkien Black (voice)","img":null,"order":554}],"tv:30984":[{"name":"Masakazu Morita","character":"Ichigo Kurosaki (voice)","img":null,"order":0},{"name":"Fumiko Orikasa","character":"Rukia Kuchiki (voice)","img":null,"order":1},{"name":"Hiroki Yasumoto","character":"Yasutora Sado (voice)","img":null,"order":2},{"name":"Yuki Matsuoka","character":"Orihime Inoue (voice)","img":null,"order":3},{"name":"Noriaki Sugiyama","character":"Uryu Ishida (voice)","img":null,"order":4},{"name":"Kentaro Ito","character":"Renji Abarai (voice)","img":null,"order":47},{"name":"Ryotaro Okiayu","character":"Byakuya Kuchki (voice)","img":null,"order":48},{"name":"Mitsuaki Madono","character":"Kon (voice)","img":null,"order":49},{"name":"Toshiyuki Morikawa","character":"Kaname T\u014dsen (voice)","img":null,"order":133},{"name":"Kiyoyuki Yanada","character":"Tessai Tsukabishi (voice)","img":null,"order":500},{"name":"Katsuyuki Konishi","character":"Shuhei Hisagi (voice)","img":null,"order":501},{"name":"Shin-ichiro Miki","character":"Kisuke Urahara (voice)","img":null,"order":504},{"name":"Masaya Onosaka","character":"Gejigeji mukade (voice)","img":null,"order":505},{"name":"Ryusei Nakao","character":"Mayuri Kurotsuchi (voice)","img":null,"order":509},{"name":"Takayuki Sugo","character":"Yhwach (voice)","img":null,"order":517}],"tv:114410":[{"name":"Kikunosuke Toya","character":"Denji (voice)","img":null,"order":0},{"name":"Tomori Kusunoki","character":"Makima (voice)","img":null,"order":1},{"name":"Shogo Sakata","character":"Aki Hayakawa (voice)","img":null,"order":2},{"name":"Fairouz Ai","character":"Power (voice)","img":null,"order":3},{"name":"Mariya Ise","character":"Himeno (voice)","img":null,"order":500},{"name":"Marina Inoue","character":"Child Denji (voice)","img":null,"order":507},{"name":"Kenjiro Tsuda","character":"Kishibe (voice)","img":null,"order":519},{"name":"Taku Yashiro","character":"Arai (voice)","img":null,"order":520},{"name":"Karin Takahashi","character":"Kobeni (voice)","img":null,"order":521},{"name":"Shiori Izawa","character":"Pochita (voice)","img":null,"order":522},{"name":"Mitsutoshi Shundo","character":"Announcer (voice)","img":null,"order":528},{"name":"Hironori Kondoh","character":"Eternity Devil (voice)","img":null,"order":538},{"name":"Noriyuki Tsuyuki","character":"Henchman D (voice)","img":null,"order":542},{"name":"Daiki Hamano","character":"Samurai Sword (voice)","img":null,"order":546},{"name":"You Taichi","character":"Sawatari (voice)","img":null,"order":547}],"tv:105248":[{"name":"KENN","character":"David Martinez (voice)","img":null,"order":0},{"name":"Koki Uchiyama","character":"D (voice)","img":null,"order":1},{"name":"Momoka Terasawa","character":"Roman (voice)","img":null,"order":2},{"name":"Akari Kito","character":"Talia (voice)","img":null,"order":3},{"name":"Kentaro Tone","character":"Weak (voice)","img":null,"order":4},{"name":"Kento Shiraishi","character":"Maelstrom (voice)","img":null,"order":531},{"name":"Kenjiro Tsuda","character":"Ripperdoc (voice)","img":null,"order":568},{"name":"Aoi Yuki","character":"Lucy (voice)","img":null,"order":571},{"name":"Kazuhiko Inoue","character":"Faraday (voice)","img":null,"order":573},{"name":"Tomoyo Kurosawa","character":"Rebecca (voice)","img":null,"order":574},{"name":"Takako Honda","character":"Kiwi (voice)","img":null,"order":575},{"name":"Ryuho Nagaoka","character":"Driver (voice)","img":null,"order":627},{"name":"Akemi Okamura","character":"Avida (voice)","img":null,"order":668},{"name":"Aoi Koga","character":"Capri (voice)","img":null,"order":669},{"name":"Yasunori Matsumoto","character":"Kiril (voice)","img":null,"order":670}],"tv:240411":[{"name":"Shion Wakayama","character":"Momo Ayase (voice)","img":null,"order":0},{"name":"Natsuki Hanae","character":"Ken 'Okarun' Takakura (voice)","img":null,"order":1},{"name":"Mayumi Tanaka","character":"Turbo Granny (voice)","img":null,"order":2},{"name":"Nana Mizuki","character":"Seiko (voice)","img":null,"order":3},{"name":"Kaori Maeda","character":"Miko (voice)","img":null,"order":500},{"name":"Miyu Tomita","character":"Muko (voice)","img":null,"order":501},{"name":"Ayane Sakura","character":"Aira Shiratori (voice)","img":null,"order":519},{"name":"Aya Yamane","character":"Tsubame (voice)","img":null,"order":520},{"name":"Natsu Yorita","character":"Anzu (voice)","img":null,"order":521},{"name":"Koji Seki","character":"Male Teacher (voice)","img":null,"order":527},{"name":"Koseki Kogure","character":"Student C (voice)","img":null,"order":527},{"name":"Yukiko Motoyoshi","character":"Female Student A (voice)","img":null,"order":528},{"name":"Kazuya Nakai","character":"Serpoian A / Serpoian B / Serpoian C (voice)","img":null,"order":533},{"name":"Tomokazu Seki","character":"Dover Demon (voice)","img":null,"order":536},{"name":"Kaito Ishikawa","character":"Jin 'Jiji' Enjouji (voice)","img":null,"order":541}],"tv:86031":[{"name":"Yusuke Kobayashi","character":"Senku Ishigami (voice)","img":null,"order":0},{"name":"Makoto Furukawa","character":"Taiju Oki (voice)","img":null,"order":1},{"name":"Kana Ichinose","character":"Yuzuriha Ogawa (voice)","img":null,"order":2},{"name":"Manami Numakura","character":"Kohaku (voice)","img":null,"order":3},{"name":"Yuichi Nakamura","character":"Tsukasa (voice)","img":null,"order":4},{"name":"Gen Sato","character":"Chrome (voice)","img":null,"order":5},{"name":"Ayumu Murase","character":"Ginro (voice)","img":null,"order":6},{"name":"Yuya Hirose","character":"Science Club Member (voice)","img":null,"order":501},{"name":"Aoi Ichikawa","character":"Science Club Member (voice)","img":null,"order":502},{"name":"Haruki Ishiya","character":"Science Club Member (voice)","img":null,"order":503},{"name":"Kouichi Souma","character":"Teacher (voice)","img":null,"order":504},{"name":"Keiji Fujiwara","character":"Byakuya Ishigami (voice)","img":null,"order":508},{"name":"Kengo Kawanishi","character":"Asagiri Gen (voice)","img":null,"order":526},{"name":"Ryota Suzuki","character":"Nanami Ryuusui (voice)","img":null,"order":527},{"name":"Karin Takahashi","character":"Suika (Voice)","img":null,"order":528}],"tv:209867":[{"name":"Atsumi Tanezaki","character":"Frieren (voice)","img":null,"order":0},{"name":"Kana Ichinose","character":"Fern (voice)","img":null,"order":1},{"name":"Chiaki Kobayashi","character":"Stark (voice)","img":null,"order":2},{"name":"Nobuhiko Okamoto","character":"Himmel (voice)","img":null,"order":3},{"name":"Hiroki Touchi","character":"\ud558\uc774\ud130 (voice)","img":null,"order":4},{"name":"Yoji Ueda","character":"Eisen (voice)","img":null,"order":5},{"name":"Kento Shiraishi","character":"Falsch (voice)","img":null,"order":550},{"name":"Azumi Waki","character":"Kanne (voice)","img":null,"order":565},{"name":"Sayumi Suzushiro","character":"Lawine (voice)","img":null,"order":566},{"name":"Ikumi Hasegawa","character":"\u00dcbel (voice)","img":null,"order":567},{"name":"Haruka Terui","character":"Sense (voice)","img":null,"order":568},{"name":"Tarusuke Shingaki","character":"Genau (voice)","img":null,"order":569},{"name":"Masafumi Kobatake","character":"Mining Worker (voice)","img":null,"order":572},{"name":"Jiro Saito","character":"Denken (voice)","img":null,"order":576},{"name":"Eiji Hanawa","character":"Richter (voice)","img":null,"order":577}],"tv:31911":[{"name":"Romi Park","character":"Edward Elric (voice)","img":null,"order":0},{"name":"Shin-ichiro Miki","character":"Roy Mustang (voice)","img":null,"order":2},{"name":"Fumiko Orikasa","character":"Riza Hawkeye (voice)","img":null,"order":3},{"name":"Megumi Takamoto","character":"Winry Rockbell (voice)","img":null,"order":4},{"name":"Rie Kugimiya","character":"Alphonse Elric (voice)","img":null,"order":341},{"name":"Hidekatsu Shibata","character":"King Bradley (voice)","img":null,"order":505},{"name":"Kenji Utsumi","character":"Louis Armstrong (voice)","img":null,"order":507},{"name":"Kenta Miyake","character":"Scar (voice)","img":null,"order":535},{"name":"Minami Takayama","character":"Envy (voice)","img":null,"order":541},{"name":"Iemasa Kayumi","character":"Father (voice)","img":null,"order":552},{"name":"Biichi Sato","character":"Doctor (voice)","img":null,"order":559},{"name":"Mamoru Miyano","character":"Ling Yao (voice)","img":null,"order":587},{"name":"Mai Gotou","character":"May Chang (voice)","img":null,"order":590},{"name":"Yuki Hayashi","character":"Military (voice)","img":null,"order":630},{"name":"Takashi Hikida","character":"Ishvalan A (voice)","img":null,"order":689}],"tv:95479":[{"name":"Takaya Kuroda","character":"Masamichi Yaga (voice)","img":null,"order":549},{"name":"Nobunaga Shimazaki","character":"Mahito (voice)","img":null,"order":600},{"name":"Tomokazu Seki","character":"Panda (voice)","img":null,"order":602},{"name":"Mikako Komatsu","character":"Maki Zen'in (voice)","img":null,"order":603},{"name":"Kenjiro Tsuda","character":"Kento Nanami (voice)","img":null,"order":605},{"name":"Junichi Suwabe","character":"Ryomen Sukuna (voice)","img":null,"order":612},{"name":"Shigeru Chiba","character":"Grandfather (voice)","img":"mF5YJxApTYKBVFJDrEC9IrJ5ooV.jpg","order":654},{"name":"Aya Endo","character":"Shoko Ieiri (voice)","img":null,"order":666},{"name":"Mitsuo Iwata","character":"Spectator (voice)","img":null,"order":685},{"name":"Yuichi Nakamura","character":"Satoru Gojo (voice)","img":null,"order":686},{"name":"Asami Seto","character":"Transfigured Human (voice)","img":null,"order":687},{"name":"Junya Enoki","character":"Yuji Itadori (voice)","img":null,"order":689},{"name":"Takahiro Sakurai","character":"Suguru Geto (voice)","img":null,"order":718},{"name":"Yoshiko Sakakibara","character":"Tengen (voice)","img":null,"order":739},{"name":"Yuma Uchida","character":"Megumi Fushiguro (voice)","img":null,"order":849}],"tv:207468":[{"name":"Masaya Fukunishi","character":"Kafka Hibino / Kaiju No. 8 (voice)","img":null,"order":0},{"name":"Asami Seto","character":"Mina Ashiro (voice)","img":null,"order":1},{"name":"Wataru Katoh","character":"Reno Ichikawa (voice)","img":null,"order":2},{"name":"Kengo Kawanishi","character":"Soshiro Hoshina (voice)","img":null,"order":4},{"name":"Fairouz Ai","character":"Kaiju No. 15 (voice)","img":null,"order":322},{"name":"Nene Hieda","character":"Akari Minase (voice)","img":null,"order":546},{"name":"Tomohiro Ono","character":"Shimoen (voice)","img":null,"order":551},{"name":"Genta Nakamura","character":"Operator (voice)","img":null,"order":569},{"name":"Takayuki Sugo","character":"Keiji Itami (voice)","img":null,"order":575},{"name":"Ryosuke Higa","character":"Ministry of Defense Staff Member (voice)","img":null,"order":577},{"name":"Shota Yamamoto","character":"Mebari (voice)","img":null,"order":612},{"name":"Yuuki Shin","character":"Iharu Furuhashi (voice)","img":null,"order":625},{"name":"Keisuke Komoto","character":"Haruichi Izumo (voice)","img":null,"order":626},{"name":"Shunsuke Takeuchi","character":"Aoi Kaguragi (voice)","img":null,"order":627},{"name":"Sayaka Senbongi","character":"Konomi Okonogi (voice)","img":null,"order":628}],"tv:65930":[{"name":"Daiki Yamashita","character":"Izuku Midoriya (voice)","img":null,"order":0},{"name":"Tarusuke Shingaki","character":"Mirio Togata (voice)","img":null,"order":1},{"name":"Nobuhiko Okamoto","character":"Katsuki Bakugo (voice)","img":null,"order":2},{"name":"Kenta Miyake","character":"All Might (voice)","img":null,"order":3},{"name":"Yuki Kaji","character":"Shoto Todoroki (voice)","img":null,"order":6},{"name":"Seiran Kobayashi","character":"Eri (voice)","img":null,"order":8},{"name":"Ayane Sakura","character":"Ochako Uraraka (voice)","img":null,"order":48},{"name":"Aoi Yuki","character":"Setsuna Tokage (voice)","img":null,"order":51},{"name":"Junichi Suwabe","character":"Jurota Shishida (voice)","img":null,"order":60},{"name":"Kaito Ishikawa","character":"Tenya Iida (voice)","img":null,"order":91},{"name":"Kenjiro Tsuda","character":"Overhaul (voice)","img":null,"order":505},{"name":"Koki Uchiyama","character":"Tomura Shigaraki (voice)","img":null,"order":546},{"name":"Hiro Shimono","character":"Dabi (voice)","img":null,"order":571},{"name":"Kiyotaka Furushima","character":"Kido (voice)","img":null,"order":583},{"name":"Tetsu Inada","character":"Endeavor (voice)","img":null,"order":585}],"tv:890":[{"name":"Megumi Ogata","character":"Shinji Ikari (voice)","img":null,"order":0},{"name":"Kotono Mitsuishi","character":"Misato Katsuragi (voice)","img":null,"order":1},{"name":"Megumi Hayashibara","character":"Rei Ayanami (voice)","img":null,"order":2},{"name":"Yuko Miyamura","character":"Asuka Langley Soryu (voice)","img":null,"order":3},{"name":"Yuriko Yamaguchi","character":"Dr. Ritsuko Akagi (voice)","img":null,"order":4},{"name":"Fumihiko Tachiki","character":"Gendo Ikari (voice)","img":null,"order":5},{"name":"Motomu Kiyokawa","character":"Kozo Fuyutsuki (voice)","img":null,"order":6},{"name":"Miki Nagasawa","character":"Maya Ibuki (voice)","img":null,"order":7},{"name":"Mugihito","character":"Keel Lorenz (voice)","img":null,"order":500},{"name":"Junko Iwao","character":"Hikari Horaki (voice)","img":null,"order":501},{"name":"Tetsuya Iwanaga","character":"Kensuke Aida (voice)","img":null,"order":503},{"name":"Tomokazu Seki","character":"Touji Suzuhara (voice)","img":null,"order":505},{"name":"Takehito Koyasu","character":"Shigeru Aoba (voice)","img":null,"order":505},{"name":"Koichi Yamadera","character":"Ryouji Kaji (voice)","img":"biov5jENp2XYfehkcdnRvi796Wi.jpg","order":506},{"name":"Hiro Yuuki","character":"Makoto Hyuuga (voice)","img":null,"order":508}],"tv:114868":[{"name":"Tomoyo Kurosawa","character":"G\u00f6ll (voice)","img":null,"order":1},{"name":"Wataru Takagi","character":"Zeus (voice)","img":null,"order":2},{"name":"Junichi Suwabe","character":"Hermes (voice)","img":null,"order":3},{"name":"Soma Saito","character":"Adam (voice)","img":null,"order":4},{"name":"Miyuki Sawashiro","character":"Narrator (voice)","img":null,"order":87},{"name":"Tatsuhisa Suzuki","character":"Shiva (voice)","img":null,"order":501},{"name":"Rie Tanaka","character":"Aphrodite (voice)","img":null,"order":502},{"name":"Yukihiro Nozuyama","character":"Heimdall (voice)","img":null,"order":516},{"name":"Koji Ishii","character":"Zhang Fei (voice)","img":null,"order":524},{"name":"Naoko Komatsu","character":"Eve (voice)","img":null,"order":525},{"name":"Taisuke Nakano","character":"Huginn (voice)","img":null,"order":531},{"name":"Daiki Hamano","character":"God (voice)","img":null,"order":532},{"name":"Chiko Mizumori","character":"Iori Miyamoto (voice)","img":null,"order":534},{"name":"Tomohiro Yamaguchi","character":"Man (voice)","img":null,"order":535},{"name":"Satoru Ito","character":"Spectator (voice)","img":null,"order":539}],"tv:207332":[{"name":"Tomokazu Sugita","character":"Taro Sakamoto (voice)","img":null,"order":0},{"name":"Nobunaga Shimazaki","character":"Shin Asakura (voice)","img":null,"order":1},{"name":"Ayane Sakura","character":"Lu Shaotang (voice)","img":null,"order":2},{"name":"Nao Toyama","character":"Aoi Sakamoto (voice)","img":null,"order":3},{"name":"Hina Kino","character":"Hana Sakamoto (voice)","img":null,"order":4},{"name":"Ryota Suzuki","character":"Heisuke Mashimo (voice)","img":null,"order":5},{"name":"Natsuki Hanae","character":"Yoichi Nagumo (voice)","img":null,"order":6},{"name":"Taku Yashiro","character":"Shishiba (voice)","img":null,"order":7},{"name":"Saori Hayami","character":"Osaragi (voice)","img":null,"order":8},{"name":"Hiroki Yasumoto","character":"Hyou (voice)","img":null,"order":9},{"name":"Hochu Otsuka","character":"Takamura (voice)","img":null,"order":10},{"name":"Daisuke Namikawa","character":"Kei Uzuki (voice)","img":null,"order":11},{"name":"Nobuhiko Okamoto","character":"Natsuki Seba (voice)","img":null,"order":500},{"name":"Yuhko Kaida","character":"Dump (voice)","img":null,"order":501},{"name":"Ryota Takeuchi","character":"Minimalist (voice)","img":null,"order":502}],"tv:249907":[{"name":"Yohei Azakami","character":"Xylo Forbartz (voice)","img":null,"order":0},{"name":"Mayu Iizuka","character":"Teoritta (voice)","img":null,"order":1},{"name":"Shizuka Ishigami","character":"Patouche Kivia (voice)","img":null,"order":2},{"name":"Shun Horie","character":"Dotta Luzlas (voice)","img":null,"order":3},{"name":"Shunichi Toki","character":"Venetim Leopold (voice)","img":null,"order":4},{"name":"Yoji Ueda","character":"Norgayu Senridge (voice)","img":null,"order":5},{"name":"Yoshitsugu Matsuoka","character":"Tatsuya (voice)","img":null,"order":6},{"name":"Jun Fukushima","character":"Tsav (voice)","img":null,"order":7},{"name":"Shoya Chiba","character":"Jace Pertilact (voice)","img":null,"order":8},{"name":"Yoko Hikasa","character":"Neely (voice)","img":null,"order":9}],"tv:120089":[{"name":"Takuya Eguchi","character":"Loid Forger (voice)","img":null,"order":0},{"name":"Atsumi Tanezaki","character":"Anya Forger (voice)","img":null,"order":1},{"name":"Saori Hayami","character":"Yor Forger (voice)","img":null,"order":2},{"name":"Kenichirou Matsuda","character":"Narration (voice)","img":null,"order":345},{"name":"Emiri Kato","character":"Agent M (voice)","img":null,"order":602},{"name":"Hiroki Goto","character":"Eden College Teacher (voice)","img":null,"order":611},{"name":"Hana Sato","character":"Onboard Announcement (voice)","img":null,"order":618},{"name":"Emiko Takeuchi","character":"Nurse (voice)","img":null,"order":643},{"name":"Mirei Kumagai","character":"Berlint General Hospital Doctor (voice)","img":null,"order":644},{"name":"Shoumaru Zouza","character":"Vides (voice)","img":null,"order":677},{"name":"Yuhko Kaida","character":"Sylvia Sherwood (voice)","img":null,"order":685},{"name":"Marie Ooi","character":"Gram Gretcher (voice)","img":null,"order":687},{"name":"Motoki Sakuma","character":"Wolson (voice)","img":null,"order":689},{"name":"Takaaki Torashima","character":"Secretary (voice)","img":null,"order":690},{"name":"Masafumi Kobatake","character":"Barkeeper (voice)","img":null,"order":694}],"tv:36243":[{"name":"Shintaro Asanuma","character":"'I' (Watashi) (voice)","img":null,"order":0},{"name":"Hiroyuki Yoshino","character":"Ozu (voice)","img":null,"order":1},{"name":"Keiji Fujiwara","character":"Higuchi (voice)","img":null,"order":2},{"name":"Yuhko Kaida","character":"Hanuki (voice)","img":null,"order":4},{"name":"Maaya Sakamoto","character":"Akashi (voice)","img":null,"order":5},{"name":"Junichi Suwabe","character":"Jogasaki (voice)","img":null,"order":6}],"tv:88803":[{"name":"Yuto Uemura","character":"Thorfinn (voice)","img":null,"order":0},{"name":"Naoya Uchida","character":"Askeladd (voice)","img":null,"order":1},{"name":"Shunsuke Takeuchi","character":"Einar (voice)","img":null,"order":2},{"name":"Kensho Ono","character":"Canute (voice)","img":null,"order":3},{"name":"Hiroki Yasumoto","character":"Bjorn (voice)","img":null,"order":4},{"name":"Akio Otsuka","character":"Thorkell (voice)","img":null,"order":5},{"name":"Yusuke Ohta","character":"Guard (voice)","img":null,"order":589},{"name":"Yoshiaki Hasegawa","character":"Scout of Thorkell's Troops (voice)","img":null,"order":596},{"name":"Takayuki Nakatsukasa","character":"Member of Askeladd's Mercenaries (voice)","img":null,"order":631},{"name":"Takuya Nakashima","character":"Retainer (voice)","img":null,"order":639},{"name":"Tsuguo Mogami","character":"Soldier of the English Army (voice)","img":null,"order":644},{"name":"Hiroki Goto","character":"Torgrim (voice)","img":null,"order":657},{"name":"Masato Niwa","character":"Wild Dog (voice)","img":null,"order":660},{"name":"Taito Ban","character":"Merchant (voice)","img":null,"order":662},{"name":"Shinya Takahashi","character":"Thegn (voice)","img":null,"order":678}],"tv:30669":[{"name":"Nozomu Sasaki","character":"Y\u016bsuke Urameshi (voice)","img":null,"order":1},{"name":"Shigeru Chiba","character":"Kazuma Kuwabara (voice)","img":"mF5YJxApTYKBVFJDrEC9IrJ5ooV.jpg","order":2},{"name":"Megumi Ogata","character":"Kurama/Sh\u016bichi Minamino (voice)","img":null,"order":3},{"name":"Nobuyuki Hiyama","character":"Hiei (voice)","img":null,"order":4},{"name":"Yuri Amano","character":"Keiko Yukimura (voice)","img":null,"order":5},{"name":"Hisako Kyoda","character":"Genkai (voice)","img":null,"order":6},{"name":"Mayumi Tanaka","character":"Koenma (voice)","img":null,"order":7},{"name":"Ai Orikasa","character":"Shizuru Kuwabara (voice)","img":null,"order":8},{"name":"Tomomichi Nishimura","character":"Narration (voice)","img":null,"order":10},{"name":"Sanae Miyuki","character":"Botan","img":null,"order":10},{"name":"Yuri Shiratori","character":"Yukina (voice)","img":null,"order":12},{"name":"Katsumi Suzuki","character":"Toguro (voice)","img":null,"order":13},{"name":"Rokuro Naya","character":"Sensui Shinobu (voice)","img":null,"order":14}],"movie:1930":[{"name":"Andrew Garfield","character":"Spider-Man / Peter Parker","img":null,"order":0},{"name":"Emma Stone","character":"Gwen Stacy","img":null,"order":1},{"name":"Rhys Ifans","character":"The Lizard / Dr. Curt Connors","img":null,"order":2},{"name":"Denis Leary","character":"Captain Stacy","img":null,"order":3},{"name":"Martin Sheen","character":"Uncle Ben","img":null,"order":4},{"name":"Sally Field","character":"Aunt May","img":null,"order":5},{"name":"Irrfan Khan","character":"Rajit Ratha","img":null,"order":6},{"name":"Campbell Scott","character":"Richard Parker","img":null,"order":7},{"name":"Embeth Davidtz","character":"Mary Parker","img":null,"order":8},{"name":"Chris Zylka","character":"Flash Thompson","img":null,"order":9},{"name":"Max Charles","character":"Peter Parker (Age 4)","img":null,"order":10},{"name":"C. Thomas Howell","character":"Jack's Father","img":null,"order":11},{"name":"Jake Keiffer","character":"Jack","img":null,"order":12},{"name":"Kari Coleman","character":"Helen Stacy","img":null,"order":13},{"name":"Michael Barra","character":"Store Clerk","img":null,"order":14}],"movie:102382":[{"name":"Andrew Garfield","character":"Spider-Man / Peter Parker","img":null,"order":0},{"name":"Emma Stone","character":"Gwen Stacy","img":null,"order":1},{"name":"Jamie Foxx","character":"Electro / Max Dillon","img":null,"order":2},{"name":"Dane DeHaan","character":"Green Goblin / Harry Osborn","img":null,"order":3},{"name":"Colm Feore","character":"Donald Menken","img":null,"order":4},{"name":"Felicity Jones","character":"Felicia","img":null,"order":5},{"name":"Paul Giamatti","character":"Aleksei Sytsevich","img":null,"order":6},{"name":"Sally Field","character":"Aunt May","img":null,"order":7},{"name":"Embeth Davidtz","character":"Mary Parker","img":null,"order":8},{"name":"Campbell Scott","character":"Richard Parker","img":null,"order":9},{"name":"Marton Csokas","character":"Dr. Ashley Kafka","img":null,"order":10},{"name":"Louis Cancelmi","character":"Man in Black Suit","img":null,"order":11},{"name":"Max Charles","character":"Young Peter Parker","img":null,"order":12},{"name":"B.J. Novak","character":"Allistar Smythe","img":null,"order":13},{"name":"Sarah Gadon","character":"Kari","img":null,"order":14}],"movie:55931":[{"name":"Keanu Reeves","character":"Neo (\"Kid's Story\") (voice)","img":null,"order":0},{"name":"Carrie-Anne Moss","character":"Trinity (\"Kid's Story\" and \"A Detective Story\") (voice)","img":null,"order":1},{"name":"Clayton Watson","character":"The Kid (\"Kid's Story\") (voice)","img":null,"order":2},{"name":"Pamela Adlon","character":"Jue (\"Final Flight of the Osiris\") / Manabu (\"Beyond\") (voice)","img":"5eIRHUbNOH7ibXa0IfUfFvj5I5L.jpg","order":3},{"name":"Melinda Clarke","character":"Alexa (\"Matriculated\") (voice)","img":null,"order":4},{"name":"John DiMaggio","character":"Crew Man (\"Final Flight of the Osiris\") / Kaiser (\"Program\") (voice)","img":null,"order":5},{"name":"Kevin Michael Richardson","character":"Thadeus (\"Final Flight of Osiris\") / Cop (\"Kid's Story\") / Agent #2 (\"World Record\")","img":null,"order":6},{"name":"Tom Kenny","character":"Operator (\"Final Flight of Osiris\")","img":null,"order":7},{"name":"Rick Gomez","character":"Pilot (\"Final Flight of Osiris\")","img":null,"order":8},{"name":"Tara Strong","character":"Crew Woman (\"Final Flight of Osiris\") / Nurse (\"World Record\") / Misha (\"Beyond\")","img":null,"order":9},{"name":"Bette Ford","character":"Old Woman (\"Final Flight of Osiris\")","img":null,"order":10},{"name":"Julia Fletcher","character":"The Instructor (\"The Second Renaissance Part I & II\") / Narrator (\"World Record\")","img":null,"order":11},{"name":"Dane A. Davis","character":"01 Versatran Spokesman (\"The Second Renaissance Part I & II\")","img":null,"order":12},{"name":"Debi Derryberry","character":"Kid (\"The Second Renaissance Part I & II\")","img":null,"order":13},{"name":"Jill Talley","character":"Mother (\"The Second Renaissance Part I & II\")","img":null,"order":14}],"movie:640146":[{"name":"Paul Rudd","character":"Scott Lang / Ant-Man","img":null,"order":0},{"name":"Evangeline Lilly","character":"Hope Van Dyne / The Wasp","img":null,"order":1},{"name":"Michael Douglas","character":"Dr. Hank Pym","img":null,"order":2},{"name":"Michelle Pfeiffer","character":"Janet Van Dyne","img":null,"order":3},{"name":"Jonathan Majors","character":"Kang the Conqueror","img":null,"order":4},{"name":"Kathryn Newton","character":"Cassie Lang","img":null,"order":5},{"name":"Corey Stoll","character":"M.O.D.O.K.","img":null,"order":6},{"name":"Bill Murray","character":"Lord Krylar","img":null,"order":7},{"name":"Katy O'Brian","character":"Jentorra","img":null,"order":8},{"name":"William Jackson Harper","character":"Quaz","img":null,"order":9},{"name":"Jamie Andrew Cutler","character":"Xolum","img":null,"order":10},{"name":"David Dastmalchian","character":"Veb (voice)","img":null,"order":11},{"name":"Randall Park","character":"Jimmy Woo","img":null,"order":12},{"name":"Mark Weinman","character":"Patrol Police Officer / On-Set M.O.D.O.K.","img":null,"order":13},{"name":"Ross Mullan","character":"Axia Restaurant Maitre D'","img":null,"order":14}],"movie:269650":[{"name":"Yuka Komatsu","character":"Deunan Knute (voice)","img":null,"order":0},{"name":"Junichi Suwabe","character":"Briareos Hecatonchires (voice)","img":null,"order":1},{"name":"Aoi Yuki","character":"Iris (voice)","img":null,"order":2},{"name":"Hiroki Takahashi","character":"Olson (voice)","img":null,"order":3},{"name":"Hiroki Touchi","character":"Talos (voice)","img":null,"order":4},{"name":"Kaori Nazuka","character":"Nyx (voice)","img":null,"order":5},{"name":"Tessyo Genda","character":"Two Horns (voice)","img":null,"order":6},{"name":"Katsunosuke Hori","character":"Mathews (voice)","img":null,"order":7},{"name":"Hisanori Yoshida","character":"(voice)","img":null,"order":8},{"name":"Shinichiro Kamio","character":"(voice)","img":null,"order":9},{"name":"Yoshiki Nakajima","character":"(voice)","img":null,"order":10},{"name":"Yuki Yonai","character":"(voice)","img":null,"order":11},{"name":"Mao Satonaka","character":"(voice)","img":null,"order":12}],"movie:572802":[{"name":"Jason Momoa","character":"Arthur","img":null,"order":0},{"name":"Patrick Wilson","character":"Orm","img":null,"order":1},{"name":"Yahya Abdul-Mateen II","character":"Black Manta","img":null,"order":2},{"name":"Randall Park","character":"Dr. Shin","img":null,"order":3},{"name":"Amber Heard","character":"Mera","img":null,"order":4},{"name":"Nicole Kidman","character":"Atlanna","img":null,"order":5},{"name":"Dolph Lundgren","character":"King Nereus","img":null,"order":6},{"name":"Temuera Morrison","character":"Tom","img":null,"order":7},{"name":"Lillah Indya Moore","character":"Karshon","img":null,"order":8},{"name":"Pilou Asb\u00e6k","character":"Kordax","img":null,"order":9},{"name":"Jani Zhao","character":"Stingray","img":null,"order":10},{"name":"Vincent Regan","character":"Atlan","img":null,"order":11},{"name":"Martin Short","character":"Kingfish (voice)","img":null,"order":12},{"name":"John Rhys-Davies","character":"Brine King (voice)","img":null,"order":13},{"name":"Natalia Safran","character":"Council Lady","img":null,"order":14}],"movie:24428":[{"name":"Robert Downey Jr.","character":"Tony Stark / Iron Man","img":null,"order":0},{"name":"Chris Evans","character":"Steve Rogers / Captain America","img":null,"order":1},{"name":"Mark Ruffalo","character":"Bruce Banner / The Hulk","img":null,"order":2},{"name":"Chris Hemsworth","character":"Thor","img":null,"order":3},{"name":"Scarlett Johansson","character":"Natasha Romanoff / Black Widow","img":null,"order":4},{"name":"Jeremy Renner","character":"Clint Barton / Hawkeye","img":null,"order":5},{"name":"Tom Hiddleston","character":"Loki","img":null,"order":6},{"name":"Clark Gregg","character":"Agent Phil Coulson","img":null,"order":7},{"name":"Cobie Smulders","character":"Agent Maria Hill","img":null,"order":8},{"name":"Stellan Skarsg\u00e5rd","character":"Selvig","img":"mW7xmtGV4y79kQGn0zkKVGDMAmw.jpg","order":9},{"name":"Samuel L. Jackson","character":"Nick Fury","img":null,"order":10},{"name":"Gwyneth Paltrow","character":"Pepper Potts","img":null,"order":11},{"name":"Paul Bettany","character":"Jarvis (voice)","img":null,"order":12},{"name":"Alexis Denisof","character":"The Other","img":null,"order":13},{"name":"Tina Benko","character":"NASA Scientist","img":null,"order":14}],"movie:257346":[{"name":"Miyuki Sawashiro","character":"Natasha Romanoff / Black Widow (voice)","img":null,"order":0},{"name":"Tessyo Genda","character":"Frank Castle / The Punisher (voice)","img":null,"order":1},{"name":"Hideaki Tezuka","character":"Nick Fury (voice)","img":null,"order":2},{"name":"Hiroki Touchi","character":"Elihas Starr (voice)","img":null,"order":3},{"name":"Ryuuzaburou Ootomo","character":"Cain (voice)","img":null,"order":4},{"name":"Junko Minagawa","character":"Maria Hill (voice)","img":null,"order":5},{"name":"Daisuke Namikawa","character":"Amadeus Cho (voice)","img":null,"order":6},{"name":"Masashi Sugawara","character":"Orion (voice)","img":null,"order":7},{"name":"Yuichi Karasuma","character":"The Hulk (voice)","img":null,"order":8},{"name":"Hisashi Izumi","character":"Ren (voice)","img":null,"order":9},{"name":"Keiji Fujiwara","character":"Tony Stark / Iron Man (voice)","img":null,"order":10},{"name":"Shuhei Sakaguchi","character":"Clint Barton / Hawkeye (voice)","img":null,"order":11}],"movie:99861":[{"name":"Robert Downey Jr.","character":"Tony Stark / Iron Man","img":null,"order":0},{"name":"Chris Hemsworth","character":"Thor","img":null,"order":1},{"name":"Mark Ruffalo","character":"Bruce Banner / Hulk","img":null,"order":2},{"name":"Chris Evans","character":"Steve Rogers / Captain America","img":null,"order":3},{"name":"Scarlett Johansson","character":"Natasha Romanoff / Black Widow","img":null,"order":4},{"name":"Jeremy Renner","character":"Clint Barton / Hawkeye","img":null,"order":5},{"name":"James Spader","character":"Ultron (voice)","img":null,"order":6},{"name":"Samuel L. Jackson","character":"Nick Fury","img":null,"order":7},{"name":"Don Cheadle","character":"James Rhodes / War Machine","img":null,"order":8},{"name":"Aaron Taylor-Johnson","character":"Pietro Maximoff / Quicksilver","img":null,"order":9},{"name":"Elizabeth Olsen","character":"Wanda Maximoff / Scarlet Witch","img":null,"order":10},{"name":"Paul Bettany","character":"Jarvis / Vision","img":null,"order":11},{"name":"Cobie Smulders","character":"Maria Hill","img":null,"order":12},{"name":"Anthony Mackie","character":"Sam Wilson / The Falcon","img":null,"order":13},{"name":"Hayley Atwell","character":"Peggy Carter","img":null,"order":14}],"movie:299536":[{"name":"Robert Downey Jr.","character":"Tony Stark / Iron Man","img":null,"order":0},{"name":"Chris Evans","character":"Steve Rogers / Captain America","img":null,"order":1},{"name":"Chris Hemsworth","character":"Thor","img":null,"order":2},{"name":"Josh Brolin","character":"Thanos","img":null,"order":3},{"name":"Mark Ruffalo","character":"Bruce Banner / Hulk","img":null,"order":4},{"name":"Scarlett Johansson","character":"Natasha Romanoff / Black Widow","img":null,"order":5},{"name":"Don Cheadle","character":"James Rhodes / War Machine","img":null,"order":6},{"name":"Benedict Cumberbatch","character":"Doctor Strange","img":null,"order":7},{"name":"Tom Holland","character":"Peter Parker / Spider-Man","img":"xKBAaPIa1c7tzZD3Y0MhBLv4hPE.jpg","order":8},{"name":"Chadwick Boseman","character":"T'Challa / Black Panther","img":null,"order":9},{"name":"Zoe Salda\u00f1a","character":"Gamora","img":null,"order":10},{"name":"Karen Gillan","character":"Nebula","img":null,"order":11},{"name":"Tom Hiddleston","character":"Loki","img":null,"order":12},{"name":"Paul Bettany","character":"Vision","img":null,"order":13},{"name":"Elizabeth Olsen","character":"Wanda Maximoff / Scarlet Witch","img":null,"order":14}],"movie:485942":[{"name":"Koichi Yamadera","character":"Batman / Bruce Wayne (voice)","img":"biov5jENp2XYfehkcdnRvi796Wi.jpg","order":0},{"name":"Wataru Takagi","character":"The Joker (voice)","img":null,"order":1},{"name":"Rie Kugimiya","character":"Harley Quinn / Harleen Quinzel (voice)","img":null,"order":2},{"name":"Ai Kakuma","character":"Catwoman / Selina Kyle (voice)","img":null,"order":3},{"name":"Hochu Otsuka","character":"Alfred Pennyworth (voice)","img":null,"order":4},{"name":"Daisuke Ono","character":"Nightwing / Dick Grayson (voice)","img":null,"order":5},{"name":"Akira Ishida","character":"Red Hood / Jason Todd (voice)","img":null,"order":6},{"name":"Kengo Kawanishi","character":"Red Robin / Tim Drake (voice)","img":null,"order":7},{"name":"Yuki Kaji","character":"Robin / Damian Wayne (voice)","img":null,"order":8},{"name":"Junichi Suwabe","character":"Deathstroke / Slade Wilson (voice)","img":null,"order":9},{"name":"Cho","character":"The Penguin / Oswald Cobblepot (voice)","img":null,"order":10},{"name":"Takehito Koyasu","character":"Gorilla Grodd (voice)","img":null,"order":11},{"name":"Toshiyuki Morikawa","character":"Two-Face / Harvey Dent (voice)","img":null,"order":12},{"name":"Atsuko Tanaka","character":"Poison Ivy / Pamela Isley (voice)","img":null,"order":13},{"name":"Kenta Miyake","character":"Bane (voice)","img":null,"order":14}],"movie:209112":[{"name":"Ben Affleck","character":"Bruce Wayne / Batman","img":null,"order":0},{"name":"Henry Cavill","character":"Clark Kent / Superman","img":null,"order":1},{"name":"Jesse Eisenberg","character":"Lex Luthor","img":null,"order":2},{"name":"Gal Gadot","character":"Diana Prince / Wonder Woman","img":null,"order":3},{"name":"Amy Adams","character":"Lois","img":null,"order":4},{"name":"Diane Lane","character":"Martha Kent","img":null,"order":5},{"name":"Laurence Fishburne","character":"Perry White","img":null,"order":6},{"name":"Jeremy Irons","character":"Alfred","img":null,"order":7},{"name":"Holly Hunter","character":"Senator Finch","img":null,"order":8},{"name":"Scoot McNairy","character":"Wallace Keefe","img":null,"order":9},{"name":"Callan Mulvey","character":"Anatoli Knyazev","img":null,"order":10},{"name":"Tao Okamoto","character":"Mercy Graves","img":null,"order":11},{"name":"Brandon Spink","character":"Young Bruce Wayne","img":null,"order":12},{"name":"Lauren Cohan","character":"Martha Wayne","img":null,"order":13},{"name":"Alan D. Purwin","character":"Wayne Industries Pilot","img":null,"order":14}],"movie:123025":[{"name":"Peter Weller","character":"Batman / Bruce Wayne (voice)","img":null,"order":0},{"name":"Ariel Winter","character":"Robin / Carrie Kelley (voice)","img":null,"order":1},{"name":"David Selby","character":"James Gordon (voice)","img":null,"order":2},{"name":"Wade Williams","character":"Harvey Dent / Two-Face (voice)","img":null,"order":3},{"name":"Michael McKean","character":"Dr. Bartholomew Wolper (voice)","img":null,"order":4},{"name":"Rob Paulsen","character":"Jeff Adams (voice)","img":null,"order":5},{"name":"Gary Anthony Williams","character":"Mutant Leader / Anchor Bill (voice)","img":null,"order":6},{"name":"Gary Anthony Sturgis","character":"Silk / Other Spike / Young Mutant (voice)","img":null,"order":7},{"name":"Paget Brewster","character":"Lana Lang (voice)","img":null,"order":8},{"name":"Carlos Alazraqui","character":"Hernando / TV Host (voice)","img":null,"order":9},{"name":"Dee Bradley Baker","character":"Don / Fat Mutant / Additional Voices (voice)","img":null,"order":10},{"name":"Maria Canals-Barrera","character":"Yindel (voice)","img":null,"order":11},{"name":"Cathy Cavadini","character":"Joanie / Woman with Hot Dog (voice)","img":null,"order":12},{"name":"Townsend Coleman","character":"Morrie / Civilian (voice)","img":null,"order":13},{"name":"Grey DeLisle","character":"Anchor Carla / Female Mutant (voice)","img":null,"order":14}],"movie:436270":[{"name":"Dwayne Johnson","character":"Black Adam / Teth Adam","img":null,"order":0},{"name":"Aldis Hodge","character":"Hawkman / Carter Hall","img":null,"order":1},{"name":"Noah Centineo","character":"Atom Smasher / Al Rothstein","img":null,"order":2},{"name":"Sarah Shahi","character":"Adrianna Tomaz","img":null,"order":3},{"name":"Quintessa Swindell","character":"Cyclone / Maxine Hunkel","img":null,"order":4},{"name":"Marwan Kenzari","character":"Ishmael / Sabbac / King Ahk-Ton","img":null,"order":5},{"name":"Mo Amer","character":"Karim","img":null,"order":6},{"name":"Bodhi Sabongui","character":"Amon Tomaz","img":null,"order":7},{"name":"Pierce Brosnan","character":"Dr. Fate / Kent Nelson","img":null,"order":8},{"name":"James Cusati-Moyer","character":"Samir","img":null,"order":9},{"name":"Jalon Christian","character":"Hurut","img":null,"order":10},{"name":"Benjamin Patterson","character":"Skinny Teth Adam","img":null,"order":11},{"name":"Odelya Halevi","character":"Shiruta","img":null,"order":12},{"name":"Uli Latukefu","character":"The Champion","img":null,"order":13},{"name":"Jennifer Holland","character":"Emilia Harcourt","img":null,"order":14}],"movie:284054":[{"name":"Chadwick Boseman","character":"T'Challa / Black Panther","img":null,"order":0},{"name":"Michael B. Jordan","character":"Erik Killmonger","img":null,"order":1},{"name":"Lupita Nyong'o","character":"Nakia","img":null,"order":2},{"name":"Danai Gurira","character":"Okoye","img":null,"order":3},{"name":"Martin Freeman","character":"Everett K. Ross","img":null,"order":4},{"name":"Daniel Kaluuya","character":"W'Kabi","img":null,"order":5},{"name":"Letitia Wright","character":"Shuri","img":null,"order":6},{"name":"Winston Duke","character":"M'Baku","img":null,"order":7},{"name":"Sterling K. Brown","character":"N'Jobu","img":null,"order":8},{"name":"Angela Bassett","character":"Ramonda","img":null,"order":9},{"name":"Forest Whitaker","character":"Zuri","img":null,"order":10},{"name":"Andy Serkis","character":"Ulysses Klaue","img":null,"order":11},{"name":"Florence Kasumba","character":"Ayo","img":null,"order":12},{"name":"John Kani","character":"T'Chaka","img":null,"order":13},{"name":"David S. Lee","character":"Limbani","img":null,"order":14}],"movie:505642":[{"name":"Letitia Wright","character":"Shuri","img":null,"order":0},{"name":"Tenoch Huerta Mej\u00eda","character":"Namor","img":null,"order":1},{"name":"Lupita Nyong'o","character":"Nakia","img":null,"order":2},{"name":"Danai Gurira","character":"Okoye","img":null,"order":3},{"name":"Winston Duke","character":"M'Baku","img":null,"order":4},{"name":"Angela Bassett","character":"Ramonda","img":null,"order":5},{"name":"Martin Freeman","character":"Everett Ross","img":null,"order":6},{"name":"Julia Louis-Dreyfus","character":"Valentina Allegra de Fontaine","img":null,"order":7},{"name":"Dominique Thorne","character":"Riri","img":null,"order":8},{"name":"Florence Kasumba","character":"Ayo","img":null,"order":9},{"name":"Michaela Coel","character":"Aneka","img":null,"order":10},{"name":"Alex Livinalli","character":"Attuma","img":null,"order":11},{"name":"Mabel Cadena","character":"Namora","img":null,"order":12},{"name":"Michael B. Jordan","character":"Killmonger","img":null,"order":13},{"name":"Isaach de Bankol\u00e9","character":"River Tribe Elder","img":null,"order":14}],"movie:409421":[{"name":"Takahiro Sakurai","character":"Killy (voice)","img":null,"order":0},{"name":"Kana Hanazawa","character":"Cibo (voice)","img":null,"order":1},{"name":"Sora Amamiya","character":"Zuru (voice)","img":null,"order":2},{"name":"Mamoru Miyano","character":"Sutezo (voice)","img":null,"order":3},{"name":"Aya Suzaki","character":"Tae (voice)","img":null,"order":4},{"name":"Nobunaga Shimazaki","character":"Fusata (voice)","img":null,"order":5},{"name":"Nanako Mori","character":"Fuku (voice)","img":null,"order":6},{"name":"Kazuhiro Yamaji","character":"Pop (voice)","img":null,"order":7}],"movie:17165":[{"name":"Masakazu Morita","character":"Ichigo Kurosaki (voice)","img":null,"order":0},{"name":"Fumiko Orikasa","character":"Rukia Kuchiki (voice)","img":null,"order":1},{"name":"Kentaro Ito","character":"Renji Abarai (voice)","img":null,"order":2},{"name":"Aya Hirano","character":"Homura (voice)","img":null,"order":3},{"name":"Hiroshi Kamiya","character":"Shizuku (voice)","img":null,"order":4},{"name":"Mitsuaki Madono","character":"Kon (voice)","img":null,"order":5},{"name":"Jun Fukuyama","character":"Yumichika Ayasegawa (voice)","img":null,"order":6},{"name":"Taro Yamaguchi","character":"Sasakibe Choujiro (voice)","img":null,"order":7},{"name":"Takako Honda","character":"Jinta Hanakari (voice)","img":null,"order":8},{"name":"Katsuyuki Konishi","character":"Shuuhei Hisagi (voice)","img":null,"order":9},{"name":"Rintaro Nishi","character":"Tetsuzaemon Iba (voice)","img":null,"order":10},{"name":"Tetsu Inada","character":"Sajin Komamura (voice)","img":null,"order":11},{"name":"Fumiko Orikasa","character":"Hisana Kuchiki (voice)","img":null,"order":12},{"name":"Rie Kugimiya","character":"Nemu Kurotsuchi (voice)","img":null,"order":13},{"name":"Hisayo Mochizuki","character":"Yachiru Kusajishi (voice)","img":null,"order":14}],"tv:73319":[{"name":"Ed Brown","character":"Self","img":null,"order":0},{"name":"Rosemarie Vega","character":"Self","img":null,"order":1},{"name":"Angela Deem","character":"Self","img":null,"order":2},{"name":"Michael Ilesanmi","character":"Self","img":null,"order":3}],"tv:90046":[],"tv:48866":[{"name":"Eliza Taylor","character":"Clarke Griffin","img":null,"order":0},{"name":"Bob Morley","character":"Bellamy Blake","img":null,"order":1},{"name":"Lindsey Morgan","character":"Raven Reyes","img":null,"order":2},{"name":"Marie Avgeropoulos","character":"Octavia Blake","img":null,"order":3},{"name":"Richard Harmon","character":"John Murphy","img":null,"order":5},{"name":"Luisa d'Oliveira","character":"Emori","img":null,"order":7},{"name":"Christopher Larkin","character":"Monty Green","img":null,"order":9},{"name":"Tati Gabrielle","character":"Gaia","img":null,"order":11},{"name":"Devon Bostick","character":"Jasper Jordan","img":null,"order":13},{"name":"Isaiah Washington","character":"Thelonious Jaha","img":null,"order":15},{"name":"Henry Ian Cusick","character":"Marcus Kane","img":null,"order":16},{"name":"Adina Porter","character":"Indra","img":null,"order":20},{"name":"Jarod Joseph","character":"Nathan Miller","img":null,"order":21},{"name":"Ricky Whittle","character":"Lincoln","img":null,"order":25},{"name":"Paige Turco","character":"Judge","img":null,"order":102}],"tv:11821":[{"name":"Bud Abbott","character":"Bud Abbott","img":null,"order":0},{"name":"Lou Costello","character":"Lou Costello","img":null,"order":1},{"name":"Joe Besser","character":"Stinky Davis","img":null,"order":500},{"name":"Hillary Brooke","character":"Hillary Brooke","img":null,"order":539},{"name":"Gordon Jones","character":"Mike Kelly","img":null,"order":540},{"name":"Sid Fields","character":"Sid Fields","img":null,"order":561},{"name":"Joe Kirk","character":"Mr. Bacciagalupe","img":null,"order":567},{"name":"Murray Leonard","character":"Doctor","img":null,"order":587},{"name":"Bobby Barber","character":"Tout","img":null,"order":614},{"name":"Joan Shawlee","character":"Marriage License Bureau Clerk","img":null,"order":634},{"name":"Dorothy Granger","character":"Arguing Wife","img":null,"order":642},{"name":"Milt Bronson","character":"Sam Speedy","img":null,"order":646},{"name":"Ray Walker","character":"Police Lt. Smith","img":null,"order":653},{"name":"Lucien Littlefield","character":"First Man","img":null,"order":658},{"name":"Veda Ann Borg","character":"Crazy Lady","img":null,"order":663}],"tv:43167":[{"name":"Yuki Kaji","character":"Arita Haruyuki","img":null,"order":0},{"name":"Sachika Misawa","character":"Kuroyuki-hime","img":null,"order":1},{"name":"Ayako Kawasumi","character":"Kakei Mihaya","img":null,"order":2},{"name":"Kenichi Suzumura","character":"Ash Roller","img":null,"order":3},{"name":"Aki Toyosaki","character":"Kurashima Chiyuri","img":null,"order":4},{"name":"Shintaro Asanuma","character":"Mayuzumi Takumu","img":null,"order":5},{"name":"Sanae Kobayashi","character":"Noumi Seiji","img":null,"order":6},{"name":"Rina Hidaka","character":"Kouzuki Yuniko","img":null,"order":7},{"name":"Haruka Tomatsu","character":"Wakamiya Megumi","img":null,"order":8}],"tv:114461":[{"name":"Rosario Dawson","character":"Ahsoka Tano","img":null,"order":0},{"name":"Natasha Liu Bordizzo","character":"Sabine Wren","img":null,"order":1},{"name":"Ivanna Sakhno","character":"Shin Hati","img":null,"order":2},{"name":"Ray Stevenson","character":"Baylan Skoll","img":null,"order":2},{"name":"Mary Elizabeth Winstead","character":"Hera Syndulla","img":null,"order":3},{"name":"Lars Mikkelsen","character":"Grand Admiral Thrawn","img":null,"order":4},{"name":"Eman Esfandi","character":"Ezra Bridger","img":null,"order":5},{"name":"Diana Lee Inosanto","character":"Morgan Elsbeth","img":null,"order":5},{"name":"Rory McCann","character":"Baylan Skoll","img":null,"order":6},{"name":"David Tennant","character":"Huyang (voice)","img":null,"order":6},{"name":"Hayden Christensen","character":"Anakin Skywalker","img":null,"order":7},{"name":"Paul Darnell","character":"Marrok","img":null,"order":512},{"name":"Chris Bartlett","character":"Home One Protocol Droid","img":null,"order":519},{"name":"Nican Robinson","character":"First Officer Vic Hawkins","img":null,"order":526},{"name":"Dawn Dininger","character":"Lieutenant Beyta","img":null,"order":546}],"tv:1433":[{"name":"Seth MacFarlane","character":"Stan Smith / Roger (voice)","img":null,"order":0},{"name":"Wendy Schaal","character":"Francine Smith (voice)","img":null,"order":1},{"name":"Rachael MacFarlane","character":"Hayley Smith (voice)","img":null,"order":2},{"name":"Scott Grimes","character":"Steve Smith (voice)","img":null,"order":3},{"name":"Dee Bradley Baker","character":"Klaus (voice)","img":null,"order":4},{"name":"Jeff Fischer","character":"Kidnapper (voice)","img":null,"order":204},{"name":"Mike Barker","character":"Terry Bates / Researcher (voice)","img":null,"order":1590},{"name":"Kevin Michael Richardson","character":"Rerun (voice)","img":null,"order":1824},{"name":"Mike Henry","character":"Jackson / Maitre D' (voice)","img":null,"order":1927},{"name":"Eddie Kaye Thomas","character":"Barry Robinson / Spike (voice)","img":null,"order":1967},{"name":"Patrick Stewart","character":"Avery Bullock as B (voice)","img":null,"order":2007},{"name":"Curtis Armstrong","character":"","img":null,"order":2028},{"name":"David Koechner","character":"Dick Reynolds (voice)","img":null,"order":2052},{"name":"Daisuke Suzuki","character":"Toshi Yoshida (voice)","img":null,"order":2054},{"name":"Richard Kind","character":"Car Salesman (voice)","img":null,"order":2057}],"tv:46639":[{"name":"Ricky Whittle","character":"Shadow Moon","img":null,"order":0},{"name":"Ian McShane","character":"Mr. Wednesday / God Odin","img":null,"order":1},{"name":"Emily Browning","character":"Laura Moon","img":null,"order":2},{"name":"Pablo Schreiber","character":"Mad Sweeney","img":null,"order":3},{"name":"Yetide Badaki","character":"Bilquis","img":null,"order":4},{"name":"Crispin Glover","character":"Mr. World","img":null,"order":5},{"name":"Bruce Langley","character":"Technical Boy","img":null,"order":6},{"name":"Omid Abtahi","character":"Salim","img":null,"order":7},{"name":"Kenzie Delo","character":"Herman","img":null,"order":9},{"name":"Demore Barnes","character":"Mr. Ibis","img":null,"order":611},{"name":"Herizen F. Guardiola","character":"Oshun","img":null,"order":612},{"name":"Peter Stormare","character":"Czernobog","img":null,"order":619},{"name":"Julia Sweeney","character":"Ann-Marie Hinzelmann","img":null,"order":620},{"name":"Eric Johnson","character":"Chad Mulligan","img":null,"order":621},{"name":"Lela Loren","character":"Marguerite Olsen","img":null,"order":624}],"tv:2985":[{"name":"Kevin Sorbo","character":"Dylan Hunt","img":null,"order":0},{"name":"Lisa Ryder","character":"Beka Valentine","img":null,"order":1},{"name":"Laura Bertram","character":"Trance Gemini","img":null,"order":2},{"name":"Gordon Michael Woolvett","character":"Seamus Harper","img":null,"order":3},{"name":"Lexa Doig","character":"Andromeda Ascendant","img":null,"order":4},{"name":"Brandy Ledford","character":"Doyle","img":null,"order":5},{"name":"Keith Hamilton Cobb","character":"Tyr Anasazi","img":null,"order":6},{"name":"Brent Stait","character":"Rev Bem","img":null,"order":7},{"name":"Steve Bacic","character":"Gaheris Rhade","img":null,"order":424},{"name":"Rik Kiviaho","character":"High Guard Captain Perim","img":null,"order":666},{"name":"Janyse Jaud","character":"Cavava (voice)","img":null,"order":677},{"name":"Robert Saunders","character":"Spirit of the Abyss","img":null,"order":689},{"name":"Jim Byrnes","character":"Virgil Vox","img":null,"order":775},{"name":"Nicholas Lea","character":"Tri-Lorn","img":null,"order":777},{"name":"Carmen Moore","character":"Tri-Jema","img":null,"order":813}],"tv:251":[{"name":"Dana Snyder","character":"Master Shake (voice)","img":null,"order":0},{"name":"Carey Means","character":"Frylock (voice)","img":null,"order":1},{"name":"Dave Willis","character":"Meatwad / Carl (voice)","img":null,"order":3},{"name":"Mike Schatz","character":"Emory (voice)","img":null,"order":6},{"name":"Andy Merrill","character":"Oglethorpe / Merle (voice)","img":null,"order":145},{"name":"Schoolly D","character":"Boost Mobile Phone (voice)","img":null,"order":333},{"name":"Matt Maiellaro","character":"Err / Cybernetic Ghost of Christmas Past (voice)","img":null,"order":396},{"name":"C. Martin Croker","character":"Birds (voice)","img":null,"order":455},{"name":"H. Jon Benjamin","character":"Don Shake","img":null,"order":576},{"name":"MC Chris","character":"Little Brittle (voice)","img":null,"order":617},{"name":"George Lowe","character":"George Lowe (voice)","img":null,"order":642},{"name":"Scott Hilley","character":"George Washington (voice)","img":null,"order":642},{"name":"Eugene Mirman","character":"Dr. Eugene Mirman (voice)","img":null,"order":660},{"name":"Edward Hastings","character":"Panda Furry (voice)","img":null,"order":661},{"name":"Nick Ingkatanuwat","character":"Tour Guide (voice)","img":null,"order":670}],"tv:86034":[{"name":"Toshinari Fukamachi","character":"Hajime Nagumo (voice)","img":null,"order":0},{"name":"Yuuki Kuwahara","character":"Yue (voice)","img":null,"order":1},{"name":"Minami Takahashi","character":"Shea Haulia (voice)","img":null,"order":2},{"name":"Yoko Hikasa","character":"Tio Klarus (voice)","img":null,"order":3},{"name":"Saori Onishi","character":"Kaori Shirasaki (voice)","img":null,"order":4},{"name":"Yumiri Hanamori","character":"Shizuku Yaegashi (voice)","img":null,"order":5},{"name":"Ai Kakuma","character":"Aiko Hatayama (voice)","img":null,"order":6},{"name":"Yui Ogura","character":"Myu (voice)","img":null,"order":7},{"name":"Noriko Shibasaki","character":"Liliana S. B. Heiligh (voice)","img":null,"order":8},{"name":"Katsuyuki Konishi","character":"Freid Bagwa (voice)","img":null,"order":10},{"name":"Makoto Ishii","character":"Mikhail (voice)","img":null,"order":11},{"name":"Hiroshi Watanabe","character":"Haulia Yao (voice)","img":null,"order":12},{"name":"Rina Sato","character":"Nun (voice)","img":null,"order":269},{"name":"Tetsuya Kakihara","character":"K\u014dki Amanogawa (voice)","img":null,"order":563},{"name":"Yasuhiro Mamiya","character":"Meld Loggins (voice)","img":null,"order":564}],"tv:1412":[{"name":"Stephen Amell","character":"Oliver Queen / Green Arrow","img":null,"order":0},{"name":"David Ramsey","character":"John Diggle / Spartan","img":null,"order":1},{"name":"Rick Gonzalez","character":"Rene Ramirez / Wild Dog","img":null,"order":4},{"name":"Susanna Thompson","character":"Moira Queen","img":null,"order":5},{"name":"Emily Bett Rickards","character":"Felicity Smoak","img":null,"order":13},{"name":"Paul Blackthorne","character":"Quentin Lance","img":null,"order":14},{"name":"Colton Haynes","character":"Roy Harper / Arsenal","img":null,"order":19},{"name":"John Barrowman","character":"Malcolm Merlyn","img":null,"order":26},{"name":"Echo Kellum","character":"Curtis Holt","img":null,"order":27},{"name":"Katie Cassidy","character":"Black Siren","img":null,"order":34},{"name":"Willa Holland","character":"Thea Queen / Speedy","img":null,"order":96},{"name":"Juliana Harkavy","character":"Dinah Drake / Black Canary","img":null,"order":223},{"name":"Manu Bennett","character":"Slade Wilson / Deathstroke","img":null,"order":279},{"name":"Audrey Marie Anderson","character":"Lyla Michaels","img":null,"order":1444},{"name":"Keri Adams","character":"Bethany Snow","img":null,"order":1589}],"tv:82452":[{"name":"Gordon Cormier","character":"Aang","img":null,"order":0},{"name":"Kiawentiio","character":"Katara","img":null,"order":1},{"name":"Ian Ousley","character":"Sokka","img":null,"order":2},{"name":"Dallas Liu","character":"Zuko","img":null,"order":3},{"name":"Paul Sun-Hyung Lee","character":"Uncle Iroh","img":null,"order":4},{"name":"Miyako","character":"Toph Beifong","img":null,"order":5},{"name":"Ken Leung","character":"Commander Zhao","img":null,"order":6},{"name":"Daniel Dae Kim","character":"Fire Lord Ozai","img":null,"order":7},{"name":"Ruy Iskandar","character":"Lieutenant Jee","img":null,"order":504},{"name":"Maria Zhang","character":"Suki","img":null,"order":523},{"name":"Thalia Tran","character":"Mai","img":null,"order":532},{"name":"Momona Tamada","character":"Ty Lee","img":null,"order":533},{"name":"Matthew Yang King","character":"Appa/Momo(voice)","img":null,"order":568},{"name":"Elizabeth Yu","character":"Azula","img":null,"order":575},{"name":"Dee Bradley Baker","character":"Appa/Momo(voice)","img":null,"order":629}],"tv:284833":[{"name":"Saheli Khan","character":"Pavi (voice)","img":null,"order":0},{"name":"Aishwarya 'Aishu' Devan","character":"Nisha (voice)","img":null,"order":1},{"name":"Major Curda","character":"Jae (voice)","img":null,"order":2},{"name":"Akshay Khanna","character":"Karthik (voice)","img":null,"order":3},{"name":"Sakina Jaffrey","character":"Agam (voice)","img":null,"order":4},{"name":"Eric Bauza","character":"Jin-woo / Pich / One Guy in the Crowd / Crowd / Airbenders / Firebenders (voice)","img":null,"order":502},{"name":"Tobit Raphael","character":"Ulan / Bending Cadet #1 / Bending Cadets (voice)","img":null,"order":509},{"name":"Dee Bradley Baker","character":"Geet / Ruhi (voice)","img":null,"order":510},{"name":"Darren Barnet","character":"Daemin (voice)","img":null,"order":511},{"name":"Clyde Kusatsu","character":"Commander Bountan / Crowd / Airbenders / Firebenders (voice)","img":null,"order":513},{"name":"Sarah Anne","character":"Fang / Bending Cadet #5 / Elloran Girl (voice)","img":null,"order":514},{"name":"Brycen Taylor Hall","character":"Ping (voice)","img":null,"order":515},{"name":"Xanthe Huynh","character":"Lan / Elloran Citizens (voice)","img":null,"order":516},{"name":"Kimberly Woods","character":"Lucky Cadet / Bending Cadet #2 / Bending Cadets (voice)","img":null,"order":519},{"name":"Zehra Fazal","character":"Bending Cadet #3 / Bending Cadet #4 / Masked Elloran Woman (voice)","img":null,"order":519}],"tv:15804":[{"name":"Diedrich Bader","character":"Batman (voice)","img":null,"order":0},{"name":"James Arnold Taylor","character":"Green Arrow / Jace (voice)","img":null,"order":523},{"name":"John DiMaggio","character":"Aquaman / Mr. Freeze (voice)","img":null,"order":549},{"name":"Jeff Bennett","character":"Buddy / OMAC (voice)","img":null,"order":553},{"name":"Tara Strong","character":"Mary/Billy Batson (voice)","img":null,"order":606},{"name":"Jason Marsden","character":"Scooby-Doo Robin (voice)","img":null,"order":628},{"name":"Tom Kenny","character":"Babyface / Plastic Man (voice)","img":null,"order":648},{"name":"Dee Bradley Baker","character":"Felix Faust / Fluke (voice)","img":null,"order":665},{"name":"Kevin Michael Richardson","character":"Lex Luthor (voice)","img":null,"order":667},{"name":"Greg Ellis","character":"Cavalier / Computer Voice / Nuclear Engineer (voice)","img":null,"order":673},{"name":"Corey Burton","character":"Silver Cyclone (voice)","img":null,"order":682},{"name":"Nicholas Guest","character":"Question (voice)","img":null,"order":722},{"name":"Will Friedle","character":"Blue Beetle (voice)","img":null,"order":733},{"name":"Grey DeLisle","character":"Daphne (voice)","img":null,"order":736},{"name":"Tom Everett Scott","character":"Booster Gold (voice)","img":null,"order":759}],"tv:89247":[{"name":"Ruby Rose","character":"Kate Kane / Batwoman","img":null,"order":1},{"name":"Javicia Leslie","character":"Ryan Wilder / Batwoman","img":null,"order":2},{"name":"Rachel Skarsten","character":"Alice / Beth Kane","img":null,"order":3},{"name":"Meagan Tandy","character":"Sophie Moore","img":null,"order":4},{"name":"Nicole Kang","character":"Mary Hamilton","img":null,"order":5},{"name":"Camrus Johnson","character":"Luke Fox","img":null,"order":6},{"name":"Dougray Scott","character":"Jacob Kane","img":null,"order":7},{"name":"Nick Creegan","character":"Marquis Jet","img":null,"order":8},{"name":"Robin Givens","character":"Jada Jet","img":null,"order":9},{"name":"Elizabeth Anweis","character":"Catherine Hamilton-Kane","img":null,"order":10},{"name":"Christina Wolfe","character":"Julia Pennyworth","img":null,"order":679},{"name":"Rachel Maddow","character":"Vesper Fairchild (voice)","img":null,"order":836},{"name":"Sam Littlefield","character":"Mouse","img":null,"order":841},{"name":"Nathan Owens","character":"Ocean","img":null,"order":842},{"name":"Allison Riley","character":"Dana Dewitt","img":null,"order":859}],"tv:74204":[{"name":"Nick Kroll","character":"Nick Birch / Maury the Hormone Monster / Coach Steve / Lola Skumpy / Rick the Hormone Monster (voice)","img":null,"order":0},{"name":"John Mulaney","character":"Andrew Glouberman (voice)","img":null,"order":1},{"name":"Jessi Klein","character":"Jessi Glaser (voice)","img":null,"order":2},{"name":"Jason Mantzoukas","character":"Jay Bilzerian (voice)","img":null,"order":4},{"name":"Maya Rudolph","character":"Diane Birch / Connie the Hormone Monstress (voice)","img":null,"order":5},{"name":"Fred Armisen","character":"Elliot Birch (voice)","img":null,"order":6},{"name":"Jordan Peele","character":"Ghost of Duke Ellington (voice)","img":null,"order":7},{"name":"Ayo Edebiri","character":"Missy Foreman-Greenwald (voice)","img":null,"order":91},{"name":"Andrew Rannells","character":"Leander / Matthew MacDell (voice)","img":null,"order":136},{"name":"Jenny Slate","character":"Pharmacist / Caitlin (voice)","img":null,"order":149},{"name":"Joe Wengert","character":"Caleb / Go-Gurt Thief / Teacher (voice)","img":null,"order":578},{"name":"Paula Pell","character":"(voice)","img":null,"order":622},{"name":"Neil Casey","character":"Detective Dumont (voice)","img":null,"order":624},{"name":"June Diane Raphael","character":"","img":null,"order":639},{"name":"Richard Kind","character":"","img":null,"order":674}],"tv:71663":[{"name":"Cress Williams","character":"Jefferson Pierce / Black Lightning","img":null,"order":0},{"name":"Nafessa Williams","character":"Anissa Pierce / Thunder / Blackbird","img":null,"order":1},{"name":"China Anne McClain","character":"Jennifer Pierce / Lightning","img":null,"order":2},{"name":"Christine Adams","character":"Lynn Pierce","img":null,"order":3},{"name":"Marvin Jones III","character":"Tobias Whale","img":null,"order":4},{"name":"James Remar","character":"Peter Gambi","img":null,"order":5},{"name":"Jordan Calloway","character":"Khalil Payne / Painkiller","img":null,"order":6},{"name":"Chantal Thuy","character":"Grace Choi","img":null,"order":7},{"name":"Damon Gupton","character":"Bill Henderson (voice)","img":null,"order":211},{"name":"Clifton Powell","character":"Reverend Jeremiah Holt","img":null,"order":730},{"name":"Bill Duke","character":"Agent Percy Odell","img":null,"order":801},{"name":"Jennifer Riker","character":"Dr. Helga Jace","img":null,"order":802},{"name":"Christopher Ammanuel","character":"Baron / TC","img":null,"order":818},{"name":"William Catlett","character":"Latavious 'Lala' Johnson","img":null,"order":853},{"name":"Jahking Guillory","character":"Brandon","img":null,"order":855}],"movie:1574":[{"name":"Ren\u00e9e Zellweger","character":"Roxie Hart","img":null,"order":0},{"name":"Catherine Zeta-Jones","character":"Velma Kelly","img":null,"order":1},{"name":"Richard Gere","character":"Billy Flynn","img":null,"order":2},{"name":"Queen Latifah","character":"Matron Mama Morton","img":null,"order":3},{"name":"John C. Reilly","character":"Amos Hart","img":null,"order":4},{"name":"Colm Feore","character":"Harrison","img":null,"order":5},{"name":"Dominic West","character":"Fred Casely","img":null,"order":6},{"name":"Christine Baranski","character":"Mary Sunshine","img":null,"order":7},{"name":"Ekaterina Chtchelkanova","character":"Katalin Helinski \"Hunyak\"","img":null,"order":8},{"name":"Lucy Liu","character":"Kitty Baxter","img":null,"order":9},{"name":"Taye Diggs","character":"Bandleader","img":null,"order":10},{"name":"Mya","character":"Mona","img":null,"order":11},{"name":"Deidre Goodwin","character":"June","img":null,"order":12},{"name":"Denise Faye","character":"Annie","img":null,"order":13},{"name":"Susan Misner","character":"Liz","img":null,"order":14}],"movie:220289":[{"name":"Emily Baldoni","character":"Em","img":null,"order":0},{"name":"Maury Sterling","character":"Kevin","img":null,"order":1},{"name":"Nicholas Brendon","character":"Mike","img":null,"order":2},{"name":"Lauren Maher","character":"Laurie","img":null,"order":3},{"name":"Elizabeth Gracen","character":"Beth","img":null,"order":4},{"name":"Hugo Armstrong","character":"Hugh","img":null,"order":5},{"name":"Lorene Scafaria","character":"Lee","img":null,"order":6},{"name":"Alex Manugian","character":"Amir","img":null,"order":7},{"name":"Kelly Donovan","character":"Extra","img":null,"order":8},{"name":"Aqueela Zoll","character":"Extra","img":null,"order":9},{"name":"Mark Ballou","character":"Extra","img":null,"order":10},{"name":"Alexis Boozer Sterling","character":"Extra","img":null,"order":11}],"movie:399057":[{"name":"Colin Farrell","character":"Steven Murphy","img":null,"order":0},{"name":"Nicole Kidman","character":"Anna Murphy","img":null,"order":1},{"name":"Barry Keoghan","character":"Martin Lang","img":null,"order":2},{"name":"Raffey Cassidy","character":"Kim Murphy","img":null,"order":3},{"name":"Sunny Suljic","character":"Bob Murphy","img":null,"order":4},{"name":"Bill Camp","character":"Matthew Williams","img":null,"order":5},{"name":"Alicia Silverstone","character":"Martin's Mother","img":null,"order":6},{"name":"Herb Caillouet","character":"Ed Thompson (Hospital Director)","img":null,"order":7},{"name":"Barry G. Bernson","character":"Dr. Larry Banks","img":null,"order":8},{"name":"Denise Dal Vera","character":"Mary Williams","img":null,"order":9},{"name":"Drew Logan","character":"Principal","img":null,"order":10},{"name":"Michael Trester","character":"Elderly Man","img":null,"order":11},{"name":"Anita Farmer Bergman","character":"Nurse (uncredited)","img":null,"order":12},{"name":"Lea Hutton Beasmore","character":"Conference Guest (uncredited)","img":null,"order":13},{"name":"Dylan Keith Adams","character":"Doctor at Conference and Event Dinner (uncredited)","img":null,"order":14}],"movie:430214":[{"name":"Gen Hoshino","character":"Senpai (voice)","img":null,"order":0},{"name":"Kana Hanazawa","character":"The Girl with Black Hair (voice)","img":null,"order":1},{"name":"Ami Koshimizu","character":"Naoko (voice)","img":null,"order":2},{"name":"Aoi Yuki","character":"Princess Daruma (voice)","img":null,"order":3},{"name":"Hiroshi Kamiya","character":"Director of School Festival Operations (voice)","img":null,"order":4},{"name":"Chikara Honda","character":"Bookstore Shopkeeper Gabi (voice)","img":null,"order":5},{"name":"Hiroyuki Yoshino","character":"God of the Old Books Market (voice)","img":null,"order":6},{"name":"Junichi Suwabe","character":"Nise-J\u014dgasaki (voice)","img":null,"order":7},{"name":"Kazuhiro Yamaji","character":"Todo (voice)","img":null,"order":8},{"name":"Kazuya Nakai","character":"Seitar\u014d Higuchi (voice)","img":null,"order":9},{"name":"Mugihito","character":"Ri Haku (voice)","img":null,"order":10},{"name":"Nobuyuki Hiyama","character":"Johnny (voice)","img":null,"order":11},{"name":"Ryuji Akiyama","character":"Don Underwear (voice)","img":null,"order":12},{"name":"Seiko Niizuma","character":"Kiko (voice)","img":null,"order":13},{"name":"S\u014dichi Nakaoka","character":"K\u014dsaka (voice)","img":null,"order":14}],"movie:1541":[{"name":"Susan Sarandon","character":"Louise","img":null,"order":0},{"name":"Geena Davis","character":"Thelma","img":null,"order":1},{"name":"Harvey Keitel","character":"Hal","img":null,"order":2},{"name":"Michael Madsen","character":"Jimmy","img":null,"order":3},{"name":"Christopher McDonald","character":"Darryl","img":null,"order":4},{"name":"Stephen Tobolowsky","character":"Max","img":"uL8yfcm0dCFYFQt052kczVQVvac.jpg","order":5},{"name":"Brad Pitt","character":"J.D.","img":null,"order":6},{"name":"Timothy Carhart","character":"Harlan","img":null,"order":7},{"name":"Lucinda Jenney","character":"Lena, the Waitress","img":null,"order":8},{"name":"Jason Beghe","character":"State Trooper","img":"hrTwOPWek7nkPJgFhh6inFu7vSS.jpg","order":9},{"name":"Sonny Carl Davis","character":"Albert","img":null,"order":10},{"name":"Ken Swofford","character":"Major","img":null,"order":11},{"name":"Shelly Desai","character":"East Indian Motel Clerk","img":null,"order":12},{"name":"Carol Mansell","character":"Waitress","img":null,"order":13},{"name":"Stephen Polk","character":"Surveilance Man","img":null,"order":14}],"movie:5038":[{"name":"Scarlett Johansson","character":"Cristina","img":null,"order":0},{"name":"Rebecca Hall","character":"Vicky","img":null,"order":1},{"name":"Javier Bardem","character":"Juan Antonio Gonzalo","img":null,"order":2},{"name":"Pen\u00e9lope Cruz","character":"Mar\u00eda Elena","img":null,"order":3},{"name":"Christopher Evan Welch","character":"Narrator (voice)","img":null,"order":4},{"name":"Chris Messina","character":"Doug","img":null,"order":5},{"name":"Patricia Clarkson","character":"Judy Nash","img":null,"order":6},{"name":"Kevin Dunn","character":"Mark Nash","img":null,"order":7},{"name":"Julio Perill\u00e1n","character":"Charles","img":null,"order":8},{"name":"Ricard Salom","character":"Art Gallery Guest","img":null,"order":9},{"name":"Maurice Sonnenberg","character":"Art Gallery Guest","img":null,"order":10},{"name":"Manel Barcel\u00f3","character":"Doctor","img":null,"order":11},{"name":"Josep Maria Dom\u00e8nech","character":"Julio","img":null,"order":12},{"name":"Emilio de Benito","character":"Guitarist in Asturias","img":null,"order":13},{"name":"Jaume Montan\u00e9","character":"Juan Antonio's Friend","img":null,"order":14}],"tv:108255":[{"name":"Nicholas Ralph","character":"James Herriot","img":null,"order":0},{"name":"Samuel West","character":"Siegfried Farnon","img":null,"order":1},{"name":"Anna Madeley","character":"Mrs Hall","img":null,"order":2},{"name":"Callum Woodhouse","character":"Tristan Farnon","img":null,"order":3},{"name":"Rachel Shenton","character":"Helen Herriot","img":null,"order":4},{"name":"James Anthony-Rose","character":"Richard Carmody","img":null,"order":500},{"name":"Mollie Winnard","character":"Maggie","img":null,"order":528},{"name":"Maimie McCoy","character":"Dorothy","img":null,"order":530},{"name":"Drew Cain","character":"James Herriot Senior","img":null,"order":535},{"name":"Will Thorp","character":"Gerald Hammond","img":null,"order":539},{"name":"Matthew Lewis","character":"Hugh Hulton","img":null,"order":552},{"name":"Patricia Hodge","character":"Mrs. Pumphrey","img":null,"order":553},{"name":"Imogen Clawson","character":"Jenny Alderson","img":null,"order":556},{"name":"Tony Pitts","character":"Richard Alderson","img":null,"order":558},{"name":"Gaia Wise","character":"Charlotte Beauvoir","img":null,"order":582}],"tv:88510":[{"name":"Daisy Haggard","character":"Miri Matteson","img":null,"order":0},{"name":"Geraldine James","character":"Caroline Matteson","img":null,"order":1},{"name":"Richard Durden","character":"Oscar Matteson","img":null,"order":2},{"name":"Jo Martin","character":"Janice","img":null,"order":3},{"name":"Adeel Akhtar","character":"Billy","img":null,"order":4},{"name":"Jamie Michie","character":"Dom","img":null,"order":5},{"name":"Christine Bottomley","character":"Mandy","img":null,"order":6},{"name":"Frank Feys","character":"Samuel","img":null,"order":502},{"name":"Liam Williams","character":"Nathan","img":null,"order":504},{"name":"Imogen Gurney","character":"Lara","img":null,"order":505},{"name":"Juliet Cowan","character":"Tina","img":null,"order":510},{"name":"Lizzy McInnerny","character":"Norah Boback","img":null,"order":515},{"name":"Adrian Edmondson","character":"John Boback","img":null,"order":516},{"name":"Keir Charles","character":"Mark","img":null,"order":520},{"name":"Hebe Bartlett","character":"Cerys","img":null,"order":522}],"tv:202851":[{"name":"Jack Rooke","character":"Narrator (voice)","img":null,"order":0},{"name":"Dylan Llewellyn","character":"Jack","img":null,"order":1},{"name":"Camille Coduri","character":"Peggy","img":null,"order":2},{"name":"Jon Pointing","character":"Danny","img":null,"order":3},{"name":"Katy Wix","character":"Jules","img":null,"order":4},{"name":"Izuka Hoyle","character":"Corinne","img":null,"order":5},{"name":"Olisa Odele","character":"Yemi","img":null,"order":6},{"name":"Harriet Webb","character":"Shannon","img":null,"order":7},{"name":"Annette Badland","character":"Nanny Bingo","img":null,"order":8},{"name":"Robert Gilbert","character":"Tim","img":null,"order":501},{"name":"Sheila Reid","character":"Iris","img":null,"order":502},{"name":"Lucia Keskin","character":"Kelly","img":null,"order":503},{"name":"Shane Zaza","character":"Tariq","img":null,"order":504},{"name":"Callum Mardy","character":"Ash","img":null,"order":505},{"name":"Ian Burfield","character":"Lance (voice)","img":null,"order":506}],"tv:39793":[{"name":"Vanessa Redgrave","character":"Jennifer Worth (voice)","img":null,"order":0},{"name":"Jenny Agutter","character":"Sister Julienne","img":null,"order":2},{"name":"Judy Parfitt","character":"Sister Monica Joan","img":null,"order":3},{"name":"Linda Bassett","character":"Phyllis Crane","img":null,"order":12},{"name":"Stephen McGann","character":"Dr Patrick Turner","img":null,"order":14},{"name":"Alice Brown","character":"Angela Turner","img":null,"order":23},{"name":"Laura Main","character":"Nurse Shelagh Turner","img":null,"order":24},{"name":"Cliff Parisi","character":"Fred Buckle","img":null,"order":26},{"name":"Georgie Glen","character":"Miss Millicent Higgins","img":null,"order":28},{"name":"Victoria Yeates","character":"Sister Winifred","img":null,"order":35},{"name":"Annabelle Apsion","character":"Violet Buckle","img":null,"order":87},{"name":"Max Macmillan","character":"Timothy Turner","img":null,"order":94},{"name":"Helen George","character":"Nurse Trixie Aylward","img":null,"order":102},{"name":"Zephryn Taitte","character":"Cyril Robinson","img":null,"order":104},{"name":"April Rae Hoang","character":"May Tang","img":null,"order":237}],"tv:76148":[{"name":"Saoirse-Monica Jackson","character":"Erin Quinn","img":null,"order":0},{"name":"Louisa Harland","character":"Orla McCool","img":null,"order":1},{"name":"Nicola Coughlan","character":"Clare Devlin","img":null,"order":2},{"name":"Jamie Lee O'Donnell","character":"Michelle Mallon","img":null,"order":3},{"name":"Dylan Llewellyn","character":"James Maguire","img":null,"order":4},{"name":"Tara Lynne O'Neill","character":"Ma Mary Quinn","img":null,"order":5},{"name":"Tommy Tiernan","character":"Da Gerry Quinn","img":null,"order":6},{"name":"Kathy Kiera Clarke","character":"Aunt Sarah","img":null,"order":7},{"name":"Ian McElhinney","character":"Granda Joe","img":null,"order":8},{"name":"Siobh\u00e1n McSweeney","character":"Sister Michael","img":null,"order":9},{"name":"Leah O'Rourke","character":"Jenny Joyce","img":null,"order":10},{"name":"Donna Traynor","character":"Donna Traynor","img":null,"order":555},{"name":"Beccy Henderson","character":"Aisling","img":null,"order":558},{"name":"Claire Rafferty","character":"Miss Mooney","img":null,"order":559},{"name":"Phillipa Dunne","character":"Geraldine Devlin","img":null,"order":572}],"tv:693":[{"name":"Teri Hatcher","character":"Susan Mayer","img":null,"order":0},{"name":"Felicity Huffman","character":"Lynette Scavo","img":null,"order":1},{"name":"Marcia Cross","character":"Bree Van de Kamp","img":null,"order":2},{"name":"Eva Longoria","character":"Gabrielle Solis","img":null,"order":3},{"name":"Ricardo Chavira","character":"Carlos Solis","img":null,"order":4},{"name":"Doug Savant","character":"Tom Scavo","img":null,"order":5},{"name":"Nicollette Sheridan","character":"Edie Britt","img":null,"order":6},{"name":"Mark Moses","character":"Paul Young","img":null,"order":7},{"name":"James Denton","character":"Mike Delfino","img":null,"order":8},{"name":"Brenda Strong","character":"Mary Alice Young","img":null,"order":10},{"name":"Kyle MacLachlan","character":"Orson Hodge","img":null,"order":14},{"name":"Shawn Pyfrom","character":"Andrew Van de Kamp","img":null,"order":19},{"name":"Andrea Bowen","character":"Julie Mayer","img":null,"order":21},{"name":"Kathryn Joosten","character":"Karen McCluskey","img":null,"order":25},{"name":"Joy Jorgensen","character":"Danielle Van de Kamp","img":null,"order":717}],"tv:203857":[{"name":"Keri Russell","character":"Ambassador Kate Wyler","img":null,"order":0},{"name":"Rufus Sewell","character":"Hal Wyler","img":null,"order":1},{"name":"David Gyasi","character":"Foreign Secretary Austin Dennison","img":null,"order":2},{"name":"Ali Ahn","character":"Eidra Park","img":null,"order":3},{"name":"Rory Kinnear","character":"Prime Minister Nicol Trowbridge","img":null,"order":4},{"name":"Ato Essandoh","character":"Stuart Hayford","img":null,"order":5},{"name":"Allison Janney","character":"Grace Penn","img":null,"order":7},{"name":"Nana Mensah","character":"Billie Appiah","img":null,"order":8},{"name":"Celia Imrie","character":"Meg Roylin","img":null,"order":500},{"name":"Penny Downie","character":"Frances Munning","img":null,"order":505},{"name":"Adam Silver","character":"Howard","img":null,"order":506},{"name":"Tim Delap","character":"Byron","img":null,"order":507},{"name":"Kenichiro Thomson","character":"Martin","img":null,"order":508},{"name":"Georgie Henley","character":"Pensy","img":null,"order":509},{"name":"Graham Miller","character":"Neil Barrow","img":null,"order":572}],"tv:66134":[{"name":"Keeley Hawes","character":"Louisa Durrell","img":null,"order":0},{"name":"Josh O'Connor","character":"Lawrence Durrell","img":null,"order":1},{"name":"Milo Parker","character":"Gerald Durrell","img":null,"order":2},{"name":"Daisy Waterstone","character":"Margo Durrell","img":null,"order":3},{"name":"Callum Woodhouse","character":"Leslie Durrell","img":null,"order":4},{"name":"Alexis Georgoulis","character":"Spiros Halikiopoulos","img":null,"order":5},{"name":"Yorgos Karamihos","character":"Theo Stephanides","img":null,"order":6},{"name":"Anna Savva","character":"Lugaretzia","img":null,"order":8},{"name":"Lucy Black","character":"Florence Petridis","img":null,"order":79},{"name":"Ben Hall","character":"Donald","img":null,"order":525},{"name":"Nikorestis Chaniotakis","character":"Pavlos the Monk","img":null,"order":553},{"name":"Elli Tringou","character":"Daphne Likourgou","img":null,"order":553},{"name":"Ulric von der Esch","character":"Sven","img":null,"order":578},{"name":"Alexis Conran","character":"Dr. Petridis","img":null,"order":579},{"name":"Miles Jupp","character":"Basil","img":null,"order":584}],"tv:225383":[{"name":"Luke Kirby","character":"Jack McMillan","img":null,"order":0},{"name":"Charlotte Gainsbourg","character":"Genevi\u00e8ve Lavigne","img":null,"order":1},{"name":"Lou de La\u00e2ge","character":"Cheyenne Toussaint","img":null,"order":2},{"name":"Gideon Glick","character":"Tobias Bell","img":null,"order":3},{"name":"David Alvarez","character":"Gael Rodriguez","img":null,"order":4},{"name":"Ivan du Pontavice","character":"Gabin","img":null,"order":5},{"name":"Ta\u00efs Vinolo","character":"Mishi Duplessis","img":null,"order":6},{"name":"David Haig","character":"Nicholas","img":null,"order":7},{"name":"LaMay Zhang","character":"Susu","img":null,"order":8},{"name":"Simon Callow","character":"Crispin Shamblee","img":null,"order":9},{"name":"Yanic Truesdale","character":"Rapha\u00ebl Marchand","img":null,"order":10},{"name":"Etai Benson","character":"Curt","img":null,"order":500},{"name":"Steve Belanger","character":"Al","img":null,"order":501}],"tv:4586":[{"name":"Lauren Graham","character":"Lorelai Gilmore","img":null,"order":0},{"name":"Alexis Bledel","character":"Rory Gilmore","img":null,"order":1},{"name":"Scott Patterson","character":"Luke Danes","img":null,"order":2},{"name":"Melissa McCarthy","character":"Sookie St. James","img":null,"order":3},{"name":"Keiko Agena","character":"Lane Kim","img":null,"order":4},{"name":"Yanic Truesdale","character":"Michel Gerard","img":null,"order":5},{"name":"Liza Weil","character":"Paris Geller","img":null,"order":6},{"name":"Jared Padalecki","character":"Dean Forester","img":null,"order":8},{"name":"Matt Czuchry","character":"Logan Huntzberger","img":null,"order":9},{"name":"Kelly Bishop","character":"Emily Gilmore","img":null,"order":10},{"name":"Edward Herrmann","character":"Richard Gilmore","img":null,"order":12},{"name":"Sean Gunn","character":"Kirk Gleason","img":null,"order":60},{"name":"Liz Torres","character":"Miss Patty","img":null,"order":692},{"name":"Michael Winters","character":"Taylor Doose","img":null,"order":697},{"name":"Jackson Douglas","character":"Jackson Belleville","img":null,"order":746}],"tv:117581":[{"name":"Antonia Gentry","character":"Virginia 'Ginny' Miller","img":null,"order":0},{"name":"Brianne Howey","character":"Georgia Miller","img":null,"order":1},{"name":"Diesel La Torraca","character":"Austin Miller","img":null,"order":2},{"name":"Jennifer Robertson","character":"Ellen Baker","img":null,"order":3},{"name":"Felix Mallard","character":"Marcus Baker","img":null,"order":4},{"name":"Sara Waisglass","character":"Maxine Baker","img":null,"order":5},{"name":"Scott Porter","character":"Mayor Paul Randolph","img":null,"order":6},{"name":"Raymond Ablack","character":"Joe","img":null,"order":7},{"name":"Mason Temple","character":"Hunter Chen","img":null,"order":8},{"name":"Katie Douglas","character":"Abigail 'Abby' Littman","img":null,"order":9},{"name":"Chelsea Clark","character":"Norah","img":null,"order":10},{"name":"Nikki Roumel","character":"Young Georgia","img":null,"order":205},{"name":"Sabrina Grdevich","character":"Cynthia Fuller","img":null,"order":502},{"name":"Colton Gobbo","character":"Jordan","img":null,"order":503},{"name":"Tyssen Smith","character":"Brodie","img":null,"order":504}],"tv:32504":[{"name":"Aly Michalka","character":"Marti Perkins","img":null,"order":0},{"name":"Ashley French","character":"Savannah Monroe","img":null,"order":1},{"name":"Heather Hemmens","character":"Alice Verdura","img":null,"order":2},{"name":"Robbie Jones","character":"Lewis Flynn","img":null,"order":3},{"name":"Matt Barr","character":"Dan Patch","img":null,"order":4},{"name":"Gail O'Grady","character":"Wanda Perkins","img":null,"order":5},{"name":"Sharon Leal","character":"Vanessa Lodge","img":null,"order":6},{"name":"Aaron Douglas","character":"Bill Marsh","img":null,"order":500},{"name":"Jeff Hephner","character":"Red Raymond","img":null,"order":501},{"name":"D. B. Woodside","character":"Derrick Altman","img":null,"order":502},{"name":"Elena Esovolova","character":"Patty Wedgerman","img":null,"order":503},{"name":"Emma Lahana","character":"Charlotte Monroe","img":null,"order":504},{"name":"Teryl Rothery","character":"Layne Monroe","img":null,"order":505},{"name":"Lauren Watson","character":"Judge (uncredited)","img":null,"order":506},{"name":"John Pyper-Ferguson","character":"Rex Perkins","img":null,"order":507}],"tv:226637":[{"name":"Kaitlin Olson","character":"Morgan Gillory","img":null,"order":0},{"name":"Daniel Sunjata","character":"Adam Karadec","img":null,"order":1},{"name":"Judy Reyes","character":"Selena Soto","img":null,"order":2},{"name":"Javicia Leslie","character":"Daphne Forrester","img":null,"order":3},{"name":"Deniz Akdeniz","character":"Lev 'Oz' Ozdil","img":null,"order":4},{"name":"Amirah J","character":"Ava Gillory","img":null,"order":5},{"name":"Matthew Lamb","character":"Elliot Radovic","img":null,"order":6},{"name":"Taran Killam","character":"Ludo Radovic","img":null,"order":500},{"name":"Garret Dillahunt","character":"Lieutenant Melon","img":null,"order":520},{"name":"TJ Lee","character":"Officer Lin","img":null,"order":522},{"name":"J. D. Pardo","character":"Tom","img":null,"order":570},{"name":"Mekhi Phifer","character":"Arthur Ellis","img":null,"order":686},{"name":"Steve Howey","character":"Nick Wagner","img":null,"order":719},{"name":"John Pyper-Ferguson","character":"Eric Hayworth","img":null,"order":754},{"name":"Susan Kelechi Watson","character":"Lucia","img":null,"order":774}],"tv:233079":[{"name":"Roisin Gallagher","character":"Saoirse","img":null,"order":0},{"name":"Sin\u00e9ad Keenan","character":"Robyn","img":null,"order":1},{"name":"Caoilfhionn Dunne","character":"Dara","img":null,"order":2},{"name":"Darragh Hand","character":"Liam","img":null,"order":3},{"name":"Natasha O'Keeffe","character":"Greta","img":null,"order":500},{"name":"Bronagh Gallagher","character":"Booker","img":null,"order":501},{"name":"Emmett J. Scanlan","character":"Owen","img":null,"order":502},{"name":"Emma Canning","character":"Young Greta","img":null,"order":503},{"name":"Michelle Fairley","character":"Margo","img":null,"order":504},{"name":"Jenn Murray","character":"Jamie","img":null,"order":510},{"name":"Eleanor Methven","character":"Mrs. Friel","img":null,"order":511},{"name":"Ardal O'Hanlon","character":"S\u00e9amus","img":null,"order":512},{"name":"Tom Basden","character":"Seb","img":null,"order":513},{"name":"Matilda Freeman","character":"Maria","img":null,"order":515},{"name":"Josh Finan","character":"Andrew Sampson","img":null,"order":520}],"tv:244447":[{"name":"Brittany Snow","character":"Sophie O\u2019Neill","img":null,"order":0},{"name":"Malin Akerman","character":"Margo Banks","img":null,"order":1},{"name":"Dermot Mulroney","character":"Jed Banks","img":null,"order":2},{"name":"Katie Lowes","character":"Jill Thompson","img":null,"order":3},{"name":"Jaime Ray Newman","character":"Callie","img":null,"order":4},{"name":"George Ferrier","character":"Brad Thompson","img":null,"order":4},{"name":"Chrissy Metz","character":"Starr Jackson","img":null,"order":4},{"name":"Evan Jonigkeit","character":"Graham O\u2019Neill","img":null,"order":5},{"name":"Alex Fitzalan","character":"Lincoln Trout","img":null,"order":6},{"name":"Hunter Emery","character":"Deputy Walter Flynn","img":null,"order":8},{"name":"Steve D'Avria","character":"Sheriff's Deputy","img":null,"order":9},{"name":"Karen Rodriguez","character":"Deputy Wanda Salazar","img":null,"order":10},{"name":"Madison Wolfe","character":"Abby Jackson","img":null,"order":503},{"name":"Alexandria DeBerry","character":"Taylor Tucker","img":null,"order":504},{"name":"Joyce Glenn","character":"Monae Roberts","img":null,"order":505}],"tv:125816":[{"name":"Sigourney Weaver","character":"June Hart","img":null,"order":0},{"name":"Alycia Debnam-Carey","character":"Alice Hart","img":null,"order":1},{"name":"Alyla Browne","character":"Young Alice Hart","img":null,"order":2},{"name":"Leah Purcell","character":"Twig","img":null,"order":3},{"name":"Frankie Adams","character":"Candy","img":null,"order":4},{"name":"Tilda Cobham-Hervey","character":"Agnes Hart","img":null,"order":5},{"name":"Asher Keddie","character":"Sally Morgan","img":null,"order":6},{"name":"Alexander England","character":"John Morgan","img":null,"order":7},{"name":"Charlie Vickers","character":"Clem Hart","img":null,"order":8},{"name":"Sebasti\u00e1n Zurita","character":"Dylan","img":null,"order":9},{"name":"Maggie Dence","character":"Boo","img":null,"order":502},{"name":"Dalara Williams","character":"Myf","img":null,"order":504},{"name":"Amy Kersey","character":"Rosie","img":null,"order":506},{"name":"Vivienne Awosoga","character":"Lulu","img":null,"order":514},{"name":"Shareena Clanton","character":"Ruby","img":null,"order":515}],"tv:99353":[{"name":"Nick Lachey","character":"Self - Host","img":null,"order":0},{"name":"Vanessa Lachey","character":"Self - Host","img":null,"order":1},{"name":"Cole Barnett","character":"Self - Contestant","img":null,"order":511},{"name":"Paul Peden","character":"Self - Contestant","img":null,"order":545},{"name":"Colleen Reed","character":"Self - Contestant","img":null,"order":581},{"name":"Matt Bolton","character":"Self - Contestant","img":null,"order":583},{"name":"Micah Lussier","character":"Self - Video Message","img":null,"order":594},{"name":"Alexa Alfia","character":"Self - Contestant","img":null,"order":602},{"name":"Brennon Lemieux","character":"Self - Video Message","img":null,"order":605},{"name":"Tiffany Pennywell","character":"Self - Contestant","img":null,"order":606},{"name":"Brett Brown","character":"Self - Video Message","img":null,"order":607},{"name":"Chelsea Griffin Appiah","character":"Self - Contestant","img":null,"order":607},{"name":"Zack Goytowski","character":"Self - Video Message","img":null,"order":608},{"name":"Kwame Appiah","character":"Self - Video Message","img":null,"order":610},{"name":"Bliss Poureetezadi","character":"Self - Video Message","img":null,"order":616}],"tv:285404":[{"name":"Tatiana Maslany","character":"Paula Sanders","img":null,"order":0},{"name":"Jake Johnson","character":"Karl Hendricks","img":null,"order":1},{"name":"Dolly de Leon","character":"Detective Sofia Gonzalez","img":null,"order":2},{"name":"Jessy Hodges","character":"Mallory","img":null,"order":3},{"name":"Jon Michael Hill","character":"Detective Baxter","img":null,"order":4},{"name":"Charlie Hall","character":"Rudy","img":null,"order":5},{"name":"Kiarra Hamagami Goldberg","character":"Geri","img":null,"order":6},{"name":"Nola Wallace","character":"Hazel","img":null,"order":7},{"name":"Brandon Flynn","character":"Trevor","img":null,"order":500},{"name":"Nina Bloomgarden","character":"Ash","img":null,"order":502},{"name":"Daniel Dale","character":"Sky","img":null,"order":504},{"name":"Remy Auberjonois","character":"Doug","img":null,"order":505},{"name":"Grace Porter","character":"Gwynn","img":null,"order":506},{"name":"Raymond Lee","character":"Steve","img":null,"order":507},{"name":"Murray Bartlett","character":"Dennis","img":null,"order":509}],"tv:118303":[{"name":"Ophelia Lovibond","character":"Joyce","img":null,"order":0},{"name":"Jake Johnson","character":"Doug","img":null,"order":1},{"name":"Michael Angarano","character":"Glenn","img":null,"order":2},{"name":"Jessica Lowe","character":"Bambi","img":null,"order":3},{"name":"Oscar Montoya","character":"Richie","img":null,"order":4},{"name":"Lennon Parham","character":"Shelly","img":null,"order":5},{"name":"Idara Victor","character":"Tina","img":null,"order":6},{"name":"Sofia Gonzalez","character":"Rita","img":null,"order":554},{"name":"David Lee Hess","character":"Phil","img":null,"order":557},{"name":"Jaeden Bettencourt","character":"Tommy","img":null,"order":572},{"name":"Rich Sommer","character":"Lenny","img":null,"order":576},{"name":"Elizabeth Perkins","character":"Constance","img":null,"order":579},{"name":"Lincoln A. Castellanos","character":"Daniel","img":null,"order":597},{"name":"Liora Belle","character":"Millie","img":null,"order":744},{"name":"Vera Myers","character":"Bottom Dollar Playmate (uncredited)","img":null,"order":766}],"tv:33155":[{"name":"Don Hany","character":"","img":null,"order":0},{"name":"Asher Keddie","character":"Nina Proudman","img":null,"order":1},{"name":"Deborah Mailman","character":"","img":null,"order":2},{"name":"Kat Stewart","character":"Billie Proudman","img":null,"order":3},{"name":"Richard Davies","character":"Jimmy Proudman","img":null,"order":4},{"name":"Linda Cropper","character":"Geraldine Proudman","img":null,"order":5},{"name":"Jane Harber","character":"Zara Perkich","img":null,"order":6},{"name":"Alicia Gardiner","character":"Kim Akerholt","img":null,"order":7},{"name":"Eddie Perfect","character":"Mick Holland","img":null,"order":8},{"name":"John Waters","character":"","img":null,"order":9},{"name":"Matthew Le Nevez","character":"","img":null,"order":10},{"name":"Lachy Hulme","character":"","img":null,"order":11},{"name":"Clare Bowditch","character":"Rosanna Harding","img":null,"order":12},{"name":"Kate Atkinson","character":"Renee","img":null,"order":508},{"name":"Shannon Berry","character":"Brody Jordan","img":null,"order":511}],"tv:107113":[{"name":"Steve Martin","character":"Charles-Haden Savage","img":null,"order":0},{"name":"Martin Short","character":"Oliver Putnam","img":null,"order":1},{"name":"Selena Gomez","character":"Mabel Mora","img":null,"order":2},{"name":"Amy Ryan","character":"Jan Bellows","img":null,"order":3},{"name":"Michael Cyril Creighton","character":"Howard Morris","img":null,"order":5},{"name":"Jackie Hoffman","character":"Uma Heller","img":null,"order":542},{"name":"Da'Vine Joy Randolph","character":"Donna Williams","img":null,"order":567},{"name":"Vanessa Aspillaga","character":"Ursula","img":null,"order":576},{"name":"Teddy Coluca","character":"Lester","img":null,"order":577},{"name":"Russell G. Jones","character":"Grover Stanley","img":null,"order":583},{"name":"Jayne Houdyshell","character":"Bunny Folger","img":null,"order":586},{"name":"Ryan Broussard","character":"Will Putnam","img":null,"order":588},{"name":"Meryl Streep","character":"Loretta Durkin","img":null,"order":598},{"name":"Paul Rudd","character":"Ben Glenroy","img":null,"order":644},{"name":"Richard Kind","character":"Vince Fish","img":null,"order":659}],"tv:207484":[{"name":"Harriet Slater","character":"Ellen MacKenzie","img":null,"order":0},{"name":"Jamie Roy","character":"Brian Fraser","img":null,"order":1},{"name":"Hermione Corfield","character":"Julia Moriston Beauchamp","img":null,"order":2},{"name":"Jeremy Irvine","character":"Henry Beauchamp","img":null,"order":3},{"name":"Tony Curran","character":"Lord Lovat (Simon Fraser)","img":null,"order":4},{"name":"S\u00e9amus McLean Ross","character":"Colum MacKenzie","img":null,"order":5},{"name":"Sam Retford","character":"Dougal MacKenzie","img":null,"order":6},{"name":"Rory Alexander","character":"Murtagh Fitzgibbons Fraser","img":null,"order":7},{"name":"Conor MacNeill","character":"Ned Gowan","img":null,"order":8},{"name":"Sara Vickers","character":"Davina Porter","img":null,"order":9},{"name":"Sadhbh Malin","character":"Jocasta MacKenzie Cameron","img":null,"order":502},{"name":"Jhon Lumsden","character":"Malcolm Grant","img":null,"order":503},{"name":"Sally Messham","character":"Mrs. Fitzgibbons","img":null,"order":506},{"name":"Terence Rae","character":"Arch Bug","img":null,"order":507},{"name":"Chick Allan","character":"Balloch","img":null,"order":514}],"tv:208921":[{"name":"David Tennant","character":"Tony Baddingham","img":null,"order":0},{"name":"Aidan Turner","character":"Declan O'Hara","img":null,"order":1},{"name":"Danny Dyer","character":"Freddie Jones","img":null,"order":2},{"name":"Alex Hassell","character":"Rupert Campbell-Black","img":null,"order":3},{"name":"Nafessa Williams","character":"Cameron Cook","img":null,"order":4},{"name":"Bella Maclean","character":"Taggie O'Hara","img":null,"order":5},{"name":"Katherine Parkinson","character":"Lizzie Vereker","img":null,"order":6},{"name":"Victoria Smurfit","character":"Maud O'Hara","img":null,"order":7},{"name":"Claire Rushbrook","character":"Lady Monica Baddingham","img":null,"order":8},{"name":"Oliver Chris","character":"James Vereker","img":null,"order":9},{"name":"Lisa McGrillis","character":"Valerie Jones","img":null,"order":10},{"name":"Emily Atack","character":"Sarah Stratton","img":null,"order":11},{"name":"Rufus Jones","character":"Paul Stratton","img":null,"order":12},{"name":"Luke Pasqualino","character":"Basil 'Bas' Baddingham","img":null,"order":13},{"name":"Catriona Chandler","character":"Caitlin O'Hara","img":null,"order":14}],"tv:254953":[{"name":"Steve Carell","character":"Greg Russo","img":null,"order":0},{"name":"Charly Clive","character":"Katie Russo","img":null,"order":1},{"name":"Danielle Deadwyler","character":"Dylan Shepard","img":null,"order":2},{"name":"Phil Dunster","character":"Archie Bates","img":null,"order":3},{"name":"John C. McGinley","character":"Walter Mann","img":null,"order":4},{"name":"Lauren Tsai","character":"Sunny Salewski","img":null,"order":5},{"name":"Annie Mumolo","character":"Cristle","img":null,"order":500},{"name":"Rory Scovel","character":"Officer Donnie Mullins","img":null,"order":501},{"name":"Cece Abbey","character":"Maya","img":null,"order":503},{"name":"Xavier Beloved","character":"George Heitman","img":null,"order":504},{"name":"Noah Grismer","character":"J.D.","img":null,"order":507},{"name":"Madison Hu","character":"Eva","img":null,"order":508},{"name":"Evan Jachelski","character":"Spooner","img":null,"order":509},{"name":"Maximo Salas","character":"Tommy Newton","img":null,"order":515},{"name":"Robby Hoffman","character":"Mo","img":null,"order":518}],"tv:105":[{"name":"Sarah Jessica Parker","character":"Carrie Bradshaw","img":null,"order":0},{"name":"Kim Cattrall","character":"Samantha Jones","img":null,"order":1},{"name":"Cynthia Nixon","character":"Miranda Hobbes","img":null,"order":2},{"name":"Kristin Davis","character":"Charlotte York","img":null,"order":3},{"name":"Lynn Cohen","character":"Magda","img":null,"order":826},{"name":"Willie Garson","character":"Stanford Blatch","img":null,"order":962},{"name":"Mario Cantone","character":"Anthony Marantino","img":null,"order":964},{"name":"Chris Noth","character":"Mr. Big","img":null,"order":982},{"name":"Kyle MacLachlan","character":"Trey MacDougal","img":null,"order":1001},{"name":"David Eigenberg","character":"Steve Brady","img":null,"order":1022},{"name":"Frances Sternhagen","character":"Bunny MacDougal","img":null,"order":1023},{"name":"John Corbett","character":"Aidan Shaw","img":null,"order":1026},{"name":"James Remar","character":"Richard Wright","img":null,"order":1040},{"name":"Jason Lewis","character":"Jerry 'Smith' Jerrod","img":null,"order":1062},{"name":"Evan Handler","character":"Harry Goldenblatt","img":"yU0OXeZ0K1ppe1o9SpHiAMHy1rc.jpg","order":1096}],"tv:133908":[{"name":"Natasha Calis","character":"Hayley Roberts","img":null,"order":0},{"name":"Morgan Holmstrom","character":"Crystal Highway","img":null,"order":1},{"name":"Aaron Ashmore","character":"William \"Wheezer\" Heaseman","img":null,"order":2},{"name":"Mercedes Morris","character":"Lexi Martine","img":null,"order":3},{"name":"Praneet Akilla","character":"Jay \"Chopper\" Chopra","img":null,"order":4},{"name":"Aason Nadjiwan","character":"Austen Bodie","img":null,"order":5},{"name":"Alexander Eling","character":"Wyatt Ellis","img":null,"order":6},{"name":"Thomas Elms","character":"Milosz Nowak","img":null,"order":8},{"name":"Kheon Clarke","character":"Tristan Green","img":null,"order":10},{"name":"Rebecca Kwan","character":"Emma Lin","img":null,"order":12},{"name":"Braeden Clarke","character":"Jeremy Wood","img":null,"order":14},{"name":"Emilia McCarthy","character":"Madison Van Camp","img":null,"order":15},{"name":"Patrick Kwok-Choon","character":"Trevor Sung","img":null,"order":16},{"name":"Sydney Kuhne","character":"Stef","img":null,"order":17},{"name":"Anthony Grant","character":"TJ","img":null,"order":18}],"tv:40231":[{"name":"EliZe","character":"Self - Presenter","img":null,"order":0},{"name":"Dan Karaty","character":"Self - Jury","img":null,"order":1},{"name":"Euvgenia Parakhina","character":"Self - Jury","img":null,"order":2},{"name":"Jaakko Toivonen","character":"Self - Jury","img":null,"order":3},{"name":"Nicky Vernieuwe","character":"Self - Jury","img":null,"order":4},{"name":"Marco Gerris","character":"Self - Jury","img":null,"order":5},{"name":"Min Hee Bervoets","character":"Self - Jury","img":null,"order":6},{"name":"Roberto da Costa","character":"Guest Jury","img":null,"order":7},{"name":"Brahim Attaeb","character":"Guest Jury","img":null,"order":8},{"name":"Eszteca Noya","character":"Guest Jury","img":null,"order":9},{"name":"Dennis Weening","character":"Self - Presenter","img":null,"order":10},{"name":"Ish A\u00eft Hamou","character":"Self - Jury","img":null,"order":11},{"name":"Eline De Munck","character":"Self - Presenter","img":null,"order":12},{"name":"Jan Kooijman","character":"Self - Jury","img":null,"order":13},{"name":"Wendy van Dijk","character":"Self - Jury","img":null,"order":257}],"tv:111803":[{"name":"Leslie Bibb","character":"Kate Bohr","img":null,"order":0},{"name":"Jennifer Coolidge","character":"Tanya McQuoid","img":null,"order":1},{"name":"Carrie Coon","character":"Laurie Duffy","img":null,"order":1},{"name":"Walton Goggins","character":"Rick Hatchett","img":null,"order":2},{"name":"Sarah Catherine Hook","character":"Piper Ratliff","img":null,"order":3},{"name":"Jason Isaacs","character":"Timothy Ratliff","img":null,"order":4},{"name":"Jon Gries","character":"Greg Hunt","img":null,"order":5},{"name":"Parker Posey","character":"Victoria Ratliff","img":null,"order":5},{"name":"Patrick Schwarzenegger","character":"Saxon Ratliff","img":null,"order":6},{"name":"Tayme Thapthimthong","character":"Gaitok","img":null,"order":7},{"name":"Aimee Lou Wood","character":"Chelsea","img":null,"order":8},{"name":"LISA","character":"Mook","img":null,"order":9},{"name":"Michelle Monaghan","character":"Jaclyn Lemon","img":null,"order":10},{"name":"Natasha Rothwell","character":"Belinda Lindsey","img":null,"order":11},{"name":"Sam Nivola","character":"Lochlan Ratliff","img":null,"order":12}],"tv:117488":[{"name":"Melanie Lynskey","character":"Shauna Sadecki","img":null,"order":0},{"name":"Tawny Cypress","character":"Taissa Turner","img":null,"order":1},{"name":"Sophie N\u00e9lisse","character":"Teen Shauna Shipman","img":null,"order":3},{"name":"Jasmin Savoy Brown","character":"Teen Taissa Turner","img":null,"order":4},{"name":"Sophie Thatcher","character":"Teen Natalie Scatorccio","img":null,"order":5},{"name":"Sammi Hanratty","character":"Teen Misty Quigley","img":null,"order":6},{"name":"Steven Krueger","character":"Ben Scott","img":null,"order":7},{"name":"Warren Kole","character":"Jeff Sadecki","img":null,"order":8},{"name":"Courtney Eaton","character":"Teen Lottie Matthews","img":null,"order":9},{"name":"Lauren Ambrose","character":"Van Palmer","img":null,"order":10},{"name":"Christina Ricci","character":"Misty Quigley","img":null,"order":11},{"name":"Kevin Alves","character":"Teen Travis","img":null,"order":14},{"name":"Liv Hewson","character":"Teen Van Palmer","img":null,"order":15},{"name":"Sarah Desjardins","character":"Callie Sadecki","img":null,"order":16},{"name":"Alexa Barajas","character":"Teen Mari Ibarra","img":null,"order":18}],"movie:21469":[{"name":"Mike Vogel","character":"Julian","img":null,"order":0},{"name":"Brittany Murphy","character":"June","img":null,"order":1},{"name":"Danny Pino","character":"Terry","img":null,"order":2},{"name":"Brad Greenquist","character":"The Porter","img":null,"order":3},{"name":"Arie Verveen","character":"Lucas","img":null,"order":4},{"name":"Natalie Smyka","character":"Anna","img":null,"order":5},{"name":"Guillermo D\u00edaz","character":"The Cook","img":null,"order":6},{"name":"Dov Davidoff","character":"The Bellhop","img":null,"order":7},{"name":"William Stanford Davis","character":"Custodian","img":null,"order":8},{"name":"Erika Ringor","character":"Detective","img":null,"order":9},{"name":"Mark Engelhardt","character":"Officer","img":null,"order":10},{"name":"Chase Kim","character":"Police Officer","img":null,"order":11},{"name":"Erika Seifred","character":"Dominatrix","img":null,"order":12},{"name":"Cameron Cash","character":"Georgie (uncredited)","img":null,"order":13}],"movie:235271":[{"name":"Sharon Leal","character":"Zoe Reynard","img":null,"order":0},{"name":"Boris Kodjoe","character":"Jason Reynard","img":null,"order":1},{"name":"John Newberg","character":"Balthazar Crayne","img":null,"order":2},{"name":"Brandon Gonzales","character":"Tony","img":null,"order":3},{"name":"Cameron Mills","character":"10-year-old Zoe","img":null,"order":4},{"name":"Emayatzy Corinealdi","character":"Brina","img":null,"order":5},{"name":"Garrett Hines","character":"Benny","img":null,"order":6},{"name":"Hunter Burke","character":"Shane","img":null,"order":7},{"name":"Kat Graham","character":"Diamond","img":null,"order":8},{"name":"Maria Howell","character":"Nina","img":null,"order":9},{"name":"Omer Mughal","character":"Handsome Man","img":null,"order":10},{"name":"Tasha Smith","character":"Marcella","img":null,"order":11},{"name":"Tyson Beckford","character":"Corey","img":null,"order":12},{"name":"William Levy","character":"Quentin Matthews","img":null,"order":13},{"name":"Mikayla Donlon","character":"Girl on Playground","img":null,"order":14}],"movie:376004":[{"name":"Sean Faris","character":"Samuel Deuprey","img":null,"order":0},{"name":"Danielle Savre","character":"Ashley","img":null,"order":1},{"name":"Mehcad Brooks","character":"Damien","img":null,"order":2},{"name":"Stephanie Charles","character":"Lola","img":null,"order":3},{"name":"Steffinnie Phrommany","character":"Jasmine","img":null,"order":4},{"name":"Rebecca Reaney","character":"Rebecca Scott","img":null,"order":5},{"name":"Phillip Brock","character":"Jimmy","img":null,"order":6},{"name":"Robert Eric Wise","character":"Tyrone","img":null,"order":7}],"movie:18206":[{"name":"Colin Hanks","character":"Doug","img":null,"order":0},{"name":"Ana Claudia Talanc\u00f3n","character":"Amy","img":null,"order":1},{"name":"Jordana Spiro","character":"Jen","img":null,"order":2},{"name":"Jonathon Trent","character":"Matt","img":null,"order":3},{"name":"Alex Boling","character":"Barrista","img":null,"order":4},{"name":"Tony Armatrading","character":"Cop","img":null,"order":5}],"movie:13483":[{"name":"Hayden Christensen","character":"Clay Beresford","img":null,"order":0},{"name":"Jessica Alba","character":"Sam Lockwood","img":null,"order":1},{"name":"Terrence Howard","character":"Dr. Jack Harper","img":null,"order":2},{"name":"Lena Olin","character":"Lilith Beresford","img":null,"order":3},{"name":"Christopher McDonald","character":"Dr. Larry Lupin","img":null,"order":4},{"name":"Sam Robards","character":"Clayton Beresford Sr.","img":null,"order":5},{"name":"Arliss Howard","character":"Dr. Jonathan Neyer","img":null,"order":6},{"name":"Fisher Stevens","character":"Dr. Puttnam","img":null,"order":7},{"name":"Georgina Chapman","character":"Penny Carver","img":null,"order":8},{"name":"David Harbour","character":"Dracula","img":null,"order":9},{"name":"Steven Hinkle","character":"Young Clay","img":null,"order":10},{"name":"Denis O'Hare","character":"Financial News Analyst","img":null,"order":11},{"name":"Charlie Hewson","character":"Brian the Orderly","img":null,"order":12},{"name":"Court Young","character":"Officer Doherty","img":null,"order":13},{"name":"Poorna Jagannathan","character":"Dr. Neyer's Nurse","img":null,"order":14}],"movie:624788":[{"name":"Aubrey Plaza","character":"Allison","img":null,"order":0},{"name":"Christopher Abbott","character":"Gabe","img":null,"order":1},{"name":"Sarah Gadon","character":"Blair","img":null,"order":2},{"name":"Paola L\u00e1zaro","character":"Cahya","img":null,"order":3},{"name":"Grantham Coleman","character":"Baako","img":null,"order":4},{"name":"Lindsay Burdge","character":"Maude","img":null,"order":5},{"name":"Lou Gonzalez","character":"Chris","img":null,"order":6},{"name":"Shannon O'Neill","character":"Simone","img":null,"order":7},{"name":"Alexander Koch","character":"Mike","img":null,"order":8},{"name":"Jennifer Kim","character":"Nora","img":null,"order":9},{"name":"Kevin Barker","character":"John the Gaffer","img":null,"order":10},{"name":"Mary Borrello","character":"1st AC","img":null,"order":11},{"name":"Rob Turbovsky","character":"2nd AC","img":null,"order":12},{"name":"Haitao Zeng","character":"PA","img":null,"order":13}],"movie:13250":[{"name":"Pierce Brosnan","character":"Tom Ryan","img":null,"order":0},{"name":"Maria Bello","character":"Abby Randall","img":null,"order":1},{"name":"Gerard Butler","character":"Neil Randall","img":null,"order":2},{"name":"Emma Karwandy","character":"Sophie Randall","img":null,"order":3},{"name":"Claudette Mink","character":"Judy Ryan","img":null,"order":4},{"name":"Desiree Zurowski","character":"Helen Schriver","img":null,"order":5},{"name":"Nicholas Lea","character":"Jerry Crane","img":null,"order":6},{"name":"Peter Keleghan","character":"Karl Granger","img":null,"order":7},{"name":"Samantha Ferris","character":"Diane","img":null,"order":8},{"name":"Malcolm Stewart","character":"Dave Carver","img":null,"order":9},{"name":"Callum Keith Rennie","character":"Det. McGill","img":null,"order":10},{"name":"Dustin Milligan","character":"Matt Ryan","img":null,"order":11},{"name":"Julie Patzwald","character":"Female Teller","img":null,"order":12},{"name":"Jason McKinnon","character":"French Waiter","img":null,"order":13},{"name":"Kurt Evans","character":"Maitre D'","img":null,"order":14}],"movie:317744":[{"name":"Nick Jonas","character":"Doug Martin","img":null,"order":0},{"name":"Isabel Lucas","character":"Lena Harper","img":null,"order":1},{"name":"Dermot Mulroney","character":"Eliott Harper","img":null,"order":2},{"name":"Kandyse McClure","character":"Angie Alvarez","img":null,"order":3},{"name":"Graham Rogers","character":"Carson","img":null,"order":4},{"name":"Marc Macaulay","character":"Gordon","img":null,"order":5},{"name":"David Sherrill","character":"Brian Martin","img":null,"order":6},{"name":"Kevin J. O'Connor","character":"Pier/Patron du bar","img":null,"order":7},{"name":"Paul Sorvino","character":"Sheriff Big Jack","img":null,"order":8},{"name":"Alex ter Avest","character":"Emma Shalloway","img":null,"order":9},{"name":"John Driskell Hopkins","character":"Gus","img":null,"order":10},{"name":"Ross Gallo","character":"Lena's Lawyer","img":null,"order":11},{"name":"Kiki Harris","character":"Emily/Doug's mother","img":null,"order":12}],"movie:1920":[{"name":"Barbara Stanwyck","character":"Kathy Ferguson","img":null,"order":0},{"name":"Sterling Hayden","character":"Lt. William Doyle","img":null,"order":1},{"name":"Raymond Burr","character":"Inspector Tony Pope","img":null,"order":2},{"name":"Fay Wray","character":"Alice Pope","img":null,"order":3},{"name":"Virginia Grey","character":"Sara Alidas","img":null,"order":4},{"name":"Royal Dano","character":"Capt. Charlie Alidas","img":null,"order":5},{"name":"Robert Griffin","character":"Police Sgt. James","img":null,"order":6},{"name":"Dennis Cross","character":"Police Sgt. Jules","img":null,"order":7},{"name":"Jay Adler","character":"Mr. Nalence","img":null,"order":8},{"name":"Stuart Whitman","character":"Laboratory Technician","img":null,"order":9},{"name":"Malcolm Atterbury","character":"Police Officer Spitz","img":null,"order":10},{"name":"Robert Quarry","character":"Sam, Reporter","img":null,"order":11},{"name":"Gail Bonney","character":"Mrs. London","img":null,"order":12},{"name":"Joe Conley","character":"Delivery Boy","img":null,"order":13},{"name":"Ralph Brooks","character":"Reporter in Newspaper Office (Uncredited)","img":null,"order":14}],"movie:619979":[{"name":"Ben Affleck","character":"Vic Van Allen","img":null,"order":0},{"name":"Ana de Armas","character":"Melinda Van Allen","img":null,"order":1},{"name":"Tracy Letts","character":"Don Wilson","img":null,"order":2},{"name":"Lil Rel Howery","character":"Grant","img":null,"order":3},{"name":"Dash Mihok","character":"Jonas Fernandez","img":null,"order":4},{"name":"Finn Wittrock","character":"Tony Cameron","img":null,"order":5},{"name":"Kristen Connolly","character":"Kelly Wilson","img":null,"order":6},{"name":"Jacob Elordi","character":"Charlie De Lisle","img":null,"order":7},{"name":"Rachel Blanchard","character":"Kristin Peterson","img":null,"order":8},{"name":"Michael Braun","character":"Jeff Peterson","img":null,"order":9},{"name":"Jade Fernandez","character":"Jen Fernandez","img":null,"order":10},{"name":"Grace Jenkins","character":"Trixie","img":null,"order":11},{"name":"Brendan Miller","character":"Joel Dash","img":null,"order":12},{"name":"Devyn A. Tyler","character":"Mary Washington","img":null,"order":13},{"name":"Jeff Pope","character":"Chief Nichols","img":null,"order":14}],"movie:8999":[{"name":"Clive Owen","character":"Charles Schine","img":null,"order":0},{"name":"Jennifer Aniston","character":"Lucinda Harris","img":null,"order":1},{"name":"Vincent Cassel","character":"LaRoche","img":null,"order":2},{"name":"Melissa George","character":"Deanna Schine","img":null,"order":3},{"name":"Giancarlo Esposito","character":"Detective Church","img":null,"order":4},{"name":"David Morrissey","character":"Sam Griffin","img":null,"order":5},{"name":"Georgina Chapman","character":"Candy","img":null,"order":6},{"name":"Denis O'Hare","character":"Jerry","img":null,"order":7},{"name":"Tom Conti","character":"Eliot Firth","img":null,"order":8},{"name":"Addison Timlin","character":"Amy Schine","img":null,"order":9},{"name":"RZA","character":"Winston Boyko","img":null,"order":10},{"name":"Xzibit","character":"Dexter","img":null,"order":11},{"name":"Sandra Bee","character":"Train Conductor","img":null,"order":12},{"name":"William Armstrong","character":"Accountant","img":null,"order":13},{"name":"Rachael Blake","character":"Susan Davis","img":null,"order":14}],"movie:1033148":[{"name":"Jennifer Lawrence","character":"Grace","img":null,"order":0},{"name":"Robert Pattinson","character":"Jackson","img":null,"order":1},{"name":"Sissy Spacek","character":"Pam","img":null,"order":2},{"name":"LaKeith Stanfield","character":"Karl","img":null,"order":3},{"name":"Nick Nolte","character":"Harry","img":null,"order":4},{"name":"Gabrielle Rose","character":"Jen","img":null,"order":5},{"name":"Clare Coulter","character":"Courtney","img":null,"order":6},{"name":"Sarah Lind","character":"Cheryl","img":null,"order":7},{"name":"Luke Camilleri","character":"Greg","img":null,"order":8},{"name":"Victor Zinck Jr.","character":"Tom","img":null,"order":9},{"name":"Debs Howard","character":"Marsha","img":null,"order":10},{"name":"Phillip Forest Lewitski","character":"Charlie","img":null,"order":11},{"name":"Georgina Lightning","character":"Kathleen the Orderly","img":null,"order":12},{"name":"Darren Moore","character":"Gerry","img":null,"order":13},{"name":"Lauren Viau","character":"Bessie","img":null,"order":14}],"movie:69668":[{"name":"Daniel Craig","character":"Will Atenton","img":null,"order":0},{"name":"Naomi Watts","character":"Ann Patterson","img":null,"order":1},{"name":"Rachel Weisz","character":"Libby Atenton","img":null,"order":2},{"name":"Marton Csokas","character":"Jack Patterson","img":null,"order":3},{"name":"Elias Koteas","character":"Boyce","img":null,"order":4},{"name":"Taylor Geare","character":"Trish","img":null,"order":5},{"name":"Claire Geare","character":"Dee Dee","img":null,"order":6},{"name":"Rachel Fox","character":"Chloe Patterson","img":null,"order":7},{"name":"Jane Alexander","character":"Dr. Greeley","img":null,"order":8},{"name":"Brian Murray","character":"Dr. Medlin","img":null,"order":9},{"name":"Bernadette Quigley","character":"Heather Keeler","img":null,"order":10},{"name":"Sarah Gadon","character":"Cindi","img":null,"order":11},{"name":"Gregory Smith","character":"Artie","img":null,"order":12},{"name":"David Huband","character":"Officer Nelson","img":null,"order":13},{"name":"Martin Roach","character":"Tommy","img":null,"order":14}],"movie:18190":[{"name":"James Spader","character":"Ray Reardon","img":null,"order":0},{"name":"M\u00e4dchen Amick","character":"Lena Mathers","img":null,"order":1},{"name":"Fredric Lehne","character":"Larry","img":null,"order":2},{"name":"Bess Armstrong","character":"Elaine","img":null,"order":3},{"name":"Larry Miller","character":"Norman","img":null,"order":4},{"name":"Kathleen York","character":"Martha","img":null,"order":5},{"name":"Kate Williamson","character":"Mrs. Sneeder","img":null,"order":6},{"name":"Tom Lillard","character":"Hank Sneeder","img":null,"order":7},{"name":"William Shockley","character":"Buddy","img":null,"order":8},{"name":"Carl Sundstrom","character":"Officer","img":null,"order":9},{"name":"Irwin Keyes","character":"Officer","img":null,"order":10},{"name":"Joel McKinnon Miller","character":"Minister","img":null,"order":11},{"name":"Joseph Scoren","character":"Martha's Lawyer (as Joseph Scorsiani)","img":null,"order":12},{"name":"Archie Lang","character":"Judge #1","img":null,"order":13},{"name":"Clyde Kusatsu","character":"Judge Kurita","img":null,"order":14}],"movie:1249213":[{"name":"Meghann Fahy","character":"Violet","img":null,"order":0},{"name":"Brandon Sklenar","character":"Henry","img":null,"order":1},{"name":"Reed Diamond","character":"Richard","img":null,"order":2},{"name":"Violett Beane","character":"Jen","img":null,"order":3},{"name":"Jeffery Self","character":"Matt","img":null,"order":4},{"name":"Jacob Robinson","character":"Toby","img":null,"order":5},{"name":"Gabrielle Ryan","character":"Cara","img":null,"order":6},{"name":"Ed Weeks","character":"Phil","img":null,"order":7},{"name":"Travis Nelson","character":"Connor","img":null,"order":8},{"name":"Sarah McCormack","character":"Hostess","img":null,"order":9},{"name":"Ben Pelletier","character":"Bearded Man / Masked Man","img":null,"order":10},{"name":"Saoirse Hayden","character":"Green Prom Dress Girl","img":null,"order":11},{"name":"Fiona Browne","character":"Diane","img":null,"order":12},{"name":"Stephanie Karam","character":"Young Woman (Zoom)","img":null,"order":13},{"name":"Michael Shea","character":"Blake","img":null,"order":14}],"movie:2252":[{"name":"Viggo Mortensen","character":"Nikolai Luzhin","img":null,"order":0},{"name":"Naomi Watts","character":"Anna Ivanovna Khitrova","img":null,"order":1},{"name":"Vincent Cassel","character":"Kirill","img":null,"order":2},{"name":"Armin Mueller-Stahl","character":"Semyon","img":null,"order":3},{"name":"Sin\u00e9ad Cusack","character":"Helen","img":null,"order":4},{"name":"Donald Sumpter","character":"Yuri","img":null,"order":5},{"name":"Jerzy Skolimowski","character":"Stepan","img":null,"order":6},{"name":"Josef Altin","character":"Ekrem","img":null,"order":7},{"name":"Aleksandar Mikic","character":"Soyka","img":null,"order":8},{"name":"Sarah-Jeanne Labrosse","character":"Tatiana","img":null,"order":9},{"name":"Lalita Ahmed","character":"Customer","img":null,"order":10},{"name":"Tatiana Maslany","character":"Tatiana (voice)","img":null,"order":11},{"name":"Tereza Srbova","character":"Kirilenko","img":null,"order":12},{"name":"David Papava","character":"Chechen","img":null,"order":13},{"name":"Tamer Hassan","character":"Chechen","img":null,"order":14}],"movie:753":[{"name":"John Marley","character":"Richard Forst","img":null,"order":0},{"name":"Gena Rowlands","character":"Jeannie Rapp","img":null,"order":1},{"name":"Lynn Carlin","character":"Maria Forst","img":null,"order":2},{"name":"Fred Draper","character":"Freddie Draper","img":null,"order":3},{"name":"Seymour Cassel","character":"Chet","img":null,"order":4},{"name":"Val Avery","character":"Jim McCarthy","img":null,"order":5},{"name":"Dorothy Gulliver","character":"Florence","img":null,"order":6},{"name":"Joanne Moore Jordan","character":"Louise Draper","img":null,"order":7},{"name":"Darlene Conley","character":"Billy Mae","img":null,"order":8},{"name":"Gene Darfler","character":"Joe Jackson","img":null,"order":9},{"name":"Elizabeth Deering","character":"Stella","img":null,"order":10},{"name":"George Dunn","character":"Comedian (as George Dunne)","img":null,"order":11},{"name":"Laurie Mock","character":"Barmaid","img":null,"order":12},{"name":"Christina Crawford","character":"Woman Scattering Coins on Bar","img":null,"order":13},{"name":"George Sims","character":"Bartender","img":null,"order":14}],"movie:549514":[{"name":"Hilary Swank","character":"Det. Valerie Quinlan","img":null,"order":0},{"name":"Michael Ealy","character":"Derrick Tyler","img":null,"order":1},{"name":"Mike Colter","character":"Rafe Grimes","img":null,"order":2},{"name":"Damaris Lewis","character":"Tracie Tyler","img":null,"order":3},{"name":"Tyrin Turner","character":"Tyrin Abenathy","img":null,"order":4},{"name":"Danny Pino","character":"Carter Heywood","img":null,"order":5},{"name":"Geoffrey Owens","character":"Bill Cranepool","img":null,"order":6},{"name":"David Hoflin","character":"Officer Lowe","img":null,"order":7},{"name":"Sam Daly","character":"Officer Stallman","img":null,"order":8},{"name":"Lance Stephenson","character":"Sports Star Cameo","img":null,"order":9},{"name":"Chic Daniel","character":"Investigator","img":null,"order":10},{"name":"Stephen O'Mahoney","character":"Uniformed Police Officer","img":null,"order":11},{"name":"Lexa Gluck","character":"Carter's Trophy Wife","img":null,"order":12},{"name":"Oakley Bull","character":"Haley Older / Haley Younger","img":null,"order":13},{"name":"Ian Stanley","character":"First Officer","img":null,"order":14}],"tv:241372":[{"name":"Dove Cameron","character":"Ciara Wyse","img":null,"order":0},{"name":"Avan Jogia","character":"Oliver Kennedy","img":null,"order":1},{"name":"Dorian Missick","character":"Karl Connelly","img":null,"order":2},{"name":"Karla Souza","character":"Lee Reardon","img":null,"order":3},{"name":"Kingston Rumi Southwick","character":"Young Oliver","img":null,"order":4},{"name":"Patch Darragh","character":"Dan Troxler","img":null,"order":5},{"name":"Kira Guloien","character":"Jane Miller","img":null,"order":6},{"name":"Megan Peta Hill","character":"Shyla","img":null,"order":7}],"tv:4493":[{"name":"Jennifer Saunders","character":"Edina Monsoon","img":null,"order":0},{"name":"Joanna Lumley","character":"Patsy Stone","img":null,"order":1},{"name":"Julia Sawalha","character":"Saffron 'Saffy' Monsoon","img":null,"order":2},{"name":"June Whitfield","character":"Mother","img":null,"order":3},{"name":"Jane Horrocks","character":"Bubble / Katy Grin","img":null,"order":118},{"name":"Naoko Mori","character":"Sarah","img":null,"order":505},{"name":"Christopher Malcolm","character":"Justin","img":null,"order":509},{"name":"Kathy Burke","character":"Magda","img":null,"order":510},{"name":"Harriet Thorpe","character":"Fleur","img":null,"order":512},{"name":"Christopher Ryan","character":"Marshall","img":null,"order":513},{"name":"Mo Gaffney","character":"Bo","img":null,"order":514},{"name":"Lulu","character":"Self","img":null,"order":514},{"name":"Helen Lederer","character":"Catriona","img":null,"order":518},{"name":"Tilly Blackwood","character":"Lady Candida De Denison-Bender","img":null,"order":624},{"name":"Llewella Gideon","character":"Nurse","img":null,"order":641}],"tv:106454":[{"name":"Tiffany Haddish","character":"Detective Danner","img":null,"order":0},{"name":"Sam Richardson","character":"Aniq","img":null,"order":1},{"name":"Zo\u00eb Chao","character":"Zoe","img":null,"order":2},{"name":"Ben Schwartz","character":"Yasper","img":null,"order":3},{"name":"Jamie Demetriou","character":"Walt","img":null,"order":7},{"name":"John Early","character":"Detective Culp","img":null,"order":8},{"name":"John Cho","character":"Ulysses","img":null,"order":10},{"name":"Paul Walter Hauser","character":"Travis","img":null,"order":11},{"name":"Ken Jeong","character":"Feng","img":null,"order":12},{"name":"Anna Konkle","character":"Hannah","img":null,"order":13},{"name":"Poppy Liu","character":"Grace","img":null,"order":14},{"name":"Elizabeth Perkins","character":"Isabel","img":null,"order":15},{"name":"Jack Whitehall","character":"Sebastian","img":null,"order":16},{"name":"Zach Woods","character":"Edgar","img":null,"order":17},{"name":"Vivian Wu","character":"Vivian","img":null,"order":18}],"tv:6127":[{"name":"Julia McKenzie","character":"Miss Marple","img":null,"order":0},{"name":"Geraldine McEwan","character":"Miss Marple","img":null,"order":1},{"name":"Emilia Fox","character":"Joanna Burton","img":null,"order":2},{"name":"Sylvia Syms","character":"Lavinia Pinkerton","img":null,"order":500},{"name":"Russell Tovey","character":"PC Terence Reed","img":null,"order":501},{"name":"Hugo Speer","character":"James Abbot","img":null,"order":502},{"name":"Shirley Henderson","character":"Honoria Waynflete","img":null,"order":503},{"name":"Margo Stilley","character":"Bridget Conway","img":null,"order":504},{"name":"Steve Pemberton","character":"Henry Wake","img":null,"order":505},{"name":"Benedict Cumberbatch","character":"Luke Fitzwilliam","img":null,"order":506},{"name":"Anna Chancellor","character":"Lydia Horton","img":null,"order":507},{"name":"Jemma Redgrave","character":"Jessie Humbleby","img":null,"order":508},{"name":"Lyndsey Marshal","character":"Amy Gibbs","img":null,"order":509},{"name":"David Haig","character":"Major Hugh Horton","img":null,"order":510},{"name":"Joanna Lumley","character":"Dolly Bantry","img":null,"order":679}],"tv:153723":[{"name":"Geffri Maya","character":"Simone Hicks","img":null,"order":0},{"name":"Peyton Alex Smith","character":"Damon Sims","img":null,"order":1},{"name":"Kelly Jenrette","character":"Amara Patterson","img":null,"order":2},{"name":"Cory Hardrict","character":"Marcus Turner","img":null,"order":3},{"name":"Sylvester Powell","character":"Jessie 'JR' Raymond","img":null,"order":4},{"name":"Camille Hyde","character":"Thea Mays","img":null,"order":5},{"name":"Mitchell Edwards","character":"Cam Watkins","img":null,"order":6},{"name":"Netta Walker","character":"Keisha McCalla","img":null,"order":7},{"name":"Rhoyle Ivy King","character":"Nathaniel Hardin","img":null,"order":8},{"name":"Leonard Roberts","character":"Zeke Allen","img":null,"order":505},{"name":"Derek Rivera","character":"Santiago Reyes","img":null,"order":510},{"name":"Joe Holt","character":"Jesse","img":null,"order":529},{"name":"Heather Lynn Harris","character":"Gabrielle","img":null,"order":554},{"name":"Martin Bobb-Semple","character":"Orlando 'Lando' Johnson","img":null,"order":555},{"name":"Taylor Polidore","character":"Tootie","img":null,"order":579}],"tv:116450":[{"name":"Sarah Jessica Parker","character":"Carrie Bradshaw","img":null,"order":0},{"name":"Cynthia Nixon","character":"Miranda Hobbes","img":null,"order":1},{"name":"Kristin Davis","character":"Charlotte York","img":null,"order":2},{"name":"Sara Ramirez","character":"Che Diaz","img":null,"order":3},{"name":"Cathy Ang","character":"Lily Goldenblatt","img":null,"order":4},{"name":"Mario Cantone","character":"Anthony Marentino","img":null,"order":5},{"name":"Sarita Choudhury","character":"Seema Patel","img":null,"order":6},{"name":"Evan Handler","character":"Harry Goldenblatt","img":"yU0OXeZ0K1ppe1o9SpHiAMHy1rc.jpg","order":7},{"name":"Christopher Jackson","character":"Herbert Wexley","img":null,"order":8},{"name":"Nicole Ari Parker","character":"Lisa Todd Wexley","img":null,"order":9},{"name":"Alexa Swinton","character":"Rose 'Rock' Goldenblatt","img":null,"order":10},{"name":"Karen Pittman","character":"Dr. Nya Wallace","img":null,"order":11},{"name":"Niall Cunningham","character":"Brady Hobbes","img":null,"order":12},{"name":"Alexander Bello","character":"Henry Wexley","img":null,"order":515},{"name":"Sebastiano Pigazzi","character":"Giuseppe","img":null,"order":620}],"tv:70785":[{"name":"Amybeth McNulty","character":"Anne Shirley","img":null,"order":0},{"name":"Geraldine James","character":"Marilla Cuthbert","img":null,"order":1},{"name":"R.H. Thomson","character":"Matthew Cuthbert","img":null,"order":2},{"name":"Dalila Bela","character":"Diana Barry","img":null,"order":3},{"name":"Lucas Jade Zumann","character":"Gilbert Blythe","img":null,"order":4},{"name":"Corrine Koslo","character":"Rachel Lynde","img":null,"order":5},{"name":"Jonathan Holmes","character":"Mr. William Barry","img":null,"order":539},{"name":"Helen Johns","character":"Mrs. Eliza Barry","img":null,"order":543},{"name":"Lia Pappas-Kemps","character":"Jane Andrews","img":null,"order":567},{"name":"Kyla Matthews","character":"Ruby Gillis","img":null,"order":569},{"name":"Miranda McKeon","character":"Josie Pye","img":null,"order":570},{"name":"Jacob Horsley","character":"Charlie Sloane","img":null,"order":572},{"name":"Jacob Ursomarzo","character":"Moody Spurgeon","img":null,"order":573},{"name":"Dalmar Abuzeid","character":"Sebastian 'Bash' Lacroix","img":null,"order":574},{"name":"Aymeric Jett Montaz","character":"Jerry Baynard","img":null,"order":579}],"tv:39859":[{"name":"Ashley Rickards","character":"Jenna Hamilton","img":null,"order":0},{"name":"Beau Mirchoff","character":"Matty McKibben","img":null,"order":1},{"name":"Nikki DeLoach","character":"Lacey Hamilton","img":null,"order":2},{"name":"Jillian Rose Reed","character":"Tamara Kaplan","img":null,"order":4},{"name":"Brett Davern","character":"Jake Rosati","img":null,"order":5},{"name":"Molly Tarlov","character":"Sadie Saxton","img":null,"order":6},{"name":"Desi Lydic","character":"Valerie Marks","img":null,"order":7},{"name":"Jessica Lu","character":"Ming Huang","img":null,"order":8},{"name":"Greer Grammer","character":"Lissa Miller","img":null,"order":9},{"name":"Meaghan Jette Martin","character":"Julie #2","img":null,"order":10},{"name":"Wesam Keesh","character":"Kyle Cohen","img":null,"order":522},{"name":"Barret Swatek","character":"Ally Saxton","img":null,"order":617},{"name":"Monty Geer","character":"Cole","img":null,"order":642},{"name":"Evan Crooks","character":"Theo","img":null,"order":643},{"name":"Niko Pepaj","character":"Sergio","img":null,"order":694}],"tv:100412":[{"name":"Sophie Grace","character":"Kristy Thomas","img":null,"order":0},{"name":"Momona Tamada","character":"Claudia Kishi","img":null,"order":1},{"name":"Shay Rudolph","character":"Stacey McGill","img":null,"order":2},{"name":"Malia Baker","character":"Mary Anne Spier","img":null,"order":3},{"name":"Alicia Silverstone","character":"Elizabeth Thomas-Brewer","img":null,"order":500},{"name":"Mark Feuerstein","character":"Watson Brewer","img":null,"order":501},{"name":"Takayo Fischer","character":"Mimi Yamamoto","img":null,"order":502},{"name":"Benjamin Goas","character":"David Michael Thomas","img":null,"order":505},{"name":"Sophia Reid-Gantzert","character":"Karen Brewer","img":null,"order":509},{"name":"Marc Evan Jackson","character":"Richard Spier","img":null,"order":515},{"name":"Xochitl Gomez","character":"Dawn Schafer","img":null,"order":536},{"name":"Jessica Elaina Eason","character":"Sharon Porter","img":null,"order":537},{"name":"Vivian Watson","character":"Mallory Pike","img":null,"order":562},{"name":"Anais Lee","character":"Jessi Ramsey","img":null,"order":577},{"name":"Kyndra Sanchez","character":"Dawn Schafer","img":null,"order":587}],"tv:62704":[{"name":"Dwayne Johnson","character":"Spencer Strassmore","img":null,"order":0},{"name":"Rob Corddry","character":"Joe Krutel","img":null,"order":1},{"name":"John David Washington","character":"Ricky Jerret","img":null,"order":2},{"name":"Omar Benson Miller","character":"Charles Greane","img":null,"order":3},{"name":"Troy Garity","character":"Jason Antolotti","img":null,"order":4},{"name":"London Brown","character":"Reggie","img":null,"order":5},{"name":"Donovan W. Carter","character":"Vernon Littlefield","img":null,"order":6},{"name":"Arielle Kebbel","character":"Tracy Legette","img":null,"order":7},{"name":"Jazmyn Simon","character":"Julie Greane","img":null,"order":9},{"name":"Brittany S. Hall","character":"Amber","img":null,"order":10},{"name":"Dul\u00e9 Hill","character":"Larry Siefert","img":null,"order":501},{"name":"Richard Schiff","character":"Brett Anderson","img":null,"order":503},{"name":"Jay Glazer","character":"Jay Glazer","img":null,"order":647},{"name":"Carl McDowell","character":"TTD","img":null,"order":673},{"name":"Robert Wisdom","character":"Dennis","img":null,"order":674}],"tv:3216":[{"name":"Robert Blake","character":"Det. Tony Baretta","img":null,"order":0},{"name":"Dana Elcar","character":"Inspector Shiller","img":null,"order":1},{"name":"Sharon Cintron","character":"","img":null,"order":2},{"name":"Burt Young","character":"Solomon","img":null,"order":368},{"name":"Michael D. Roberts","character":"","img":null,"order":500},{"name":"Val Avery","character":"","img":null,"order":501},{"name":"Joshua Shelley","character":"","img":null,"order":502},{"name":"Timothy Carey","character":"","img":null,"order":554},{"name":"Sharon Cintron","character":"","img":null,"order":565},{"name":"Art Metrano","character":"","img":null,"order":649},{"name":"Tom Ewell","character":"","img":null,"order":667},{"name":"Strother Martin","character":"","img":null,"order":678},{"name":"Ron Thompson","character":"","img":null,"order":689},{"name":"Elisha Cook Jr.","character":"","img":null,"order":700},{"name":"Angelo Rossitto","character":"Little Moe (uncredited)","img":null,"order":708}],"tv:197373":[{"name":"Kaley Cuoco","character":"Ava Bartlett","img":null,"order":0},{"name":"Chris Messina","character":"Nathan Bartlett","img":null,"order":1},{"name":"Tom Bateman","character":"Matt Pierce","img":null,"order":2},{"name":"Priscilla Quintana","character":"Ruby Gale","img":null,"order":3},{"name":"Liana Liberato","character":"Tory Thompson","img":null,"order":4},{"name":"Li Jun Li","character":"Michelle","img":null,"order":502},{"name":"Annabelle Dexter-Jones","character":"Serena","img":null,"order":503},{"name":"Aisha Alfa","character":"Carolyn","img":null,"order":504},{"name":"Alex Alomar Akpobome","character":"Ryan","img":null,"order":505},{"name":"June Diane Raphael","character":"Romy Lipinski","img":null,"order":506},{"name":"Brandon Keener","character":"Paul","img":null,"order":507},{"name":"Miles Mussenden","character":"Detective Quincy Burrell","img":null,"order":508},{"name":"Jessica St. Clair","character":"Rochelle Lipinski","img":null,"order":519},{"name":"Sebastian Quinn","character":"Carlos","img":null,"order":521},{"name":"Melissa Fumero","character":"Drew","img":null,"order":559}],"tv:250504":[{"name":"Claire Danes","character":"Agatha 'Aggie' Wiggs","img":null,"order":0},{"name":"Matthew Rhys","character":"Nile Jarvis","img":null,"order":1},{"name":"Brittany Snow","character":"Nina Jarvis","img":null,"order":2},{"name":"Natalie Morales","character":"Shelley Morris","img":null,"order":3},{"name":"Jonathan Banks","character":"Martin Jarvis","img":null,"order":500},{"name":"Tim Guinee","character":"Rick 'Wrecking Ball' Jarvis","img":null,"order":501},{"name":"David Lyons","character":"Brian Abbott","img":null,"order":502},{"name":"Bubba Weiler","character":"Teddy Fenig","img":null,"order":503},{"name":"Deirdre O'Connell","character":"Carol McGiddish","img":null,"order":504},{"name":"Leonard Gerome","character":"Cooper Morris-Wiggs","img":null,"order":508},{"name":"Hettienne Park","character":"Erika Breton","img":null,"order":514},{"name":"Aleyse Shannon","character":"Olivia Benitez","img":null,"order":515},{"name":"Julie Ann Emery","character":"Lila Jarvis","img":null,"order":519},{"name":"Amir Arison","character":"Frank Breton","img":null,"order":520},{"name":"Peter Grosz","character":"Elijah Garrity","img":null,"order":526}],"tv:80587":[{"name":"Chris Houghton","character":"Cricket Green (voice)","img":null,"order":0},{"name":"Marieve Herington","character":"Tilly Green (voice)","img":null,"order":1},{"name":"Bob Joles","character":"Bill Green (voice)","img":null,"order":2},{"name":"Artemis Pebdani","character":"Alice 'Gramma' Green (voice)","img":null,"order":3},{"name":"Zeno Robinson","character":"Remy (voice)","img":null,"order":4},{"name":"Wendi McLendon-Covey","character":"Nancy Green (voice)","img":null,"order":5},{"name":"Raven-Symon\u00e9","character":"Maria Media (voice)","img":null,"order":503},{"name":"Anna Akana","character":"Gloria (voice)","img":null,"order":512},{"name":"Danny Trejo","character":"Vasquez (voice)","img":null,"order":513},{"name":"Andy Daly","character":"Officer Keys (voice)","img":null,"order":514},{"name":"Paul Scheer","character":"Chip Whistler (voice)","img":null,"order":516},{"name":"Vladimir Caama\u00f1o","character":"Juan Pablo (voice)","img":null,"order":517},{"name":"Jenna Ortega","character":"Gabriella Espinosa (voice)","img":null,"order":521},{"name":"Paul F. Tompkins","character":"Tooth Fairy (voice)","img":null,"order":523},{"name":"Shane Houghton","character":"Driver Construction Worker (voice)","img":null,"order":541}],"tv:69630":[{"name":"Katie Stevens","character":"Jane Sloan","img":null,"order":0},{"name":"Aisha Dee","character":"Kat Edison","img":null,"order":1},{"name":"Meghann Fahy","character":"Sutton Brady","img":null,"order":2},{"name":"Melora Hardin","character":"Jacqueline Carlyle","img":null,"order":3},{"name":"Stephen Conrad Moore","character":"Oliver Grayson","img":null,"order":4},{"name":"Matt Ward","character":"Alex Crawford","img":null,"order":5},{"name":"Sam Page","character":"Richard 'Dick' Mott","img":null,"order":6},{"name":"Nikohl Boosheri","character":"Aden 'Adena' El Amin","img":null,"order":7},{"name":"Luca James Lee","character":"Ben Chau","img":null,"order":625},{"name":"Alexis Floyd","character":"Tia Clayton","img":null,"order":699},{"name":"Peter Vack","character":"Patrick Duchand","img":null,"order":711},{"name":"Adam Capriolo","character":"Andrew Morrison","img":null,"order":856},{"name":"Stephanie Costa","character":"Sage Aiello","img":null,"order":857},{"name":"Dan Jeannotte","character":"Ryan Decker","img":null,"order":859},{"name":"Gildart Jackson","character":"Ian Carlyle","img":null,"order":860}],"tv:92621":[{"name":"Joseph Gilgun","character":"Vincent \"Vinnie\" O'Neill","img":null,"order":0},{"name":"Michelle Keegan","character":"Erin Croft","img":null,"order":1},{"name":"Steve Evets","character":"Jim","img":null,"order":2},{"name":"Damien Molony","character":"Dylan Golding","img":null,"order":3},{"name":"Bronagh Gallagher","character":"Carol Dennings","img":null,"order":4},{"name":"Tom Hanson","character":"Leslie \"Cardi\" Titt","img":null,"order":5},{"name":"Aaron Heffernan","character":"Ashley \"Ash\" Dennings","img":null,"order":6},{"name":"Joanna Higson","character":"Mary \"Sugar\" Jones","img":null,"order":7},{"name":"Parth Thakerar","character":"Jehan \"JJ\" Jovani","img":null,"order":8},{"name":"Ryan Sampson","character":"Thomas \"Tommo\" Schaffner","img":null,"order":9},{"name":"Dominic West","character":"Dr. Chris Coxley","img":null,"order":10},{"name":"Ramon Tikaram","character":"Terence McCann","img":null,"order":11},{"name":"Tadhg Murphy","character":"Gary Cullen","img":null,"order":14},{"name":"Neil Ashton","character":"David \"Davey\" MacDonagh","img":null,"order":16},{"name":"Jude Riordan","character":"Tyler Croft","img":null,"order":501}],"movie:4982":[{"name":"Denzel Washington","character":"Frank Lucas","img":null,"order":0},{"name":"Russell Crowe","character":"Richie Roberts","img":null,"order":1},{"name":"Josh Brolin","character":"Detective Trupo","img":null,"order":2},{"name":"Chiwetel Ejiofor","character":"Huey Lucas","img":null,"order":3},{"name":"Cuba Gooding Jr.","character":"Nicky Barnes","img":null,"order":4},{"name":"Lymari Nadal","character":"Eva","img":null,"order":5},{"name":"Ted Levine","character":"Lou Toback","img":null,"order":6},{"name":"Armand Assante","character":"Dominic Cattano","img":null,"order":7},{"name":"John Ortiz","character":"Javier J. Rivera","img":null,"order":8},{"name":"John Hawkes","character":"Freddie Spearman","img":null,"order":9},{"name":"RZA","character":"Moses Jones","img":null,"order":10},{"name":"Yul Vazquez","character":"Alfonso Abruzzo","img":null,"order":11},{"name":"Ruby Dee","character":"Mama Lucas","img":null,"order":12},{"name":"Idris Elba","character":"Tango","img":null,"order":13},{"name":"Carla Gugino","character":"Laurie Roberts","img":null,"order":14}],"movie:703":[{"name":"Diane Keaton","character":"Annie Hall","img":null,"order":0},{"name":"Woody Allen","character":"Alvy Singer","img":null,"order":1},{"name":"Tony Roberts","character":"Rob","img":null,"order":2},{"name":"Carol Kane","character":"Allison","img":null,"order":3},{"name":"Paul Simon","character":"Tony Lacey","img":null,"order":4},{"name":"Shelley Duvall","character":"Pam","img":null,"order":5},{"name":"Janet Margolin","character":"Robin","img":null,"order":6},{"name":"Colleen Dewhurst","character":"Mrs. Hall","img":null,"order":7},{"name":"Christopher Walken","character":"Duane Hall","img":null,"order":8},{"name":"Donald Symington","character":"Dad Hall","img":null,"order":9},{"name":"Helen Ludlam","character":"Grammy Hall","img":null,"order":10},{"name":"Mordecai Lawner","character":"Alvy's Dad","img":null,"order":11},{"name":"Joan Neuman","character":"Alvy's Mom","img":null,"order":12},{"name":"Jonathan Munk","character":"Alvy - Age 9","img":null,"order":13},{"name":"Ruth Volner","character":"Alvy's Aunt","img":null,"order":14}],"movie:28":[{"name":"Martin Sheen","character":"Captain Benjamin Willard","img":null,"order":0},{"name":"Marlon Brando","character":"Colonel Walter Kurtz","img":null,"order":1},{"name":"Frederic Forrest","character":"Jay 'Chef' Hicks","img":null,"order":2},{"name":"Albert Hall","character":"Chief Phillips","img":null,"order":3},{"name":"Laurence Fishburne","character":"Tyrone 'Clean' Miller","img":null,"order":4},{"name":"Sam Bottoms","character":"Lance B. Johnson","img":null,"order":5},{"name":"Robert Duvall","character":"Lieutenant Colonel Bill Kilgore","img":null,"order":6},{"name":"G.D. Spradlin","character":"General Corman","img":null,"order":7},{"name":"Harrison Ford","character":"Colonel","img":null,"order":8},{"name":"Jerry Ziesmer","character":"Jerry, Civilian","img":null,"order":9},{"name":"Scott Glenn","character":"Lieutenant Richard M. Colby","img":null,"order":10},{"name":"Kerry Rossall","character":"Mike from San Diego","img":null,"order":11},{"name":"James Keane","character":"Kilgore's Gunner","img":null,"order":12},{"name":"Tom Mason","character":"Supply Sergeant","img":null,"order":13},{"name":"Cynthia Wood","character":"Playmate of the Year","img":null,"order":14}],"movie:329865":[{"name":"Amy Adams","character":"Louise Banks","img":null,"order":0},{"name":"Jeremy Renner","character":"Ian Donnelly","img":null,"order":1},{"name":"Forest Whitaker","character":"Colonel Weber","img":null,"order":2},{"name":"Michael Stuhlbarg","character":"Agent Halpern","img":null,"order":3},{"name":"Mark O'Brien","character":"Captain Marks","img":null,"order":4},{"name":"Tzi Ma","character":"General Shang","img":null,"order":5},{"name":"Abigail Pniowsky","character":"8-Year-Old Hannah","img":null,"order":6},{"name":"Julia Scarlett Dan","character":"12-Year-Old Hannah","img":null,"order":7},{"name":"Jadyn Malone","character":"6-Year-Old Hannah","img":null,"order":8},{"name":"Frank Schorpion","character":"Dr. Kettler","img":null,"order":9},{"name":"Lucas Chartier-Dessert","character":"Private Lasky","img":null,"order":10},{"name":"Christian Jadah","character":"Private Combs","img":null,"order":11},{"name":"Lucy Van Oldenbarneveld","character":"CNAC Anchor","img":null,"order":12},{"name":"Andrew Shaver","character":"Environmental Tech","img":null,"order":13},{"name":"Pat Kiely","character":"Environmental Tech","img":null,"order":14}],"movie:980431":[{"name":"Eric Nam","character":"Aang (voice)","img":null,"order":0},{"name":"Dave Bautista","character":"Tagah (voice)","img":null,"order":1},{"name":"Jessica Matten","character":"Katara (voice)","img":null,"order":2},{"name":"Rom\u00e1n Zaragoza","character":"Sokka (voice)","img":null,"order":3},{"name":"Steven Yeun","character":"Zuko (voice)","img":null,"order":4},{"name":"Dionne Quan","character":"Toph (voice)","img":null,"order":5},{"name":"Dee Bradley Baker","character":"Appa / Momo (voice)","img":null,"order":6},{"name":"Freida Pinto","character":"Avatar Sonam (voice)","img":null,"order":7},{"name":"Ke Huy Quan","character":"Avatar Xian (voice)","img":null,"order":8},{"name":"Taika Waititi","character":"Gorillavark (voice)","img":null,"order":9},{"name":"Geraldine Viswanathan","character":"Kallik (voice)","img":null,"order":10},{"name":"Peta Sergeant","character":"Jie (voice)","img":null,"order":11},{"name":"Jonathan Ohye","character":"Yuddah (voice)","img":null,"order":12},{"name":"Vic Chao","character":"Hong (voice)","img":null,"order":13},{"name":"Fran\u00e7ois Chau","character":"Monk Gyatso (voice)","img":null,"order":14}],"movie:424694":[{"name":"Rami Malek","character":"Freddie Mercury","img":null,"order":0},{"name":"Gwilym Lee","character":"Brian May","img":null,"order":1},{"name":"Ben Hardy","character":"Roger Taylor","img":null,"order":2},{"name":"Joseph Mazzello","character":"John Deacon","img":null,"order":3},{"name":"Lucy Boynton","character":"Mary Austin","img":null,"order":4},{"name":"Aidan Gillen","character":"John Reid","img":null,"order":5},{"name":"Allen Leech","character":"Paul Prenter","img":null,"order":6},{"name":"Tom Hollander","character":"Jim Beach","img":null,"order":7},{"name":"Mike Myers","character":"Ray Foster","img":null,"order":8},{"name":"Aaron McCusker","character":"Jim Hutton","img":null,"order":9},{"name":"Meneka Das","character":"Jer Bulsara","img":null,"order":10},{"name":"Ace Bhatti","character":"Bomi Bulsara","img":null,"order":11},{"name":"Priya Blackburn","character":"Kashmira Bulsara","img":null,"order":12},{"name":"Max Bennett","character":"David","img":null,"order":13},{"name":"Dermot Murphy","character":"Bob Geldof","img":null,"order":14}],"movie:508883":[{"name":"Soma Santoki","character":"Mahito Maki (voice)","img":null,"order":0},{"name":"Masaki Suda","character":"Gray Heron (voice)","img":null,"order":1},{"name":"Ko Shibasaki","character":"Kiriko (voice)","img":null,"order":2},{"name":"Aimyon","character":"Lady Himi (voice)","img":null,"order":3},{"name":"Yoshino Kimura","character":"Natsuko (voice)","img":null,"order":4},{"name":"Takuya Kimura","character":"Shoichi Maki (voice)","img":null,"order":5},{"name":"Keiko Takeshita","character":"Izumi (voice)","img":null,"order":6},{"name":"Jun Fubuki","character":"Utako (voice)","img":null,"order":7},{"name":"Sawako Agawa","character":"Eriko (voice)","img":null,"order":8},{"name":"Karen Takizawa","character":"Warawara (voice)","img":null,"order":9},{"name":"Shinobu Otake","character":"Aiko (voice)","img":null,"order":10},{"name":"Jun Kunimura","character":"The Parakeet King (voice)","img":null,"order":11},{"name":"Kaoru Kobayashi","character":"Noble Pelican (voice)","img":null,"order":12},{"name":"Sh\u014dhei Hino","character":"Granduncle (voice)","img":null,"order":13}],"movie:197":[{"name":"Mel Gibson","character":"William Wallace","img":null,"order":0},{"name":"Catherine McCormack","character":"Murron MacClannough","img":null,"order":1},{"name":"Sophie Marceau","character":"Princess Isabelle","img":null,"order":2},{"name":"Patrick McGoohan","character":"King Edward","img":null,"order":3},{"name":"Angus Macfadyen","character":"Robert the Bruce","img":null,"order":4},{"name":"Brendan Gleeson","character":"Hamish Campbell","img":null,"order":5},{"name":"James Robinson","character":"Young William Wallace","img":null,"order":6},{"name":"James Cosmo","character":"Campbell","img":null,"order":7},{"name":"Sean McGinley","character":"MacClannough","img":null,"order":8},{"name":"Gerda Stevenson","character":"Mother MacClannough","img":null,"order":9},{"name":"Mhairi Calvey","character":"Young Murron MacClannough","img":null,"order":10},{"name":"Jeanne Marine","character":"Nicolette","img":null,"order":11},{"name":"Sean Lawlor","character":"Malcolm Wallace","img":null,"order":12},{"name":"Sandy Nelson","character":"John Wallace","img":null,"order":13},{"name":"Alan Tall","character":"Elder Stewart","img":null,"order":14}],"movie:2108":[{"name":"Emilio Estevez","character":"Andrew Clark","img":null,"order":0},{"name":"Judd Nelson","character":"John Bender","img":null,"order":1},{"name":"Molly Ringwald","character":"Claire Standish","img":null,"order":2},{"name":"Anthony Michael Hall","character":"Brian Johnson","img":null,"order":3},{"name":"Ally Sheedy","character":"Allison Reynolds","img":null,"order":4},{"name":"Paul Gleason","character":"Richard Vernon","img":null,"order":5},{"name":"John Kapelos","character":"Carl","img":null,"order":6},{"name":"Perry Crawford","character":"Allison's Father","img":null,"order":7},{"name":"Mary Christian","character":"Brian's Sister","img":null,"order":8},{"name":"Ron Dean","character":"Andy's Father","img":null,"order":9},{"name":"Tim Gamble","character":"Claire's Father","img":null,"order":10},{"name":"Fran Gargano","character":"Allison's Mom","img":null,"order":11},{"name":"Mercedes Hall","character":"Brian's Mom","img":null,"order":12},{"name":"John Hughes","character":"Brian\u2019s Father (uncredited)","img":null,"order":13},{"name":"Jonathan Chapin","character":"Janitor (uncredited)","img":null,"order":14}],"movie:10515":[{"name":"Keiko Yokozawa","character":"Sheeta (voice)","img":null,"order":0},{"name":"Mayumi Tanaka","character":"Pazu (voice)","img":null,"order":1},{"name":"Minori Terada","character":"Muska (voice)","img":null,"order":2},{"name":"Kotoe Hatsui","character":"Dola (voice)","img":null,"order":3},{"name":"Fujio Tokita","character":"Uncle Pomme (voice)","img":null,"order":4},{"name":"Ichiro Nagai","character":"Shogun Mouro (voice)","img":null,"order":5},{"name":"Hiroshi Ito","character":"Oyakata (voice)","img":null,"order":6},{"name":"Machiko Washio","character":"Okami (voice)","img":null,"order":7},{"name":"Takuz\u014d Kamiyama","character":"Charles / Shalulu (voice)","img":null,"order":8},{"name":"Yoshito Yasuhara","character":"Louis (voice)","img":null,"order":9},{"name":"Sukekiyo Kameyama","character":"Henri (voice)","img":null,"order":10},{"name":"Eken Mine","character":"Underling (voice)","img":null,"order":11},{"name":"TARAKO","character":"Madge (voice)","img":null,"order":12},{"name":"Masashi Sugawara","character":"Underling (voice)","img":null,"order":13},{"name":"Reiko Suzuki","character":"Sheeta's Grandmother (voice)","img":null,"order":14}],"movie:15":[{"name":"Orson Welles","character":"Charles Foster Kane","img":null,"order":0},{"name":"Joseph Cotten","character":"Jedediah Leland","img":null,"order":1},{"name":"Dorothy Comingore","character":"Susan Alexander Kane","img":null,"order":2},{"name":"Ray Collins","character":"Jim W. Gettys","img":null,"order":3},{"name":"George Coulouris","character":"Walter Parks Thatcher","img":null,"order":4},{"name":"Agnes Moorehead","character":"Mary Kane","img":null,"order":5},{"name":"Paul Stewart","character":"Raymond","img":null,"order":6},{"name":"Ruth Warrick","character":"Emily Norton Kane","img":null,"order":7},{"name":"Erskine Sanford","character":"Herbert Carter","img":null,"order":8},{"name":"William Alland","character":"Jerry Thompson/Narrator","img":null,"order":9},{"name":"Everett Sloane","character":"Mr. Bernstein","img":null,"order":10},{"name":"Fortunio Bonanova","character":"Signor Matiste","img":null,"order":11},{"name":"Gus Schilling","character":"John","img":null,"order":12},{"name":"Philip Van Zandt","character":"Mr. Rawlston","img":null,"order":13},{"name":"Georgia Backus","character":"Bertha Anderson","img":null,"order":14}],"movie:974576":[{"name":"Ralph Fiennes","character":"Lawrence","img":null,"order":0},{"name":"Stanley Tucci","character":"Bellini","img":null,"order":1},{"name":"John Lithgow","character":"Tremblay","img":null,"order":2},{"name":"Isabella Rossellini","character":"Sister Agnes","img":null,"order":3},{"name":"Lucian Msamati","character":"Adeyemi","img":null,"order":4},{"name":"Carlos Diehz","character":"Benitez","img":null,"order":5},{"name":"Sergio Castellitto","character":"Tedesco","img":null,"order":6},{"name":"Br\u00edan F. O'Byrne","character":"O'Malley","img":null,"order":7},{"name":"Merab Ninidze","character":"Sabbadin","img":null,"order":8},{"name":"Thomas Loibl","character":"Mandorff","img":null,"order":9},{"name":"Jacek Koman","character":"Wozniak","img":null,"order":10},{"name":"Bruno Novelli","character":"Dead Pope","img":null,"order":11},{"name":"Rony Kramer","character":"Mendoza","img":null,"order":12},{"name":"Valerio Da Silva","character":"Father Haas","img":null,"order":13},{"name":"Joseph Mydell","character":"Nakitanda","img":null,"order":14}],"movie:567797":[{"name":"Eric Bana","character":"Aaron Falk","img":null,"order":0},{"name":"Genevieve O'Reilly","character":"Gretchen Schoner","img":"4eOoW1PNBZfxRW0g8RmYH8bL6mq.jpg","order":1},{"name":"Keir O'Donnell","character":"Greg Raco","img":null,"order":2},{"name":"John Polson","character":"Scott Whitlam","img":null,"order":3},{"name":"Matt Nable","character":"Grant Dow","img":null,"order":4},{"name":"Eddie Baroo","character":"McMurdo","img":null,"order":5},{"name":"Martin Dingle Wall","character":"Luke Hadler","img":null,"order":6},{"name":"Julia Blake","character":"Barb Hadler","img":null,"order":7},{"name":"Bruce Spence","character":"Gerry Hadler","img":null,"order":8},{"name":"BeBe Bettencourt","character":"Ellie Deacon","img":null,"order":9},{"name":"Jeremy Lindsay Taylor","character":"Erik Falk","img":null,"order":10},{"name":"Miranda Tapsell","character":"Rita Raco","img":null,"order":11},{"name":"Renee Lim","character":"Sandra Whitlam","img":null,"order":12},{"name":"James Frecheville","character":"Sullivan","img":null,"order":13},{"name":"William Zappa","character":"Mal Deacon","img":null,"order":14}],"movie:37735":[{"name":"Emma Stone","character":"Olive","img":null,"order":0},{"name":"Penn Badgley","character":"Woodchuck Todd","img":null,"order":1},{"name":"Amanda Bynes","character":"Marianne","img":null,"order":2},{"name":"Dan Byrd","character":"Brandon","img":null,"order":3},{"name":"Thomas Haden Church","character":"Mr. Griffith","img":null,"order":4},{"name":"Patricia Clarkson","character":"Rosemary","img":null,"order":5},{"name":"Cam Gigandet","character":"Micah","img":null,"order":6},{"name":"Lisa Kudrow","character":"Mrs. Griffith","img":null,"order":7},{"name":"Malcolm McDowell","character":"Principal Gibbons","img":null,"order":8},{"name":"Aly Michalka","character":"Rhiannon","img":null,"order":9},{"name":"Stanley Tucci","character":"Dill","img":null,"order":10},{"name":"Fred Armisen","character":"Pastor","img":null,"order":11},{"name":"Juliette Goglia","character":"Eighth Grade Olive","img":null,"order":12},{"name":"Jake Sandvig","character":"Anson","img":null,"order":13},{"name":"Morgan Rusler","character":"Mr. Abernathy","img":null,"order":14}],"movie:559969":[{"name":"Aaron Paul","character":"Jesse","img":null,"order":0},{"name":"Jesse Plemons","character":"Todd","img":null,"order":1},{"name":"Charles Baker","character":"Skinny Pete","img":null,"order":2},{"name":"Matt Jones","character":"Badger","img":null,"order":3},{"name":"Scott MacArthur","character":"Neil","img":null,"order":4},{"name":"Larry Hankin","character":"Old Joe","img":null,"order":5},{"name":"Scott Shepherd","character":"Casey","img":null,"order":6},{"name":"Tom Bower","character":"Lou","img":null,"order":7},{"name":"Robert Forster","character":"Ed","img":null,"order":8},{"name":"Jonathan Banks","character":"Mike","img":null,"order":9},{"name":"Bryan Cranston","character":"Walt","img":null,"order":10},{"name":"Krysten Ritter","character":"Jane","img":null,"order":11},{"name":"Kevin Rankin","character":"Kenny","img":null,"order":12},{"name":"Tess Harper","character":"Mrs. Pinkman","img":null,"order":13},{"name":"Michael Bofshever","character":"Mr. Pinkman","img":null,"order":14}],"movie:715931":[{"name":"Will Smith","character":"Peter","img":null,"order":0},{"name":"Ben Foster","character":"Jim Fassel","img":null,"order":1},{"name":"Charmaine Bingwa","character":"Dodienne","img":null,"order":2},{"name":"Gilbert Owuor","character":"Gordon","img":null,"order":3},{"name":"Ronnie Gene Blevins","character":"Harrington","img":null,"order":4},{"name":"Aaron Moten","character":"Knowls","img":null,"order":5},{"name":"Jabbar Lewis","character":"Tomas","img":null,"order":6},{"name":"Michael Luwoye","character":"John","img":null,"order":7},{"name":"Steven Ogg","character":"Howard","img":null,"order":8},{"name":"Grant Harvey","character":"Leeds","img":null,"order":9},{"name":"Mustafa Shakir","character":"Lt. Andrew Cailloux","img":null,"order":10},{"name":"Paul Ben-Victor","character":"Major G. Halstead","img":null,"order":11},{"name":"David Denman","character":"General William Dwight","img":null,"order":12},{"name":"Jesse C. Boyd","character":"Mike Hurley","img":null,"order":13},{"name":"Imani Pullum","character":"Betsy","img":null,"order":14}],"movie:445629":[{"name":"Florence Pugh","character":"Saraya 'Paige' Knight","img":null,"order":0},{"name":"Lena Headey","character":"Julia 'Sweet Saraya' Knight","img":null,"order":1},{"name":"Nick Frost","character":"Patrick 'Rowdy Ricky' Knight","img":null,"order":2},{"name":"Vince Vaughn","character":"Hutch Morgan","img":null,"order":3},{"name":"Jack Lowden","character":"Zak 'Zodiac' Knight","img":null,"order":4},{"name":"Dwayne Johnson","character":"Dwayne 'The Rock' Johnson","img":null,"order":5},{"name":"Thea Trinidad","character":"AJ Lee","img":null,"order":6},{"name":"Aqueela Zoll","character":"Kirsten","img":null,"order":7},{"name":"Stephen Merchant","character":"Hugh","img":null,"order":8},{"name":"Julia Davis","character":"Daphne","img":null,"order":9},{"name":"James Burrows","character":"Roy Knight","img":null,"order":10},{"name":"Hannah Rae","character":"Courtney","img":null,"order":11},{"name":"Kim Matula","character":"Jeri-Lynn","img":null,"order":12},{"name":"Paul Wight","character":"Big Show","img":null,"order":13},{"name":"Stephen Farrelly","character":"Sheamus","img":null,"order":14}],"movie:832262":[{"name":"Eric Bana","character":"Aaron Falk","img":null,"order":0},{"name":"Anna Torv","character":"Alice","img":null,"order":1},{"name":"Deborra-Lee Furness","character":"Jill Bailey","img":null,"order":2},{"name":"Robin McLeavy","character":"Lauren","img":null,"order":3},{"name":"Sisi Stringer","character":"Beth","img":null,"order":4},{"name":"Lucy Ansell","character":"Bree","img":null,"order":5},{"name":"Jacqueline McKenzie","character":"Carmen Cooper","img":null,"order":6},{"name":"Jeremy Lindsay Taylor","character":"Erik Falk","img":null,"order":7},{"name":"Richard Roxburgh","character":"Daniel Bailey","img":null,"order":8},{"name":"Tony Briggs","character":"Ian Chase","img":null,"order":9},{"name":"Kenneth Radley","character":"Sergeant King","img":null,"order":10},{"name":"Ash Ricardo","character":"Jennifer Falk","img":null,"order":11},{"name":"Ingrid Torelli","character":"Margot","img":null,"order":12},{"name":"Matilda May Pawsey","character":"Rebecca","img":null,"order":13},{"name":"Archie Thomson","character":"Aaron Falk","img":null,"order":14}],"movie:316152":[{"name":"Matthew McConaughey","character":"Newton Knight","img":null,"order":0},{"name":"Gugu Mbatha-Raw","character":"Rachel","img":null,"order":1},{"name":"Mahershala Ali","character":"Moses Washington","img":null,"order":2},{"name":"Keri Russell","character":"Serena Knight","img":null,"order":3},{"name":"Jacob Lofland","character":"Daniel","img":null,"order":4},{"name":"Sean Bridgers","character":"Sumrall","img":null,"order":5},{"name":"Brad Carter","character":"Lieutenant Barbour","img":null,"order":6},{"name":"Jane McNeill","character":"Miss Ellie","img":null,"order":7},{"name":"Gary Grubbs","character":"Prosecuting Attorney","img":null,"order":8},{"name":"Christopher Berry","character":"Jasper","img":null,"order":9},{"name":"Joe Chrest","character":"Amos Deason","img":null,"order":10},{"name":"David Jensen","character":"Quitman","img":null,"order":11},{"name":"Kurt Krause","character":"Injured Soldier","img":null,"order":12},{"name":"Carlton Caudle","character":"Confederate Color Guard","img":null,"order":13},{"name":"Martin Bats Bradford","character":"Freedman 1","img":null,"order":14}],"movie:83389":[{"name":"Masami Nagasawa","character":"Umi Matsuzaki (voice)","img":null,"order":0},{"name":"Junichi Okada","character":"Shun Kazama / Yuichiro Sawamura (voice)","img":null,"order":1},{"name":"Keiko Takeshita","character":"Hana Matsuzaki (voice)","img":null,"order":2},{"name":"Yuriko Ishida","character":"Miki Hokuto (voice)","img":null,"order":3},{"name":"Rumi Hiiragi","character":"Sachiko Hirokoji (voice)","img":null,"order":4},{"name":"Jun Fubuki","character":"Ryoko Matsuzaki (voice)","img":null,"order":5},{"name":"Takashi Naito","character":"Yoshio Onodera (voice)","img":null,"order":6},{"name":"Shunsuke Kazama","character":"Shiro Mizunuma / Hiroshi Tachibana (voice)","img":null,"order":7},{"name":"Nao Omori","character":"Akio Kazama (voice)","img":null,"order":8},{"name":"Teruyuki Kagawa","character":"Tokumaru Board Chairman (voice)","img":null,"order":9},{"name":"Haruka Shiraishi","character":"Sora Matsuzaki (voice)","img":null,"order":10},{"name":"Tsubasa Kobayashi","character":"Riku Matsuzaki (voice)","img":null,"order":11},{"name":"Ayako Ito","character":"Secretary to the Tokumaru Board Chairman (voice)","img":null,"order":12},{"name":"Naoya Fujimaki","character":"Tokumaru Front Desk Receptionist (voice)","img":null,"order":13},{"name":"Toshimi Kanno","character":"Nobuko (voice)","img":null,"order":14}],"movie:9323":[{"name":"Atsuko Tanaka","character":"Motoko Kusanagi (voice)","img":null,"order":0},{"name":"Akio Otsuka","character":"Batou (voice)","img":null,"order":1},{"name":"Iemasa Kayumi","character":"Puppetmaster (voice)","img":null,"order":2},{"name":"Koichi Yamadera","character":"Togusa (voice)","img":"biov5jENp2XYfehkcdnRvi796Wi.jpg","order":3},{"name":"Yutaka Nakano","character":"Ishikawa (voice)","img":null,"order":4},{"name":"Tamio Ohki","character":"Aramaki (voice)","img":null,"order":5},{"name":"Tessyo Genda","character":"Director Nakamura (voice)","img":null,"order":6},{"name":"Masakazu Namaki","character":"Dr. Willis (voice)","img":null,"order":7},{"name":"Masato Yamanouchi","character":"Minister of Foreign Affairs (voice)","img":null,"order":8},{"name":"Shinji Ogawa","character":"Gaik\u00f4kan (voice)","img":null,"order":9},{"name":"Mitsuru Miyamoto","character":"Mizuho Daita (voice)","img":null,"order":10},{"name":"Kazuhiro Yamaji","character":"Garbage Collector A (voice)","img":null,"order":11},{"name":"Shigeru Chiba","character":"Garbage Collector B (voice)","img":"mF5YJxApTYKBVFJDrEC9IrJ5ooV.jpg","order":12},{"name":"Hiroshi Yanaka","character":"Coroner (voice)","img":null,"order":13},{"name":"Ginzo Matsuo","character":"Old Man (voice)","img":null,"order":14}],"movie:12140":[{"name":"Atsuko Tanaka","character":"Motoko Kusanagi (voice)","img":null,"order":0},{"name":"Akio Otsuka","character":"Batou (voice)","img":null,"order":1},{"name":"Koichi Yamadera","character":"Togusa (voice)","img":"biov5jENp2XYfehkcdnRvi796Wi.jpg","order":2},{"name":"Tamio Ohki","character":"Section 9 Department Chief Aramaki (voice)","img":null,"order":3},{"name":"Yutaka Nakano","character":"Ishikawa (voice)","img":null,"order":4},{"name":"Hiroaki Hirata","character":"Koga (voice)","img":null,"order":5},{"name":"Masaki Terasoma","character":"Azuma (voice)","img":null,"order":6},{"name":"Sumi Mutoh","character":"Mysterious Woman (voice)","img":null,"order":7},{"name":"Yuzuru Fujimoto","character":"Criminal (voice)","img":null,"order":8},{"name":"Sukekiyo Kameyama","character":"Rin (voice)","img":null,"order":9},{"name":"Ryuji Nakagi","character":"Wakabayashi (voice)","img":null,"order":10},{"name":"Fumihiko Tachiki","character":"Bodyguard (voice)","img":null,"order":11},{"name":"Minoru Hirano","character":"Cyborg Doctor (voice)","img":null,"order":12},{"name":"Katsunosuke Hori","character":"Chief of Forensics Division (voice)","img":null,"order":13},{"name":"Naoto Takenaka","character":"Kim (voice)","img":null,"order":14}],"movie:238":[{"name":"Marlon Brando","character":"Don Vito Corleone","img":null,"order":0},{"name":"Al Pacino","character":"Michael Corleone","img":null,"order":1},{"name":"James Caan","character":"Sonny Corleone","img":null,"order":2},{"name":"Robert Duvall","character":"Tom Hagen","img":null,"order":3},{"name":"Richard S. Castellano","character":"Clemenza","img":null,"order":4},{"name":"Diane Keaton","character":"Kay Adams","img":null,"order":5},{"name":"Talia Shire","character":"Connie Corleone Rizzi","img":null,"order":6},{"name":"Gianni Russo","character":"Carlo Rizzi","img":null,"order":7},{"name":"Sterling Hayden","character":"Captain McCluskey","img":null,"order":8},{"name":"John Marley","character":"Jack Woltz","img":null,"order":9},{"name":"Richard Conte","character":"Barzini","img":null,"order":10},{"name":"Al Lettieri","character":"Sollozzo","img":null,"order":11},{"name":"Abe Vigoda","character":"Sal Tessio","img":null,"order":12},{"name":"John Cazale","character":"Fredo Corleone","img":null,"order":13},{"name":"Rudy Bond","character":"Cuneo","img":null,"order":14}],"movie:240":[{"name":"Al Pacino","character":"Don Michael Corleone","img":null,"order":0},{"name":"Robert Duvall","character":"Tom Hagen","img":null,"order":1},{"name":"Diane Keaton","character":"Kay Corleone","img":null,"order":2},{"name":"Robert De Niro","character":"Vito Corleone","img":null,"order":3},{"name":"John Cazale","character":"Frederico 'Fredo' Corleone","img":null,"order":4},{"name":"Talia Shire","character":"Constanzia 'Connie' Corleone","img":null,"order":5},{"name":"Lee Strasberg","character":"Hyman Roth","img":null,"order":6},{"name":"Michael V. Gazzo","character":"Frank Pentangeli","img":null,"order":7},{"name":"G.D. Spradlin","character":"Senator Pat Geary","img":null,"order":8},{"name":"Richard Bright","character":"Al Neri","img":null,"order":9},{"name":"Gastone Moschin","character":"Don Fanucci","img":null,"order":10},{"name":"Tom Rosqui","character":"Rocco Lampone","img":null,"order":11},{"name":"Bruno Kirby","character":"Young Clemenza","img":null,"order":12},{"name":"Frank Sivero","character":"Genco Abbandando","img":null,"order":13},{"name":"Francesca De Sapio","character":"Young Mama Corleone","img":null,"order":14}],"movie:242":[{"name":"Al Pacino","character":"Michael Corleone","img":null,"order":0},{"name":"Diane Keaton","character":"Kay Adams","img":null,"order":1},{"name":"Talia Shire","character":"Connie Corleone Rizzi","img":null,"order":2},{"name":"Andy Garcia","character":"Vincent Mancini","img":null,"order":3},{"name":"Eli Wallach","character":"Don Altobello","img":null,"order":4},{"name":"Joe Mantegna","character":"Joey Zasa","img":null,"order":5},{"name":"George Hamilton","character":"B.J. Harrison","img":null,"order":6},{"name":"Bridget Fonda","character":"Grace Hamilton","img":null,"order":7},{"name":"Sofia Coppola","character":"Mary Corleone","img":null,"order":8},{"name":"Raf Vallone","character":"Cardinal Lamberto","img":null,"order":9},{"name":"Franc D'Ambrosio","character":"Anthony Corleone","img":null,"order":10},{"name":"Donal Donnelly","character":"Archbishop Gilday","img":null,"order":11},{"name":"Richard Bright","character":"Al Neri","img":null,"order":12},{"name":"Helmut Berger","character":"Frederick Keinszig","img":null,"order":13},{"name":"Don Novello","character":"Dominic Abbandando","img":null,"order":14}],"movie:5279":[{"name":"Maggie Smith","character":"Constance Trentham","img":null,"order":0},{"name":"Michael Gambon","character":"William McCordle","img":null,"order":1},{"name":"Kristin Scott Thomas","character":"Sylvia McCordle","img":null,"order":2},{"name":"Camilla Rutherford","character":"Isobel McCordle","img":null,"order":3},{"name":"Charles Dance","character":"Raymond Stockbridge","img":null,"order":4},{"name":"Geraldine Somerville","character":"Louisa Stockbridge","img":null,"order":5},{"name":"Tom Hollander","character":"Anthony Meredith","img":null,"order":6},{"name":"Natasha Wightman","character":"Lavinia Meredith","img":null,"order":7},{"name":"Jeremy Northam","character":"Ivor Novello","img":null,"order":8},{"name":"Bob Balaban","character":"Morris Weissman","img":null,"order":9},{"name":"James Wilby","character":"Freddie Nesbitt","img":null,"order":10},{"name":"Claudie Blakley","character":"Mabel Nesbitt","img":null,"order":11},{"name":"Laurence Fox","character":"Rupert Standish","img":null,"order":12},{"name":"Trent Ford","character":"Jeremy Blond","img":null,"order":13},{"name":"Ryan Phillippe","character":"Henry Denton","img":null,"order":14}],"movie:12477":[{"name":"Tsutomu Tatsumi","character":"Seita (voice)","img":null,"order":0},{"name":"Ayano Shiraishi","character":"Setsuko (voice)","img":null,"order":1},{"name":"Yoshiko Shinohara","character":"Mother (voice)","img":null,"order":2},{"name":"Akemi Yamaguchi","character":"Auntie (voice)","img":null,"order":3},{"name":"Masayo Sakai","character":"Woman who takes care of Setsuko (voice)","img":null,"order":4},{"name":"Kozo Hashida","character":"Obayashi Chairman (voice)","img":null,"order":5},{"name":"Kazumi Nozaki","character":"Cousin (voice)","img":null,"order":6},{"name":"Yoshio Matsuoka","character":"Gosaku (voice)","img":null,"order":7},{"name":"Masahiro Kanetake","character":"Aunt's House Guest (voice)","img":null,"order":8},{"name":"Kiyoshi Yanagawa","character":"Patrolman (voice)","img":null,"order":9},{"name":"Hajime Maki","character":"Man who arrests Seita (voice)","img":null,"order":10},{"name":"Atsuo Omotem","character":"Person in Bank (voice)","img":null,"order":11},{"name":"Teruhisa Harita","character":"Station Worker (voice)","img":null,"order":12},{"name":"Hiroshi Tanaka","character":"Person in Bank (voice)","img":null,"order":13},{"name":"Michio Denpo","character":"Station Worker / Doctor (voice)","img":null,"order":14}],"movie:64682":[{"name":"Leonardo DiCaprio","character":"Jay Gatsby","img":null,"order":0},{"name":"Tobey Maguire","character":"Nick Carraway","img":null,"order":1},{"name":"Carey Mulligan","character":"Daisy Buchanan","img":null,"order":2},{"name":"Joel Edgerton","character":"Tom Buchanan","img":null,"order":3},{"name":"Elizabeth Debicki","character":"Jordan Baker","img":null,"order":4},{"name":"Isla Fisher","character":"Myrtle Wilson","img":null,"order":5},{"name":"Jason Clarke","character":"George Wilson","img":null,"order":6},{"name":"Amitabh Bachchan","character":"Meyer Wolfsheim","img":null,"order":7},{"name":"Callan McAuliffe","character":"Teen Jay Gatsby","img":null,"order":8},{"name":"Adelaide Clemens","character":"Catherine","img":null,"order":9},{"name":"Steve Bisley","character":"Dan Cody","img":null,"order":10},{"name":"Richard Carter","character":"Herzog","img":null,"order":11},{"name":"Jack Thompson","character":"Dr. Walter Perkins","img":null,"order":12},{"name":"Vince Colosimo","character":"Michaelis","img":null,"order":13},{"name":"Max Cullen","character":"Owl Eyes","img":null,"order":14}],"movie:590":[{"name":"Nicole Kidman","character":"Virginia Woolf","img":null,"order":0},{"name":"Julianne Moore","character":"Laura Brown","img":null,"order":1},{"name":"Meryl Streep","character":"Clarissa Vaughan","img":null,"order":2},{"name":"Stephen Dillane","character":"Leonard Woolf","img":null,"order":3},{"name":"Jack Rovello","character":"Richie","img":null,"order":4},{"name":"Ed Harris","character":"Richard Brown","img":null,"order":5},{"name":"Miranda Richardson","character":"Vanessa Bell","img":null,"order":6},{"name":"John C. Reilly","character":"Dan Brown","img":null,"order":7},{"name":"Allison Janney","character":"Sally Lester","img":null,"order":8},{"name":"George Loftus","character":"Quentin Bell","img":null,"order":9},{"name":"Charley Ramm","character":"Julian Bell","img":null,"order":10},{"name":"Sophie Wyburd","character":"Angelica Bell","img":null,"order":11},{"name":"Lyndsey Marshal","character":"Lottie Hope","img":null,"order":12},{"name":"Linda Bassett","character":"Nelly Boxall","img":null,"order":13},{"name":"Christian Coulson","character":"Ralph Partridge","img":null,"order":14}],"movie:4935":[{"name":"Chieko Baisho","character":"Sophie (voice)","img":null,"order":0},{"name":"Takuya Kimura","character":"Howl (voice)","img":null,"order":1},{"name":"Akihiro Miwa","character":"Witch of the Waste (voice)","img":null,"order":2},{"name":"Tatsuya Gashuin","character":"Calcifer (voice)","img":null,"order":3},{"name":"Ryunosuke Kamiki","character":"Markl (voice)","img":null,"order":4},{"name":"Mitsunori Isaki","character":"Kosho (voice)","img":null,"order":5},{"name":"Yo Oizumi","character":"Prince Justin / Turnip Head (voice)","img":null,"order":6},{"name":"Akio Otsuka","character":"King of Ingary (voice)","img":null,"order":7},{"name":"Daijir\u014d Harada","character":"Heen (voice)","img":null,"order":8},{"name":"Haruko Kat\u014d","character":"Madame Suliman (voice)","img":null,"order":9},{"name":"Makoto Yasumura","character":"(voice)","img":null,"order":10},{"name":"Manabu Muraji","character":"(voice)","img":null,"order":11},{"name":"Keiko Tsukamoto","character":"(voice)","img":null,"order":12},{"name":"Tsuzuki Kayako","character":"(voice)","img":null,"order":13},{"name":"Seiji Sasaki","character":"(voice)","img":null,"order":14}],"movie:467909":[{"name":"Anthony Ramos","character":"Usnavi","img":null,"order":0},{"name":"Corey Hawkins","character":"Benny","img":null,"order":1},{"name":"Leslie Grace","character":"Nina Rosario","img":null,"order":2},{"name":"Melissa Barrera","character":"Vanessa","img":null,"order":3},{"name":"Olga Merediz","character":"Abuela Claudia","img":null,"order":4},{"name":"Daphne Rubin-Vega","character":"Daniela","img":null,"order":5},{"name":"Gregory D\u00edaz IV","character":"Sonny","img":null,"order":6},{"name":"Marc Anthony","character":"Gapo","img":null,"order":7},{"name":"Jimmy Smits","character":"Kevin Rosario","img":null,"order":8},{"name":"Stephanie Beatriz","character":"Carla","img":null,"order":9},{"name":"Dascha Polanco","character":"Cuca","img":null,"order":10},{"name":"Noah Catala","character":"Graffiti Pete","img":null,"order":11},{"name":"Lin-Manuel Miranda","character":"Pirag\u00fcero","img":null,"order":12},{"name":"Mateo G\u00f3mez","character":"Alejandro","img":null,"order":13},{"name":"Patrick Page","character":"Pike","img":null,"order":14}],"movie:19994":[{"name":"Megan Fox","character":"Jennifer","img":null,"order":0},{"name":"Amanda Seyfried","character":"Needy","img":null,"order":1},{"name":"Johnny Simmons","character":"Chip","img":null,"order":2},{"name":"Adam Brody","character":"Nikolai","img":null,"order":3},{"name":"Sal Cortez","character":"Chas","img":null,"order":4},{"name":"Ryan Levine","character":"Mick","img":null,"order":5},{"name":"Juan Riedinger","character":"Dirk","img":null,"order":6},{"name":"Colin Askey","character":"Keyboardist","img":null,"order":7},{"name":"Chris Pratt","character":"Roman Duda","img":null,"order":8},{"name":"Juno Rinaldi","character":"Officer Warzak","img":null,"order":9},{"name":"Kyle Gallner","character":"Colin Gray","img":null,"order":10},{"name":"Josh Emerson","character":"Jonas Kozelle","img":null,"order":11},{"name":"J.K. Simmons","character":"Mr. Wroblewski","img":null,"order":12},{"name":"Amy Sedaris","character":"Needy's Mom","img":null,"order":13},{"name":"Cynthia Stevenson","character":"Chip's Mom","img":null,"order":14}],"movie:16859":[{"name":"Minami Takayama","character":"Kiki / Ursula (voice)","img":null,"order":0},{"name":"Rei Sakuma","character":"Jiji (voice)","img":null,"order":1},{"name":"Kappei Yamaguchi","character":"Tombo (voice)","img":null,"order":2},{"name":"Keiko Toda","character":"Osono (voice)","img":null,"order":3},{"name":"Mieko Nobusawa","character":"Kokiri (voice)","img":null,"order":4},{"name":"Koichi Miura","character":"Okino (voice)","img":null,"order":5},{"name":"Haruko Kat\u014d","character":"Old Lady (voice)","img":null,"order":6},{"name":"Hiroko Seki","character":"Bertha (voice)","img":null,"order":7},{"name":"Yuriko Fuchizaki","character":"Ketto (voice)","img":null,"order":8},{"name":"Koichi Yamadera","character":"Bakery Worker / Policeman (voice)","img":"biov5jENp2XYfehkcdnRvi796Wi.jpg","order":9},{"name":"Kikuko Inoue","character":"Maki (voice)","img":null,"order":10},{"name":"Yuko Kobayashi","character":"Young Senpai Witch (voice)","img":null,"order":11},{"name":"Mika Doi","character":"Ketto's Mother (voice)","img":null,"order":12},{"name":"Takaya Hashi","character":"Ketto's Father (voice)","img":null,"order":13},{"name":"Chika Sakamoto","character":"Baby (voice)","img":null,"order":14}],"movie:9361":[{"name":"Daniel Day-Lewis","character":"Hawkeye","img":null,"order":0},{"name":"Madeleine Stowe","character":"Cora","img":null,"order":1},{"name":"Jodhi May","character":"Alice","img":null,"order":2},{"name":"Russell Means","character":"Chingachgook","img":null,"order":3},{"name":"Wes Studi","character":"Magua","img":null,"order":4},{"name":"Eric Schweig","character":"Uncas","img":null,"order":5},{"name":"Steven Waddington","character":"Heyward","img":null,"order":6},{"name":"Maurice Ro\u00ebves","character":"Colonel Munro","img":null,"order":7},{"name":"Pete Postlethwaite","character":"Captain Beams","img":null,"order":8},{"name":"Colm Meaney","character":"Major Ambrose","img":null,"order":9},{"name":"Patrice Ch\u00e9reau","character":"General Montcalm","img":null,"order":10},{"name":"Edward Blatchford","character":"Jack Winthrop","img":null,"order":11},{"name":"Terry Kinney","character":"John Cameron","img":null,"order":12},{"name":"Tracey Ellis","character":"Alexandra Cameron","img":null,"order":13},{"name":"Justin M. Rice","character":"James Cameron","img":null,"order":14}],"movie:616":[{"name":"Tom Cruise","character":"Nathan Algren","img":null,"order":0},{"name":"Ken Watanabe","character":"Moritsugu Katsumoto","img":null,"order":1},{"name":"Timothy Spall","character":"Simon Graham","img":null,"order":2},{"name":"Tony Goldwyn","character":"Col. Benjamin Bagley","img":null,"order":3},{"name":"Hiroyuki Sanada","character":"Ujio","img":null,"order":4},{"name":"Koyuki","character":"Taka","img":null,"order":5},{"name":"Shin Koyamada","character":"Nobutada","img":null,"order":6},{"name":"Billy Connolly","character":"Zebulon Gant","img":null,"order":7},{"name":"Togo Igawa","character":"General Hasegawa","img":null,"order":8},{"name":"Shichinosuke Nakamura","character":"Emperor Meiji","img":null,"order":9},{"name":"Masato Harada","character":"Omura","img":null,"order":10},{"name":"William Atherton","character":"Winchester Rep","img":null,"order":11},{"name":"Chad Lindberg","character":"Winchester Rep Assistant","img":null,"order":12},{"name":"Scott Wilson","character":"Ambassador Swanbeck","img":null,"order":13},{"name":"Ray Godshall Sr.","character":"Convention Hall Attendee","img":null,"order":14}],"movie:11774":[{"name":"Emily Browning","character":"Violet Baudelaire","img":null,"order":0},{"name":"Liam Aiken","character":"Klaus Baudelaire","img":null,"order":1},{"name":"Kara Hoffman","character":"Sunny Baudelaire","img":null,"order":2},{"name":"Shelby Hoffman","character":"Sunny Baudelaire","img":null,"order":3},{"name":"Jim Carrey","character":"Count Olaf / Dr. Stephano / Captain Sham","img":null,"order":4},{"name":"Jude Law","character":"Lemony Snicket","img":null,"order":5},{"name":"Timothy Spall","character":"Mr. Poe","img":null,"order":6},{"name":"Meryl Streep","character":"Josephine Anwhistle","img":null,"order":7},{"name":"Billy Connolly","character":"Dr. Montgomery Montgomery","img":null,"order":8},{"name":"Catherine O'Hara","character":"Justice Strauss","img":null,"order":9},{"name":"Jennifer Coolidge","character":"White-Faced Women","img":null,"order":10},{"name":"Jane Adams","character":"White-Faced Women","img":null,"order":11},{"name":"Craig Ferguson","character":"Person of Indeterminate Gender","img":null,"order":12},{"name":"Luis Guzm\u00e1n","character":"Bald Man","img":null,"order":13},{"name":"Jamie Harris","character":"Hook-Handed Man","img":null,"order":14}],"movie:503919":[{"name":"Robert Pattinson","character":"Thomas Howard","img":null,"order":0},{"name":"Willem Dafoe","character":"Thomas Wake","img":null,"order":1},{"name":"Valeriia Karaman","character":"Mermaid","img":null,"order":2},{"name":"Logan Hawkes","character":"Ephraim Winslow","img":null,"order":3},{"name":"Kyla Nicolle","character":"Woman on the Rocks","img":null,"order":4},{"name":"Shaun Clarke","character":"Departing Wickie","img":null,"order":5},{"name":"Pierre Richard","character":"Departing Assistant Wickie","img":null,"order":6},{"name":"Preston Hudson","character":"Tender Mate","img":null,"order":7},{"name":"Jeff Cruts","character":"Tender Mate","img":null,"order":8}],"movie:603":[{"name":"Keanu Reeves","character":"Neo","img":null,"order":0},{"name":"Laurence Fishburne","character":"Morpheus","img":null,"order":1},{"name":"Carrie-Anne Moss","character":"Trinity","img":null,"order":2},{"name":"Hugo Weaving","character":"Agent Smith","img":null,"order":3},{"name":"Gloria Foster","character":"Oracle","img":null,"order":4},{"name":"Joe Pantoliano","character":"Cypher","img":null,"order":5},{"name":"Marcus Chong","character":"Tank","img":null,"order":6},{"name":"Julian Arahanga","character":"Apoc","img":null,"order":7},{"name":"Matt Doran","character":"Mouse","img":null,"order":8},{"name":"Belinda McClory","character":"Switch","img":null,"order":9},{"name":"Anthony Ray Parker","character":"Dozer","img":null,"order":10},{"name":"Paul Goddard","character":"Agent Brown","img":null,"order":11},{"name":"Robert Taylor","character":"Agent Jones","img":null,"order":12},{"name":"David Aston","character":"Rhineheart","img":null,"order":13},{"name":"Marc Aden Gray","character":"Choi","img":null,"order":14}],"movie:604":[{"name":"Keanu Reeves","character":"Neo","img":null,"order":0},{"name":"Laurence Fishburne","character":"Morpheus","img":null,"order":1},{"name":"Carrie-Anne Moss","character":"Trinity","img":null,"order":2},{"name":"Hugo Weaving","character":"Agent Smith","img":null,"order":3},{"name":"Jada Pinkett Smith","character":"Niobe","img":null,"order":4},{"name":"Gloria Foster","character":"The Oracle","img":null,"order":5},{"name":"Harold Perrineau","character":"Link","img":null,"order":6},{"name":"Monica Bellucci","character":"Persephone","img":null,"order":7},{"name":"Harry Lennix","character":"Commander Lock","img":null,"order":8},{"name":"Lambert Wilson","character":"The Merovingian","img":null,"order":9},{"name":"Randall Duk Kim","character":"Keymaker","img":null,"order":10},{"name":"Nona Gaye","character":"Zee","img":null,"order":11},{"name":"Anthony Zerbe","character":"Councillor Hamann","img":null,"order":12},{"name":"Daniel Bernhardt","character":"Agent Johnson","img":null,"order":13},{"name":"Helmut Bakaitis","character":"The Architect","img":null,"order":14}],"movie:624860":[{"name":"Keanu Reeves","character":"Neo / Thomas Anderson","img":null,"order":0},{"name":"Carrie-Anne Moss","character":"Trinity / Tiffany","img":null,"order":1},{"name":"Yahya Abdul-Mateen II","character":"Morpheus / Agent Smith","img":null,"order":2},{"name":"Jonathan Groff","character":"Smith","img":null,"order":3},{"name":"Jessica Henwick","character":"Bugs","img":null,"order":4},{"name":"Neil Patrick Harris","character":"The Analyst","img":null,"order":5},{"name":"Jada Pinkett Smith","character":"Niobe","img":null,"order":6},{"name":"Priyanka Chopra Jonas","character":"Sati","img":null,"order":7},{"name":"Christina Ricci","character":"Gwyn de Vere","img":null,"order":8},{"name":"Lambert Wilson","character":"The Merovingian","img":null,"order":9},{"name":"Andrew Lewis Caldwell","character":"Jude","img":null,"order":10},{"name":"Toby Onwumere","character":"Sequoia","img":null,"order":11},{"name":"Max Riemelt","character":"Sheperd","img":null,"order":12},{"name":"Joshua Grothe","character":"FunktI\u00f8n","img":null,"order":13},{"name":"Brian J. Smith","character":"Berg","img":null,"order":14}],"movie:605":[{"name":"Keanu Reeves","character":"Neo","img":null,"order":0},{"name":"Laurence Fishburne","character":"Morpheus","img":null,"order":1},{"name":"Carrie-Anne Moss","character":"Trinity","img":null,"order":2},{"name":"Hugo Weaving","character":"Agent Smith","img":null,"order":3},{"name":"Jada Pinkett Smith","character":"Niobe","img":null,"order":4},{"name":"Mary Alice","character":"The Oracle","img":null,"order":5},{"name":"Harold Perrineau","character":"Link","img":null,"order":6},{"name":"Collin Chou","character":"Seraph","img":null,"order":7},{"name":"Harry Lennix","character":"Commander Lock","img":null,"order":8},{"name":"Ian Bliss","character":"Bane","img":null,"order":9},{"name":"Lambert Wilson","character":"Merovingian","img":null,"order":10},{"name":"Bruce Spence","character":"Trainman","img":null,"order":11},{"name":"Monica Bellucci","character":"Persephone","img":null,"order":12},{"name":"Nona Gaye","character":"Zee","img":null,"order":13},{"name":"Anthony Zerbe","character":"Councillor Hamann","img":null,"order":14}],"movie:1236153":[{"name":"Chris Pratt","character":"Chris Raven","img":null,"order":0},{"name":"Rebecca Ferguson","character":"Judge Maddox","img":null,"order":1},{"name":"Kali Reis","character":"Jacqueline 'Jaq' Diallo","img":null,"order":2},{"name":"Kylie Rogers","character":"Britt Raven","img":null,"order":3},{"name":"Chris Sullivan","character":"Rob Nelson","img":null,"order":4},{"name":"Jeff Pierre","character":"Patrick Burke","img":null,"order":5},{"name":"Annabelle Wallis","character":"Nicole Raven","img":null,"order":6},{"name":"Rafi Gavron","character":"Holt Charles","img":null,"order":7},{"name":"Kenneth Choi","character":"Ray Vale","img":null,"order":8},{"name":"Jamie McBride","character":"Dan Vogel","img":null,"order":9},{"name":"Ross Gosla","character":"David Webb","img":null,"order":10},{"name":"Mark Daneri","character":"Jeff Martin","img":null,"order":11},{"name":"Haydn Dalton","character":"Bill Peterson","img":null,"order":12},{"name":"Michael C. Mahon","character":"Booking Sergeant","img":null,"order":13},{"name":"Noah Fearnley","character":"Tattoed Sleazebag","img":null,"order":14}],"movie:1242332":[{"name":"Bob Odenkirk","character":"Ulysses Richardson","img":null,"order":0},{"name":"Henry Winkler","character":"Mayor Kibner","img":null,"order":1},{"name":"Lena Headey","character":"Moira","img":null,"order":2},{"name":"Billy MacLellan","character":"Deputy Mike Nelson","img":null,"order":3},{"name":"Ryan Allen","character":"Deputy Blaine Anderson","img":null,"order":4},{"name":"Reena Jolly","character":"Lori","img":null,"order":5},{"name":"Brendan Fletcher","character":"Keith","img":null,"order":6},{"name":"Peter Shinkoda","character":"Joe","img":null,"order":7},{"name":"Jess McLeod","character":"Alex","img":null,"order":8},{"name":"Alex MacMillan","character":"Kent","img":null,"order":9},{"name":"Dan De Jaeger","character":"Ernie","img":null,"order":10},{"name":"John C. MacDonald","character":"Kenny","img":null,"order":11},{"name":"David Lawrence Brown","character":"Dr. Walter Vilie","img":null,"order":12},{"name":"Derek Barnes","character":"James","img":null,"order":13},{"name":"Megan MacArton","character":"Mary Beth","img":null,"order":14}],"movie:454227":[{"name":"Chris Pine","character":"Robert Bruce, Earl of Carrick","img":null,"order":0},{"name":"Aaron Taylor-Johnson","character":"James Douglas, Lord of Douglas","img":null,"order":1},{"name":"Florence Pugh","character":"Elizabeth Burgh","img":null,"order":2},{"name":"Billy Howle","character":"Edward, Prince of Wales","img":null,"order":3},{"name":"Sam Spruell","character":"Aymer de Valence, Earl of Pembroke","img":null,"order":4},{"name":"Tony Curran","character":"Angus Og Macdonald, Lord of Islay","img":null,"order":5},{"name":"Callan Mulvey","character":"John III Comyn, Lord of Badenoch","img":null,"order":6},{"name":"James Cosmo","character":"Robert Bruce Senior","img":null,"order":7},{"name":"Stephen Dillane","character":"King Edward I of England","img":null,"order":8},{"name":"Steven Cree","character":"Sir Christopher Seton","img":null,"order":9},{"name":"Alastair Mackenzie","character":"John Strathbogie, Earl of Atholl","img":null,"order":10},{"name":"Chris Fulton","character":"Euan Bruce","img":null,"order":11},{"name":"Lorne MacFadyen","character":"Neil Bruce","img":null,"order":12},{"name":"Jack Greenlees","character":"Alexander Bruce","img":null,"order":13},{"name":"Rebecca Robin","character":"Queen Margaret of England","img":null,"order":14}],"movie:4547":[{"name":"Jodie Foster","character":"Meg Altman","img":null,"order":0},{"name":"Kristen Stewart","character":"Sarah Altman","img":null,"order":1},{"name":"Forest Whitaker","character":"Burnham","img":null,"order":2},{"name":"Dwight Yoakam","character":"Raoul","img":null,"order":3},{"name":"Jared Leto","character":"Junior","img":null,"order":4},{"name":"Patrick Bauchau","character":"Stephen Altman","img":null,"order":5},{"name":"Ann Magnuson","character":"Lydia Lynch","img":null,"order":6},{"name":"Ian Buchanan","character":"Evan Kurlander","img":null,"order":7},{"name":"Andrew Kevin Walker","character":"Sleepy Neighbor","img":null,"order":8},{"name":"Paul Schulze","character":"Officer Keeney","img":null,"order":9},{"name":"Mel Rodriguez","character":"Officer Morales","img":null,"order":10},{"name":"Richard Conant","character":"SWAT Cop","img":null,"order":11},{"name":"Paul Simon","character":"SWAT Cop","img":null,"order":12},{"name":"Victor Thrash","character":"SWAT Cop","img":null,"order":13},{"name":"Ken Turner","character":"SWAT Cop","img":null,"order":14}],"movie:2024":[{"name":"Mel Gibson","character":"Benjamin Martin","img":null,"order":0},{"name":"Heath Ledger","character":"Gabriel Martin","img":null,"order":1},{"name":"Joely Richardson","character":"Charlotte Selton","img":null,"order":2},{"name":"Jason Isaacs","character":"Col. William Tavington","img":null,"order":3},{"name":"Chris Cooper","character":"Col. Harry Burwell","img":null,"order":4},{"name":"Tch\u00e9ky Karyo","character":"Jean Villeneuve","img":null,"order":5},{"name":"Ren\u00e9 Auberjonois","character":"Reverend Oliver","img":null,"order":6},{"name":"Lisa Brenner","character":"Anne Howard","img":null,"order":7},{"name":"Tom Wilkinson","character":"Gen. Cornwallis","img":null,"order":8},{"name":"Donal Logue","character":"Dan Scott","img":null,"order":9},{"name":"Leon Rippy","character":"John Billings","img":null,"order":10},{"name":"Adam Baldwin","character":"Capt. Wilkins","img":"lfbyJWNWGbiYfU0Yr1tjn6Trd2V.jpg","order":11},{"name":"Jay Arlen Jones","character":"Occam","img":null,"order":12},{"name":"Joey D. Vieira","character":"Peter Howard","img":null,"order":13},{"name":"Gregory Smith","character":"Thomas Martin","img":null,"order":14}],"movie:875828":[{"name":"Cillian Murphy","character":"Tommy Shelby","img":null,"order":0},{"name":"Barry Keoghan","character":"Duke Shelby","img":null,"order":1},{"name":"Rebecca Ferguson","character":"Kaulo / Zelda","img":null,"order":2},{"name":"Tim Roth","character":"John Beckett","img":null,"order":3},{"name":"Stephen Graham","character":"Hayden Stagg","img":null,"order":4},{"name":"Sophie Rundle","character":"Ada Shelby","img":null,"order":5},{"name":"Ned Dennehy","character":"Charlie Strong","img":null,"order":6},{"name":"Packy Lee","character":"Johnny Dogs","img":null,"order":7},{"name":"Ian Peck","character":"Curly","img":null,"order":8},{"name":"Jay Lycurgo","character":"Elijah","img":null,"order":9},{"name":"Kasper Hilton-Hille","character":"Karl Thorne","img":null,"order":10},{"name":"Ruby Ashbourne Serkis","character":"Agnes Shelby","img":null,"order":11},{"name":"Bonnie Stott","character":"Ruby","img":null,"order":12},{"name":"Thomas Arnold","character":"Virgil","img":null,"order":13},{"name":"Sam Baker Jones","character":"Jake","img":null,"order":14}],"movie:12429":[{"name":"Yuria Kozuki","character":"Ponyo (voice)","img":null,"order":0},{"name":"Hiroki Doi","character":"Sosuke (voice)","img":null,"order":1},{"name":"George Tokoro","character":"Fujimoto (voice)","img":null,"order":2},{"name":"Tomoko Yamaguchi","character":"Risa (voice)","img":null,"order":3},{"name":"Yuki Amami","character":"Gran Mamare (voice)","img":null,"order":4},{"name":"Kazushige Nagashima","character":"Koichi (voice)","img":null,"order":5},{"name":"Akiko Yano","character":"Ponyo's Sister (voice)","img":null,"order":6},{"name":"Shin'ichi Hatori","character":"Anchorman (voice)","img":null,"order":7},{"name":"Tokie Hidari","character":"Kayo (voice)","img":null,"order":8},{"name":"Rumi Hiiragi","character":"Young Mother (voice)","img":null,"order":9},{"name":"Tomoko Naraoka","character":"Yoshie (voice)","img":null,"order":10},{"name":"Kazuko Yoshiyuki","character":"Toki (voice)","img":null,"order":11},{"name":"Eimi Hiraoka","character":"Kumiko (voice)","img":null,"order":12},{"name":"Nozomi \u014chashi","character":"Karen (voice)","img":null,"order":13},{"name":"Akiko Takeguchi","character":"Noriko (voice)","img":null,"order":14}],"movie:11621":[{"name":"Sh\u016bichir\u014d Moriyama","character":"Porco Rosso (voice)","img":null,"order":0},{"name":"Tokiko Kato","character":"Madame Gina (voice)","img":null,"order":1},{"name":"Bunshi Katsura VI","character":"Grandpa Piccolo (voice)","img":null,"order":2},{"name":"Tsunehiko Kamij\u00f4","character":"Mamma Aiuto Boss (voice)","img":null,"order":3},{"name":"Akemi Okamura","character":"Fio Piccolo (voice)","img":null,"order":4},{"name":"Akio Otsuka","character":"Donald Curtis (voice)","img":null,"order":5},{"name":"Hiroko Seki","character":"Granny (voice)","img":null,"order":6},{"name":"Masayuki Inagaki","character":"Major Ferrarin (voice)","img":null,"order":7},{"name":"Reiz\u014d Nomoto","character":"Mamma Aiuto Gang Member (voice)","img":null,"order":8},{"name":"Osamu Saka","character":"Mamma Aiuto Gang Member (voice)","img":null,"order":9},{"name":"Yu Shimaka","character":"Mamma Aiuto Gang Member (voice)","img":null,"order":10},{"name":"Yuzuru Fujimoto","character":"Mamma Aiuto Gang Member (voice)","img":null,"order":11},{"name":"Tatsuyuki Jinnai","character":"Mamma Aiuto Gang Member (voice)","img":null,"order":12},{"name":"Kazunori Arai","character":"Mamma Aiuto Gang Member (voice)","img":null,"order":13},{"name":"Nobuo Tanaka","character":"Mamma Aiuto Gang Member (voice)","img":null,"order":14}],"movie:128":[{"name":"Yoji Matsuda","character":"Ashitaka (voice)","img":null,"order":0},{"name":"Yuriko Ishida","character":"San / Kaya (voice)","img":null,"order":1},{"name":"Yuko Tanaka","character":"Eboshi Gozen (voice)","img":null,"order":2},{"name":"Kaoru Kobayashi","character":"Jikobo (voice)","img":null,"order":3},{"name":"Masahiko Nishimura","character":"Kouroku (voice)","img":null,"order":4},{"name":"Tsunehiko Kamij\u00f4","character":"Gonza (voice)","img":null,"order":5},{"name":"Akihiro Miwa","character":"Mrs. Moro (voice)","img":null,"order":6},{"name":"Mitsuko Mori","character":"Mrs. Hii (voice)","img":null,"order":7},{"name":"Hisaya Morishige","character":"Chief of Affairs (voice)","img":null,"order":8},{"name":"Sumi Shimamoto","character":"Toki (voice)","img":null,"order":9},{"name":"Tetsu Watanabe","character":"Wild Dog (voice)","img":null,"order":10},{"name":"Makoto Sat\u014d","character":"Tatari God (voice)","img":null,"order":11},{"name":"Akira Nagoya","character":"Cowherd (voice)","img":null,"order":12},{"name":"Kei Iinuma","character":"Chief of the Sick (voice)","img":null,"order":13},{"name":"Tsuzuki Kayako","character":"Kiyo (voice)","img":null,"order":14}],"movie:146233":[{"name":"Hugh Jackman","character":"Keller Dover","img":null,"order":0},{"name":"Jake Gyllenhaal","character":"Detective Loki","img":null,"order":1},{"name":"Viola Davis","character":"Nancy Birch","img":null,"order":2},{"name":"Maria Bello","character":"Grace Dover","img":null,"order":3},{"name":"Terrence Howard","character":"Franklin Birch","img":null,"order":4},{"name":"Melissa Leo","character":"Holly Jones","img":null,"order":5},{"name":"Paul Dano","character":"Alex Jones","img":null,"order":6},{"name":"Dylan Minnette","character":"Ralph Dover","img":null,"order":7},{"name":"Zo\u00eb Soul","character":"Eliza Birch","img":null,"order":8},{"name":"Erin Gerasimovich","character":"Anna Dover","img":null,"order":9},{"name":"Kyla-Drew","character":"Joy Birch","img":null,"order":10},{"name":"Wayne Duvall","character":"Captain Richard O'Malley","img":null,"order":11},{"name":"Len Cariou","character":"Father Patrick Dunn","img":null,"order":12},{"name":"David Dastmalchian","character":"Bob Taylor","img":null,"order":13},{"name":"Brad James","character":"Officer Carter","img":null,"order":14}],"movie:6439":[{"name":"Frankie Muniz","character":"Stripes (voice)","img":null,"order":0},{"name":"Hayden Panettiere","character":"Channing Walsh","img":null,"order":1},{"name":"Bruce Greenwood","character":"Nolan Walsh","img":null,"order":2},{"name":"Mandy Moore","character":"Sandy (voice)","img":null,"order":3},{"name":"Wendie Malick","character":"Clara Dalrymple","img":null,"order":4},{"name":"M. Emmet Walsh","character":"Woodzie","img":null,"order":5},{"name":"Snoop Dogg","character":"Lightning (voice)","img":"rbxBK2m6fEq0oHeMoBUMVYkJEdJ.jpg","order":6},{"name":"Michael Clarke Duncan","character":"Clydesdale (voice)","img":null,"order":7},{"name":"Jeff Foxworthy","character":"Reggie (voice)","img":null,"order":8},{"name":"Whoopi Goldberg","character":"Franny (voice)","img":null,"order":9},{"name":"Steve Harvey","character":"Buzz (voice)","img":null,"order":10},{"name":"David Spade","character":"Scuzz (voice)","img":null,"order":11},{"name":"Dustin Hoffman","character":"Tucker (voice)","img":null,"order":12},{"name":"Joshua Jackson","character":"Trenton's Pride (voice)","img":null,"order":13},{"name":"Joe Pantoliano","character":"Goose (voice)","img":null,"order":14}],"movie:641":[{"name":"Ellen Burstyn","character":"Sara Goldfarb","img":null,"order":0},{"name":"Jared Leto","character":"Harry Goldfarb","img":null,"order":1},{"name":"Jennifer Connelly","character":"Marion Silver","img":null,"order":2},{"name":"Marlon Wayans","character":"Tyrone C. Love","img":null,"order":3},{"name":"Christopher McDonald","character":"Tappy Tibbons","img":null,"order":4},{"name":"Louise Lasser","character":"Ada","img":null,"order":5},{"name":"Marcia Jean Kurtz","character":"Rae","img":null,"order":6},{"name":"Janet Sarno","character":"Mrs. Pearlman","img":null,"order":7},{"name":"Suzanne Shepherd","character":"Mrs. Scarlini","img":null,"order":8},{"name":"Joanne Gordon","character":"Mrs. Ovadia","img":null,"order":9},{"name":"Charlotte Aronofsky","character":"Mrs. Miles","img":null,"order":10},{"name":"Mark Margolis","character":"Mr. Rabinowitz","img":null,"order":11},{"name":"Michael Kaycheck","character":"Donut Cop","img":null,"order":12},{"name":"Jack A. O'Connell","character":"Corn Dog Stand Boss","img":null,"order":13},{"name":"Chas Mastin","character":"Lyle Russel","img":null,"order":14}],"movie:330459":[{"name":"Felicity Jones","character":"Jyn Erso","img":null,"order":0},{"name":"Diego Luna","character":"Cassian Andor","img":"qwbjcyDN37OHiln4a6P4LP31o7F.jpg","order":1},{"name":"Alan Tudyk","character":"K-2SO","img":"jUuUbPuMGonFT5E2pcs4alfqaCN.jpg","order":2},{"name":"Donnie Yen","character":"Chirrut Imwe","img":null,"order":3},{"name":"Jiang Wen","character":"Baze Malbus","img":null,"order":4},{"name":"Ben Mendelsohn","character":"Orson Krennic","img":null,"order":5},{"name":"Guy Henry","character":"Governor Tarkin","img":null,"order":6},{"name":"Forest Whitaker","character":"Saw Gerrera","img":null,"order":7},{"name":"Riz Ahmed","character":"Bodhi Rook","img":null,"order":8},{"name":"Mads Mikkelsen","character":"Galen Erso","img":null,"order":9},{"name":"Jimmy Smits","character":"Bail Organa","img":null,"order":10},{"name":"Alistair Petrie","character":"General Draven","img":null,"order":11},{"name":"Genevieve O'Reilly","character":"Mon Mothma","img":"4eOoW1PNBZfxRW0g8RmYH8bL6mq.jpg","order":12},{"name":"Ben Daniels","character":"General Merrick","img":"phEIvq0Ay2KjI5ewmVvpQ1a29GJ.jpg","order":13},{"name":"Paul Kasey","character":"Admiral Raddus","img":null,"order":14}],"movie:13156":[{"name":"Michael Caine","character":"Garth","img":null,"order":0},{"name":"Robert Duvall","character":"Hub","img":null,"order":1},{"name":"Haley Joel Osment","character":"Walter","img":null,"order":2},{"name":"Josh Lucas","character":"Adult Walter","img":null,"order":3},{"name":"Kyra Sedgwick","character":"Mae","img":null,"order":4},{"name":"Christian Kane","character":"Young Hub","img":null,"order":5},{"name":"Nicky Katt","character":"Stan","img":null,"order":6},{"name":"Eric Balfour","character":"Sheik's Grandson","img":null,"order":7},{"name":"Kevin Haberer","character":"Young Garth","img":null,"order":8},{"name":"Emmanuelle Vaugier","character":"Jasmine","img":null,"order":9},{"name":"Mitchel Musso","character":"Boy","img":null,"order":10},{"name":"Marc Musso","character":"Boy","img":null,"order":11},{"name":"Michael O'Neill","character":"Ralph","img":null,"order":12},{"name":"Deirdre O'Connell","character":"Helen","img":null,"order":13},{"name":"Adam Ozturk","character":"The Sheik","img":null,"order":14}],"movie:412117":[{"name":"Patton Oswalt","character":"Max (voice)","img":null,"order":0},{"name":"Kevin Hart","character":"Snowball (voice)","img":null,"order":1},{"name":"Eric Stonestreet","character":"Duke (voice)","img":null,"order":2},{"name":"Jenny Slate","character":"Gidget (voice)","img":null,"order":3},{"name":"Tiffany Haddish","character":"Daisy (voice)","img":null,"order":4},{"name":"Lake Bell","character":"Chloe (voice)","img":null,"order":5},{"name":"Nick Kroll","character":"Sergei (voice)","img":null,"order":6},{"name":"Dana Carvey","character":"Pops (voice)","img":null,"order":7},{"name":"Ellie Kemper","character":"Katie (voice)","img":null,"order":8},{"name":"Harrison Ford","character":"Rooster (voice)","img":null,"order":9},{"name":"Chris Renaud","character":"Norman / Additional Voices (voice)","img":null,"order":10},{"name":"Bobby Moynihan","character":"Mel (voice)","img":null,"order":11},{"name":"Hannibal Buress","character":"Buddy (voice)","img":null,"order":12},{"name":"Pete Holmes","character":"Chuck (voice)","img":null,"order":13},{"name":"Henry Lynch","character":"Liam (voice)","img":null,"order":14}],"movie:1072876":[{"name":"Jake Johnson","character":"Tommy","img":null,"order":0},{"name":"Anna Kendrick","character":"Maddy","img":null,"order":1},{"name":"Natalie Morales","character":"Theresa","img":null,"order":2},{"name":"Andy Samberg","character":"Andy Samberg","img":null,"order":3},{"name":"Mary Holland","character":"Amy","img":null,"order":4},{"name":"Emily Hampshire","character":"Mary","img":null,"order":5},{"name":"Nancy Lenehan","character":"Laurie","img":null,"order":6},{"name":"Daryl J. Johnson","character":"Malcolm","img":null,"order":7},{"name":"Miriam Flynn","character":"Becky Ann","img":null,"order":8},{"name":"Boban Marjanovi\u0107","character":"7 Foot Man","img":null,"order":9},{"name":"Biff Wiff","character":"James / Walter","img":null,"order":10},{"name":"Eduardo Franco","character":"P.A. Ninja","img":null,"order":11},{"name":"Jeff Kober","character":"Cowboy","img":null,"order":12},{"name":"Christopher Lloyd","character":"Dennis Walcott","img":null,"order":13},{"name":"Theo Wilson","character":"Sinbad Guy","img":null,"order":14}],"movie:9040":[{"name":"Al Pacino","character":"Officer Frank Serpico","img":null,"order":0},{"name":"John Randolph","character":"Sidney Green","img":null,"order":1},{"name":"Jack Kehoe","character":"Tom Keough","img":null,"order":2},{"name":"Biff McGuire","character":"Captain McClain","img":null,"order":3},{"name":"Barbara Eda-Young","character":"Laurie","img":null,"order":4},{"name":"Cornelia Sharpe","character":"Leslie Lane","img":null,"order":5},{"name":"Tony Roberts","character":"Bob Blair","img":null,"order":6},{"name":"John Medici","character":"Pasquale","img":null,"order":7},{"name":"Allan Rich","character":"D. A. Tauber","img":null,"order":8},{"name":"Norman Ornellas","character":"Rubello","img":null,"order":9},{"name":"Edward Grover","character":"Lombardo","img":null,"order":10},{"name":"Albert Henderson","character":"Peluce","img":null,"order":11},{"name":"Hank Garrett","character":"Malone","img":null,"order":12},{"name":"Damien Leake","character":"Joey","img":null,"order":13},{"name":"Joseph Bova","character":"Potts","img":null,"order":14}],"movie:479":[{"name":"Samuel L. Jackson","character":"John Shaft","img":null,"order":0},{"name":"Vanessa Williams","character":"Carmen Vasquez","img":null,"order":1},{"name":"Jeffrey Wright","character":"Peoples Hernandez","img":null,"order":2},{"name":"Christian Bale","character":"Walter Wade, Jr.","img":null,"order":3},{"name":"Busta Rhymes","character":"Rasaan","img":null,"order":4},{"name":"Dan Hedaya","character":"Jack Roselli","img":null,"order":5},{"name":"Toni Collette","character":"Diane Palmieri","img":null,"order":6},{"name":"Richard Roundtree","character":"\"Uncle\" John Shaft","img":null,"order":7},{"name":"Ruben Santiago-Hudson","character":"Jimmy Groves","img":null,"order":8},{"name":"Josef Sommer","character":"Curt Flemming","img":null,"order":9},{"name":"Lynne Thigpen","character":"Carla Howard","img":null,"order":10},{"name":"Philip Bosco","character":"Walter Wade Senior","img":null,"order":11},{"name":"Pat Hingle","character":"Judge Dennis Bradford","img":null,"order":12},{"name":"Lee Tergesen","character":"Luger","img":null,"order":13},{"name":"Daniel von Bargen","character":"Lt Kearney","img":null,"order":14}],"movie:378064":[{"name":"Miyu Irino","character":"Shouya Ishida (voice)","img":null,"order":0},{"name":"Saori Hayami","character":"Shouko Nishimiya (voice)","img":null,"order":1},{"name":"Aoi Yuki","character":"Yuzuru Nishimiya (voice)","img":null,"order":2},{"name":"Kensho Ono","character":"Tomohiro Nagatsuka (voice)","img":null,"order":3},{"name":"Yuki Kaneko","character":"Naoka Ueno (voice)","img":null,"order":4},{"name":"Yui Ishikawa","character":"Miyoko Sahara (voice)","img":null,"order":5},{"name":"Megumi Han","character":"Miki Kawai (voice)","img":null,"order":6},{"name":"Toshiyuki Toyonaga","character":"Satoshi Mashiba (voice)","img":null,"order":7},{"name":"Mayu Matsuoka","character":"Shouya Ishida as an Elementary School Boy (voice)","img":null,"order":8},{"name":"Sachiko Kojima","character":"Kazuki Shimada as an Elementary School Boy (voice)","img":null,"order":9},{"name":"Hana Takeda","character":"Keisuke Hirose as an Elementary School Boy (voice)","img":null,"order":10},{"name":"Fuminori Komatsu","character":"Takeuchi-sensei (voice)","img":null,"order":11},{"name":"Ikuko Tani","character":"Ito Nishimiya (voice)","img":null,"order":12},{"name":"Erena Kamata","character":"Maria Ishida (voice)","img":null,"order":13},{"name":"Ayano Hamaguchi","character":"Shouya's Sister (voice)","img":null,"order":14}],"movie:14411":[{"name":"Brad Pitt","character":"Sinbad (voice)","img":null,"order":0},{"name":"Catherine Zeta-Jones","character":"Marina (voice)","img":null,"order":1},{"name":"Michelle Pfeiffer","character":"Eris (voice)","img":null,"order":2},{"name":"Joseph Fiennes","character":"Proteus (voice)","img":null,"order":3},{"name":"Dennis Haysbert","character":"Kale (voice)","img":null,"order":4},{"name":"Timothy West","character":"Dymas (voice)","img":null,"order":5},{"name":"Adriano Giannini","character":"Rat (voice)","img":null,"order":6},{"name":"Raman Hui Shing-Ngai","character":"Jin (voice)","img":null,"order":7},{"name":"Chung Chan","character":"Li (voice)","img":null,"order":8},{"name":"Jim Cummings","character":"Luca / Additional Voices (voice)","img":null,"order":9},{"name":"Conrad Vernon","character":"Jed (voice)","img":null,"order":10},{"name":"Andrew Birch","character":"Grum / Chum (voice)","img":null,"order":11},{"name":"Chris Miller","character":"Tower Guard (voice)","img":null,"order":12},{"name":"Frank Welker","character":"Spike (voice) (uncredited)","img":null,"order":13}],"movie:288036":[{"name":"Jason Sudeikis","character":"Jake Harper","img":null,"order":0},{"name":"Alison Brie","character":"Lainey Dalton","img":null,"order":1},{"name":"Adam Scott","character":"Matthew Sobvechik","img":null,"order":2},{"name":"Jason Mantzoukas","character":"Xander","img":null,"order":3},{"name":"Natasha Lyonne","character":"Kara","img":null,"order":4},{"name":"Adam Brody","character":"Sam","img":null,"order":5},{"name":"Amanda Peet","character":"Paula","img":null,"order":6},{"name":"Katherine Waterston","character":"Emma","img":null,"order":7},{"name":"Marc Blucas","character":"Chris Smith","img":null,"order":8},{"name":"Margarita Levieva","character":"Hannah","img":null,"order":9},{"name":"Andrea Savage","character":"Naomi","img":null,"order":10},{"name":"Daniella Pineda","character":"Danica","img":null,"order":11},{"name":"Remy Nozik","character":"George","img":null,"order":12},{"name":"Megan Guinan","character":"Alice","img":null,"order":13},{"name":"Anna Margaret Hollyman","character":"Renee","img":null,"order":14}],"movie:110415":[{"name":"Chris Evans","character":"Curtis","img":null,"order":0},{"name":"Song Kang-ho","character":"Namgoong Minsu","img":null,"order":1},{"name":"Ed Harris","character":"Wilford","img":null,"order":2},{"name":"John Hurt","character":"Gilliam","img":null,"order":3},{"name":"Tilda Swinton","character":"Mason","img":null,"order":4},{"name":"Jamie Bell","character":"Edgar","img":null,"order":5},{"name":"Octavia Spencer","character":"Tanya","img":null,"order":6},{"name":"Ewen Bremner","character":"Andrew","img":null,"order":7},{"name":"Ko Asung","character":"Yona","img":null,"order":8},{"name":"Alison Pill","character":"Teacher","img":null,"order":9},{"name":"Luke Pasqualino","character":"Grey","img":null,"order":10},{"name":"Vlad Ivanov","character":"Franco The Elder","img":null,"order":11},{"name":"Adnan Haskovi\u0107","character":"Franco The Younger","img":null,"order":12},{"name":"Emma Levie","character":"Claude","img":null,"order":13},{"name":"Steve Park","character":"Fuyu","img":null,"order":14}],"movie:969681":[{"name":"Tom Holland","character":"Peter Parker / Spider-Man","img":"xKBAaPIa1c7tzZD3Y0MhBLv4hPE.jpg","order":0},{"name":"Sadie Sink","character":"Jean Grey","img":null,"order":1},{"name":"Tramell Tillman","character":"William 'Bill' Metzger","img":null,"order":2},{"name":"Zendaya","character":"MJ","img":null,"order":3},{"name":"Jacob Batalon","character":"Ned Leeds","img":null,"order":4},{"name":"Jon Bernthal","character":"Frank Castle / Punisher","img":null,"order":5},{"name":"Mark Ruffalo","character":"Bruce Banner / Hulk","img":null,"order":6},{"name":"Florence Pugh","character":"Yelena Belova / Black Widow","img":null,"order":7},{"name":"Liza Col\u00f3n-Zayas","character":"Detective Jean DeWolff","img":null,"order":8},{"name":"Marisa Tomei","character":"May Parker","img":null,"order":9},{"name":"Naomi Watts","character":"E.V. (voice)","img":null,"order":10},{"name":"Michael Mando","character":"Mac Gargan / Scorpion","img":null,"order":11},{"name":"Keith David","character":"Narrator of Spider Video (voice)","img":null,"order":12},{"name":"Marvin Jones III","character":"Tombstone","img":null,"order":13},{"name":"Olivia Booth-Ford","character":"Sara","img":null,"order":14}],"movie:429617":[{"name":"Tom Holland","character":"Peter Parker / Spider-Man","img":"xKBAaPIa1c7tzZD3Y0MhBLv4hPE.jpg","order":0},{"name":"Jake Gyllenhaal","character":"Quentin Beck / Mysterio","img":null,"order":1},{"name":"Samuel L. Jackson","character":"Nick Fury","img":null,"order":2},{"name":"Marisa Tomei","character":"May Parker","img":null,"order":3},{"name":"Jon Favreau","character":"Happy Hogan","img":null,"order":4},{"name":"Zendaya","character":"MJ","img":null,"order":5},{"name":"Jacob Batalon","character":"Ned Leeds","img":null,"order":6},{"name":"Tony Revolori","character":"Flash Thompson","img":null,"order":7},{"name":"Angourie Rice","character":"Betty Brant","img":null,"order":8},{"name":"Remy Hii","character":"Brad Davis","img":null,"order":9},{"name":"Martin Starr","character":"Mr. Harrington","img":null,"order":10},{"name":"JB Smoove","character":"Mr. Dell","img":null,"order":11},{"name":"Jorge Lendeborg Jr.","character":"Jason Ionello","img":null,"order":12},{"name":"Cobie Smulders","character":"Maria Hill","img":null,"order":13},{"name":"Numan Acar","character":"Dimitri","img":null,"order":14}],"movie:315635":[{"name":"Tom Holland","character":"Peter Parker / Spider-Man","img":"xKBAaPIa1c7tzZD3Y0MhBLv4hPE.jpg","order":0},{"name":"Michael Keaton","character":"Adrian Toomes / Vulture","img":null,"order":1},{"name":"Robert Downey Jr.","character":"Tony Stark / Iron Man","img":null,"order":2},{"name":"Marisa Tomei","character":"May Parker","img":null,"order":3},{"name":"Jon Favreau","character":"Happy Hogan","img":null,"order":4},{"name":"Gwyneth Paltrow","character":"Pepper Potts","img":null,"order":5},{"name":"Zendaya","character":"Michelle","img":null,"order":6},{"name":"Donald Glover","character":"Aaron Davis","img":null,"order":7},{"name":"Jacob Batalon","character":"Ned","img":null,"order":8},{"name":"Laura Harrier","character":"Liz","img":null,"order":9},{"name":"Tony Revolori","character":"Flash","img":null,"order":10},{"name":"Bokeem Woodbine","character":"Herman Schultz / Shocker #2","img":null,"order":11},{"name":"Tyne Daly","character":"Anne Marie Hoag","img":null,"order":12},{"name":"Abraham Attah","character":"Abraham","img":null,"order":13},{"name":"Hannibal Buress","character":"Coach Wilson","img":null,"order":14}],"movie:634649":[{"name":"Tom Holland","character":"Peter Parker / Spider-Man","img":"xKBAaPIa1c7tzZD3Y0MhBLv4hPE.jpg","order":0},{"name":"Zendaya","character":"MJ","img":null,"order":1},{"name":"Benedict Cumberbatch","character":"Doctor Strange","img":null,"order":2},{"name":"Jacob Batalon","character":"Ned Leeds","img":null,"order":3},{"name":"Jon Favreau","character":"Happy Hogan","img":null,"order":4},{"name":"Jamie Foxx","character":"Max Dillon / Electro","img":null,"order":5},{"name":"Willem Dafoe","character":"Norman Osborn / Green Goblin","img":null,"order":6},{"name":"Alfred Molina","character":"Dr. Otto Octavius / Doc Ock","img":null,"order":7},{"name":"Benedict Wong","character":"Wong","img":null,"order":8},{"name":"Tony Revolori","character":"Flash Thompson","img":null,"order":9},{"name":"Marisa Tomei","character":"May Parker","img":null,"order":10},{"name":"Andrew Garfield","character":"Peter Parker / Spider-Man","img":null,"order":11},{"name":"Tobey Maguire","character":"Peter Parker / Spider-Man","img":null,"order":12},{"name":"Angourie Rice","character":"Betty Brant","img":null,"order":13},{"name":"Arian Moayed","character":"Agent Cleary","img":null,"order":14}],"movie:129":[{"name":"Rumi Hiiragi","character":"Chihiro (voice)","img":null,"order":0},{"name":"Miyu Irino","character":"Haku (voice)","img":null,"order":1},{"name":"Mari Natsuki","character":"Yubaba / Zeniba (voice)","img":null,"order":2},{"name":"Takashi Naito","character":"Father (voice)","img":null,"order":3},{"name":"Yasuko Sawaguchi","character":"Mother (voice)","img":null,"order":4},{"name":"Tatsuya Gashuin","character":"Aogaeru (voice)","img":null,"order":5},{"name":"Ryunosuke Kamiki","character":"Boh (voice)","img":null,"order":6},{"name":"Yumi Tamai","character":"Rin (voice)","img":null,"order":7},{"name":"Yo Oizumi","character":"Bandai Frog (voice)","img":null,"order":8},{"name":"Koba Hayashi","character":"River Spirit (voice)","img":null,"order":9},{"name":"Tsunehiko Kamij\u00f4","character":"Chichiyaku (voice)","img":null,"order":10},{"name":"Takehiko Ono","character":"Aniyaku (voice)","img":null,"order":11},{"name":"Bunta Sugawara","character":"Kamaji (voice)","img":null,"order":12},{"name":"Shigeru Wakita","character":"(voice)","img":null,"order":13},{"name":"Shirou Saitou","character":"(voice)","img":null,"order":14}],"movie:933260":[{"name":"Demi Moore","character":"Elisabeth","img":null,"order":0},{"name":"Margaret Qualley","character":"Sue","img":null,"order":1},{"name":"Dennis Quaid","character":"Harvey","img":null,"order":2},{"name":"Edward Hamilton-Clark","character":"Fred","img":null,"order":3},{"name":"Gore Abrams","character":"Oliver","img":null,"order":4},{"name":"Oscar Lesage","character":"Troy","img":null,"order":5},{"name":"Christian Erickson","character":"Man at Diner","img":null,"order":6},{"name":"Robin Greer","character":"Male Nurse","img":null,"order":7},{"name":"Tom Morton","character":"Doctor","img":null,"order":8},{"name":"Hugo Diego Garcia","character":"Diego - Boyfriend","img":null,"order":9},{"name":"Daniel Knight","character":"Casting Director","img":null,"order":10},{"name":"Jonathon Carley","character":"Assistant Casting Director","img":null,"order":11},{"name":"Jiselle Henderkott","character":"Girl Auditioning / New Year's Eve Show Dancer","img":null,"order":12},{"name":"Akil Wingate","character":"TV Host","img":null,"order":13},{"name":"Vincent Colombe","character":"Man in Suit #1 - Harvey's Office","img":null,"order":14}],"movie:149871":[{"name":"Aki Asakura","character":"The Princess Kaguya (voice)","img":null,"order":0},{"name":"Takeo Chii","character":"Sanuki no Miyatsuko (voice)","img":null,"order":1},{"name":"Nobuko Miyamoto","character":"\u014cna / Narrator (voice)","img":null,"order":2},{"name":"Kengo Kora","character":"Sutemaru (voice)","img":null,"order":3},{"name":"Atsuko Takahata","character":"Lady Sagami (voice)","img":null,"order":4},{"name":"Tomoko Tabata","character":"Menowarawa (voice)","img":null,"order":5},{"name":"Shinosuke Tatekawa","character":"Lord Inbe no Akita (voice)","img":null,"order":6},{"name":"Takaya Kamikawa","character":"Prince Ishitsukuri (voice)","img":null,"order":7},{"name":"Hikaru Ij\u016bin","character":"Minister of the Right Abe (voice)","img":null,"order":8},{"name":"Ryudo Uzaki","character":"Grand Counselor Otomo (voice)","img":null,"order":9},{"name":"Shichinosuke Nakamura","character":"The Emperor (voice)","img":null,"order":10},{"name":"Isao Hashizume","character":"Prince Kuramochi (voice)","img":null,"order":11},{"name":"Tatsuya Nakadai","character":"Charcoal-maker Old Man (voice)","img":null,"order":12},{"name":"Yukiji Asaoka","character":"Kita no kata (voice)","img":null,"order":13},{"name":"Tamaki Kojo","character":"Middle Counselor Isonokami (voice)","img":null,"order":14}],"movie:103":[{"name":"Robert De Niro","character":"Travis Bickle","img":null,"order":0},{"name":"Jodie Foster","character":"Iris","img":null,"order":1},{"name":"Cybill Shepherd","character":"Betsy","img":null,"order":2},{"name":"Harvey Keitel","character":"Sport","img":null,"order":3},{"name":"Peter Boyle","character":"Wizard","img":null,"order":4},{"name":"Leonard Harris","character":"Charles Palantine","img":null,"order":5},{"name":"Albert Brooks","character":"Tom","img":null,"order":6},{"name":"Diahnne Abbott","character":"Concession Girl","img":null,"order":7},{"name":"Frank Adu","character":"Angry Black Man","img":null,"order":8},{"name":"Victor Argo","character":"Melio","img":null,"order":9},{"name":"Gino Ardito","character":"Policeman at Rally","img":null,"order":10},{"name":"Garth Avery","character":"Iris' Friend","img":null,"order":11},{"name":"Harry Cohn","character":"Cabbie in Bellmore","img":null,"order":12},{"name":"Cooper Cunningham","character":"Hooker in Cab","img":null,"order":13},{"name":"Brenda Dickson","character":"Soap Opera Woman","img":null,"order":14}],"movie:497828":[{"name":"Harris Dickinson","character":"Carl","img":null,"order":0},{"name":"Charlbi Dean","character":"Yaya","img":null,"order":1},{"name":"Dolly de Leon","character":"Abigail","img":null,"order":2},{"name":"Woody Harrelson","character":"The Captain","img":null,"order":3},{"name":"Zlatko Buri\u0107","character":"Dimitry","img":null,"order":4},{"name":"Vicki Berlin","character":"Paula","img":null,"order":5},{"name":"Henrik Dorsin","character":"Jarmo","img":null,"order":6},{"name":"Iris Berben","character":"Therese","img":null,"order":7},{"name":"Jean-Christophe Folly","character":"Nelson","img":null,"order":8},{"name":"Amanda Walker","character":"Clementine","img":null,"order":9},{"name":"Oliver Ford Davies","character":"Winston","img":null,"order":10},{"name":"Sunnyi Melles","character":"Vera","img":null,"order":11},{"name":"Thobias Thorwid","character":"Lewis","img":null,"order":12},{"name":"Jiannis Moustos","character":"Driver","img":null,"order":13},{"name":"Timoleon Gketsos","character":"Handsome Crewman","img":null,"order":14}],"movie:868":[{"name":"Presley Chweneyagae","character":"Tsotsi","img":null,"order":0},{"name":"Jerry Mofokeng","character":"Morris","img":null,"order":1},{"name":"Terry Pheto","character":"Miriam","img":null,"order":2},{"name":"Zenzo Ngqobe","character":"Butcher","img":null,"order":3},{"name":"Zola","character":"Fela","img":null,"order":4},{"name":"Rapulana Seiphemo","character":"John Dube","img":null,"order":5},{"name":"Nambitha Mpumlwana","character":"Pumla Dube","img":null,"order":6},{"name":"Percy Matsemela","character":"Sergeant Zuma","img":null,"order":7},{"name":"Thembi Nyandeni","character":"Soekie","img":null,"order":8},{"name":"Owen Sejake","character":"Gumboot Dlamini","img":null,"order":9},{"name":"Israel Makoe","character":"Tsotsi's father","img":null,"order":10},{"name":"Sindi Khambule","character":"Tsotsi's Mother","img":null,"order":11},{"name":"Benny Moshe","character":"Young Tsotsi","img":null,"order":12},{"name":"Mothusi Magano","character":"Boston","img":null,"order":13},{"name":"Kenneth Nkosi","character":"Aap","img":null,"order":14}],"movie:1517772":[{"name":"Lauryn Licari","character":"Self","img":null,"order":0},{"name":"Owen McKenny","character":"Self","img":null,"order":1},{"name":"Sophie Weber","character":"Self","img":null,"order":2},{"name":"Macy Johnston","character":"Self","img":null,"order":3},{"name":"Shawn Licari","character":"Self","img":null,"order":4},{"name":"Kendra Licari","character":"Self","img":null,"order":5},{"name":"Dave McKenny","character":"Self","img":null,"order":6},{"name":"Jill McKenny","character":"Self","img":null,"order":7},{"name":"Bill Chillman","character":"Self - The Superintendent","img":null,"order":8},{"name":"Dan Boyer","character":"Self - Principal","img":null,"order":9},{"name":"Khloe Wilson","character":"Self","img":null,"order":10},{"name":"Craig Wilson","character":"Self","img":null,"order":11},{"name":"Tami Wilson","character":"Self","img":null,"order":12},{"name":"Korin Weber","character":"Self","img":null,"order":13},{"name":"Bradley Peter","character":"Self - FBI Liason","img":null,"order":14}],"movie:977942":[{"name":"Andrew Garfield","character":"Ploughman","img":null,"order":0},{"name":"Jamie Bell","character":"John Ball","img":null,"order":1},{"name":"Stephen Dillane","character":"Archbishop Sudbury","img":null,"order":2},{"name":"Woody Norman","character":"King Richard II","img":null,"order":3},{"name":"Tom Hollander","character":"Treasurer Hales","img":null,"order":4},{"name":"Cosmo Jarvis","character":"Wat Tyler","img":null,"order":5},{"name":"Thomasin McKenzie","character":"Alyce","img":null,"order":6},{"name":"Jonny Lee Miller","character":"Mayor Walworth","img":null,"order":7},{"name":"Katherine Waterston","character":"Countess","img":null,"order":8},{"name":"Stanley Townsend","character":"Chief Justice Bealknap","img":null,"order":9},{"name":"Sky Yang","character":"Scribe","img":null,"order":10},{"name":"D\u00f3nal Finn","character":"Village Priest","img":null,"order":11},{"name":"Gerald Tyler","character":"Lord Beauchamp","img":null,"order":12},{"name":"Simon Kunz","character":"Sir John Newton","img":null,"order":13},{"name":"Mark Redhead","character":"Lord Peterborough","img":null,"order":14}],"movie:429197":[{"name":"Christian Bale","character":"Dick Cheney","img":null,"order":0},{"name":"Amy Adams","character":"Lynne Cheney","img":null,"order":1},{"name":"Steve Carell","character":"Donald Rumsfeld","img":null,"order":2},{"name":"Sam Rockwell","character":"George W. Bush","img":null,"order":3},{"name":"Alison Pill","character":"Mary Cheney","img":null,"order":4},{"name":"Eddie Marsan","character":"Paul Wolfowitz","img":null,"order":5},{"name":"Justin Kirk","character":"Scooter Libby","img":null,"order":6},{"name":"LisaGay Hamilton","character":"Condoleezza Rice","img":null,"order":7},{"name":"Jesse Plemons","character":"Kurt","img":null,"order":8},{"name":"Bill Camp","character":"Gerald Ford","img":null,"order":9},{"name":"Don McManus","character":"David Addington","img":null,"order":10},{"name":"Lily Rabe","character":"Liz Cheney","img":null,"order":11},{"name":"Shea Whigham","character":"Wayne Vincent","img":null,"order":12},{"name":"Stephen Adly Guirgis","character":"George Tenet","img":null,"order":13},{"name":"Tyler Perry","character":"Colin Powell","img":null,"order":14}],"movie:81":[{"name":"Sumi Shimamoto","character":"Nausica\u00e4 (voice)","img":null,"order":0},{"name":"Ichiro Nagai","character":"Mito (voice)","img":null,"order":1},{"name":"Gor\u014d Naya","character":"Yupa (voice)","img":null,"order":2},{"name":"Yoji Matsuda","character":"Asbel (voice)","img":null,"order":3},{"name":"Yoshiko Sakakibara","character":"Kushana (voice)","img":null,"order":4},{"name":"Iemasa Kayumi","character":"Kurotowa (voice)","img":null,"order":5},{"name":"Hisako Kyoda","character":"Obaba (voice)","img":null,"order":6},{"name":"Mahito Tsujimura","character":"Jihl (voice)","img":null,"order":7},{"name":"Mina Tominaga","character":"Lastel (voice)","img":null,"order":8},{"name":"Kohei Miyauchi","character":"Gol (voice)","img":null,"order":9},{"name":"Joji Yanami","character":"Gikkuri (voice)","img":null,"order":10},{"name":"Minoru Yada","character":"Niga (voice)","img":null,"order":11},{"name":"Rihoko Yoshida","character":"Teto / Girl C (voice)","img":null,"order":12},{"name":"Tetsuo Mizutori","character":"Commando (voice)","img":null,"order":13},{"name":"Masako Sugaya","character":"Girl A (voice)","img":null,"order":14}],"movie:1198984":[{"name":"Daisy Ridley","character":"Ava","img":null,"order":0},{"name":"Brenton Thwaites","character":"Clay","img":null,"order":1},{"name":"Mark Coles Smith","character":"Riley","img":null,"order":2},{"name":"Matt Whelan","character":"Mitch","img":null,"order":3},{"name":"Chloe Hurst","character":"Katie Harris","img":null,"order":4},{"name":"Kym Jackson","character":"Lt. Wilkie","img":null,"order":5},{"name":"Holly Hargreaves","character":"Mrs. Smith","img":null,"order":6},{"name":"Deanna Cooney","character":"Bianca","img":null,"order":7},{"name":"Elijah Williams","character":"Greg","img":null,"order":8},{"name":"Salme Geransar","character":"Private Clarkson","img":null,"order":9},{"name":"Luke Jai McIntosh","character":"Cadet","img":null,"order":10},{"name":"Joel Jackson","character":"Anxious Bus Volunteer","img":null,"order":11},{"name":"Dan Paris","character":"Captain Vance","img":null,"order":12},{"name":"Nicola Bartlett","character":"Woman on Plane","img":null,"order":13},{"name":"Kim Fleming","character":"Briefing Colonel","img":null,"order":14}],"movie:953371":[{"name":"Benjamin O'Keefe","character":"Self - Activist & Public Speaker","img":null,"order":0},{"name":"Bobby Blanski","character":"Self - Former A&F Model","img":null,"order":1},{"name":"Ryan Daharsh","character":"Self - Former A&F Model","img":null,"order":2},{"name":"Jennifer Sheahan","character":"Self - Former Store Employee","img":null,"order":3},{"name":"Dr. Anthony Ocampo","character":"Self - Former Store Employee","img":null,"order":4},{"name":"Sapna Maheshwari","character":"Self - Business Reporter, NY Times","img":null,"order":5},{"name":"Alan Karo","character":"Self - Fashion Marketing & Advertising Executive","img":null,"order":6},{"name":"Treva Lindsey","character":"Self - Professor of History, Ohio State University","img":null,"order":7},{"name":"Carla Barrientos","character":"Self - Former Store Employee","img":null,"order":8},{"name":"Robin Givhan","character":"Self - Senior Critic-at-Large, Washington Post","img":null,"order":9},{"name":"Jose Sanchez","character":"Self - Former A&F Recruiter","img":null,"order":10},{"name":"Moe Tkacik","character":"Self - Journalist","img":null,"order":11},{"name":"Mike Jeffries","character":"Self - Former A&F CEO (archive footage)","img":null,"order":12},{"name":"Charles Martin","character":"Self - Former A&F Design VP","img":null,"order":13},{"name":"Cindy Smith-Maglione","character":"Self - Former A&F VP of Merchandising","img":null,"order":14}],"movie:1184918":[{"name":"Lupita Nyong'o","character":"Roz / Rummage (voice)","img":null,"order":0},{"name":"Pedro Pascal","character":"Fink (voice)","img":null,"order":1},{"name":"Kit Connor","character":"Brightbill (voice)","img":null,"order":2},{"name":"Bill Nighy","character":"Longneck (voice)","img":null,"order":3},{"name":"Stephanie Hsu","character":"Vontra (voice)","img":null,"order":4},{"name":"Matt Berry","character":"Paddler (voice)","img":null,"order":5},{"name":"Ving Rhames","character":"Thunderbolt (voice)","img":null,"order":6},{"name":"Mark Hamill","character":"Thorn (voice)","img":null,"order":7},{"name":"Catherine O'Hara","character":"Pinktail (voice)","img":null,"order":8},{"name":"Boone Storm","character":"Baby Brightbill (voice)","img":null,"order":9},{"name":"Alexandra Novelle","character":"Snowdown (voice)","img":null,"order":10},{"name":"Raphael Alejandro","character":"Peck (voice)","img":null,"order":11},{"name":"Paul-Mik\u00e9l Williams","character":"Feather (voice)","img":null,"order":12},{"name":"Eddie Park","character":"Honkington (voice)","img":null,"order":13},{"name":"Dee Bradley Baker","character":"Raccoons / Squirrels / Badgers (voice)","img":null,"order":14}],"movie:149870":[{"name":"Hideaki Anno","character":"Jiro Horikoshi (voice)","img":null,"order":0},{"name":"Hidetoshi Nishijima","character":"Honj\u00f4 (voice)","img":null,"order":1},{"name":"Miori Takimoto","character":"Naoko Satomi (voice)","img":null,"order":2},{"name":"Masahiko Nishimura","character":"Kurokawa (voice)","img":null,"order":3},{"name":"Stephen Alpert","character":"Castorp (voice)","img":null,"order":4},{"name":"Mansai Nomura","character":"Giovanni Battista (voice)","img":null,"order":5},{"name":"Jun Kunimura","character":"Hattori (voice)","img":null,"order":6},{"name":"Mirai Shida","character":"Kayo Horikoshi (voice)","img":null,"order":7},{"name":"Shinobu Otake","character":"Mrs. Kurokawa (voice)","img":null,"order":8},{"name":"Morio Kazama","character":"Satomi (voice)","img":null,"order":9},{"name":"Keiko Takeshita","character":"Jir\u00f4's mother (voice)","img":null,"order":10},{"name":"Sascha","character":"German Security Guard / Flight Engineer (voice)","img":null,"order":11},{"name":"Kaichi Kaburagi","character":"Young Jiro Horikoshi (voice)","img":null,"order":12},{"name":"Maki Shinta","character":"Young Kayo Horikoshi (voice)","img":null,"order":13},{"name":"Berndt Otto","character":"(voice)","img":null,"order":14}],"movie:666243":[{"name":"Theo James","character":"Vesemir (voice)","img":null,"order":0},{"name":"Mary McDonnell","character":"Lady Zerbst (voice)","img":null,"order":1},{"name":"Lara Pulver","character":"Tetra Gilcrest (voice)","img":null,"order":2},{"name":"Graham McTavish","character":"Deglan (voice)","img":null,"order":3},{"name":"Tom Canton","character":"Filavandrel (voice)","img":null,"order":4},{"name":"David Errigo Jr.","character":"Young Vesemir / Young Remus (voice)","img":null,"order":5},{"name":"Jennifer Hale","character":"Illyana / Noblewoman (voice)","img":null,"order":6},{"name":"Kari Wahlgren","character":"Kitsu / Boy (voice)","img":null,"order":7},{"name":"Matthew Yang King","character":"Luka / Skogar (voice)","img":null,"order":8},{"name":"Darryl Kurylo","character":"Sven / Nobleman (voice)","img":null,"order":9},{"name":"Keith Ferguson","character":"Lord Carlisle / Reidrich (voice)","img":null,"order":10},{"name":"Jennie Kwan","character":"Young Luka (voice)","img":null,"order":11},{"name":"AJ LoCascio","character":"Young Sven (voice)","img":null,"order":12},{"name":"Michaela Dietz","character":"Tomas (voice)","img":null,"order":13},{"name":"Harry Hissrich","character":"Young Boy (Geralt) (voice)","img":null,"order":14}],"movie:1203329":[{"name":"Doug Cockle","character":"Geralt (voice)","img":null,"order":0},{"name":"Joey Batey","character":"Jaskier / Young Jaskier (voice)","img":null,"order":1},{"name":"Christina Wren","character":"Essi (voice)","img":null,"order":2},{"name":"Emily Carey","character":"Sh'eenaz (voice)","img":null,"order":3},{"name":"Camrus Johnson","character":"Agloval (voice)","img":null,"order":4},{"name":"Simon Templeman","character":"King Usveldt (voice)","img":null,"order":5},{"name":"Mallory Jansen","character":"Melusina / Princess Nispen (voice)","img":null,"order":6},{"name":"Anya Chalotra","character":"Yennefer (voice)","img":null,"order":7},{"name":"Ray Chase","character":"Zelest (voice)","img":null,"order":8},{"name":"Cynthia Kaye McWilliams","character":"Queen Dahut (voice)","img":null,"order":9},{"name":"Ramon Tikaram","character":"King Basim (voice)","img":null,"order":10},{"name":"Kari Wahlgren","character":"Zmarra / Vodnik Assassin (voice)","img":null,"order":11},{"name":"Stephen Fu","character":"Deroua (voice)","img":null,"order":12},{"name":"George Ackles","character":"Drouhard (voice)","img":null,"order":13},{"name":"Brian George","character":"Barkeep / Herald (voice)","img":null,"order":14}],"tv:260458":[{"name":"Malik Elassal","character":"Samir Rahman","img":null,"order":0},{"name":"Lucy Freyer","character":"Billie Schaeffer","img":null,"order":1},{"name":"Jack Innanen","character":"Paul Baker","img":null,"order":2},{"name":"Amita Rao","character":"Issa Damani","img":null,"order":3},{"name":"Owen Thiele","character":"Anton Evans","img":null,"order":4},{"name":"Julia Fox","character":"Julia Fox","img":null,"order":500},{"name":"Rachel Marsh","character":"Carly","img":null,"order":502},{"name":"Charlie Cox","character":"Mr. Teacher","img":null,"order":521},{"name":"Julian Manjerico","character":"Zack-Carlos","img":null,"order":576},{"name":"Martha Girvin","character":"Serena","img":null,"order":582},{"name":"Andrea Pavlovic","character":"Lily","img":null,"order":585},{"name":"Meghan Swaby","character":"Mary","img":null,"order":587},{"name":"Liam Cullagh","character":"OJ","img":null,"order":594},{"name":"Will Sennett","character":"Roach","img":null,"order":595},{"name":"Joey Dardano","character":"Schnee","img":null,"order":596}],"tv:64513":[{"name":"Sterling K. Brown","character":"Christopher Darden","img":null,"order":0},{"name":"Kenneth Choi","character":"Lance Ito","img":null,"order":3},{"name":"Beanie Feldstein","character":"Monica Lewinsky","img":null,"order":5},{"name":"Christian Clemenson","character":"Bill Hodgman","img":null,"order":7},{"name":"Sarah Paulson","character":"Linda Tripp","img":null,"order":9},{"name":"Cuba Gooding Jr.","character":"O. J. Simpson","img":null,"order":9},{"name":"Margo Martindale","character":"Lucianne Goldberg","img":null,"order":11},{"name":"Bruce Greenwood","character":"Gil Garcetti","img":null,"order":12},{"name":"Edie Falco","character":"Hillary Clinton","img":null,"order":13},{"name":"Nathan Lane","character":"F. Lee Bailey","img":null,"order":14},{"name":"Clive Owen","character":"Bill Clinton","img":null,"order":15},{"name":"David Schwimmer","character":"Robert Kardashian","img":null,"order":18},{"name":"John Travolta","character":"Robert Shapiro","img":null,"order":19},{"name":"Courtney B. Vance","character":"Johnnie Cochran","img":null,"order":20},{"name":"Annaleigh Ashford","character":"Elizabeth Cote","img":null,"order":398}],"tv:215866":[{"name":"Taylor Kitsch","character":"Isaac Reed","img":null,"order":0},{"name":"Betty Gilpin","character":"Sara Rowell","img":null,"order":1},{"name":"Dane DeHaan","character":"Jacob Pratt","img":null,"order":2},{"name":"Saura Lightfoot-Leon","character":"Abish Pratt","img":null,"order":3},{"name":"Derek Hinkey","character":"Red Feather","img":null,"order":4},{"name":"Joe Tippett","character":"James Wolsey","img":null,"order":5},{"name":"Jai Courtney","character":"Virgil Cutter","img":null,"order":6},{"name":"Preston Mota","character":"Devin Rowell","img":null,"order":7},{"name":"Shawnee Pourier","character":"Two Moons","img":null,"order":8},{"name":"Shea Whigham","character":"Jim Bridger","img":null,"order":9},{"name":"Kyle Davis","character":"Tilly","img":null,"order":500},{"name":"Tokala Black Elk","character":"Buffalo Run","img":null,"order":501},{"name":"Nick Hargrove","character":"Cottrell","img":null,"order":502},{"name":"Alex Fine","character":"Gant","img":null,"order":504},{"name":"Andrew P. Logan","character":"Lucas","img":null,"order":506}],"tv:4589":[{"name":"Jason Bateman","character":"Michael Bluth","img":null,"order":0},{"name":"Portia de Rossi","character":"Lindsay Bluth F\u00fcnke","img":null,"order":1},{"name":"Will Arnett","character":"Gob Bluth","img":null,"order":2},{"name":"Michael Cera","character":"George Michael Bluth","img":null,"order":3},{"name":"Alia Shawkat","character":"Maeby F\u00fcnke","img":null,"order":4},{"name":"Tony Hale","character":"Byron 'Buster' Bluth","img":null,"order":5},{"name":"David Cross","character":"Tobias F\u00fcnke","img":null,"order":6},{"name":"Jeffrey Tambor","character":"George Bluth Sr.","img":null,"order":7},{"name":"Jessica Walter","character":"Lucille Bluth","img":null,"order":8},{"name":"Ron Howard","character":"Narrator","img":null,"order":9},{"name":"Justin Grant Wade","character":"Steve Holt","img":null,"order":508},{"name":"Liza Minnelli","character":"Lucille Austero","img":null,"order":520},{"name":"Mae Whitman","character":"Ann Veal","img":null,"order":533},{"name":"John Beard","character":"John Beard","img":null,"order":609},{"name":"Henry Winkler","character":"Barry Zuckerkorn","img":null,"order":635}],"tv:246":[{"name":"Zach Tyler Eisen","character":"Aang (voice)","img":null,"order":0},{"name":"Mae Whitman","character":"Katara (voice)","img":null,"order":1},{"name":"Jack De Sena","character":"Sokka (voice)","img":null,"order":2},{"name":"Dante Basco","character":"Zuko (voice)","img":null,"order":3},{"name":"Mako","character":"Iroh (voice)","img":null,"order":4},{"name":"Dee Bradley Baker","character":"Appa / Momo (voice)","img":null,"order":7},{"name":"Cricket Leigh","character":"Mai (voice)","img":null,"order":9},{"name":"Olivia Hack","character":"Ty Lee (voice)","img":null,"order":10},{"name":"Michaela Jill Murphy","character":"Toph Beifong (voice)","img":null,"order":173},{"name":"Andr\u00e9 Sogliuzzo","character":"Captain (voice)","img":null,"order":378},{"name":"Grey DeLisle","character":"Azula / Additional Voices (voice)","img":null,"order":491},{"name":"Greg Baldwin","character":"Iroh / Combustion Man (voice)","img":null,"order":545},{"name":"Mark Hamill","character":"Ozai (voice)","img":null,"order":581},{"name":"Jennie Kwan","character":"Suki (voice)","img":null,"order":624},{"name":"Jim Meskimen","character":"Avatar Kuruk (voice)","img":null,"order":657}],"tv:124428":[{"name":"Jeroen Kijk in de Vegte","character":"Voice-over","img":null,"order":0},{"name":"Martijn Bolhoeve","character":"Self - Owner of a B&B in Hua Hin, Thailand","img":null,"order":2},{"name":"Joy van Swieten","character":"Self - Owner of a B&B in Malaga, Spain","img":null,"order":3},{"name":"Marian Trott","character":"Self - Owner of a B&B in Budens, Portugal","img":null,"order":4},{"name":"Bram Eijgenhuijsen","character":"Self - Owner of a B&B in Norrhult, Sweden","img":null,"order":5},{"name":"Debbie de Jong","character":"Self - Owner of a B&B in Sant Andreu del Terri, Spain","img":null,"order":6},{"name":"Leendert Wijland","character":"Self - Owner of a B&B in La Roche-En-Ardenne, Belgium","img":null,"order":7},{"name":"Petri Damen","character":"Self - Owner of a B&B in Monclar, France","img":null,"order":8},{"name":"Walter Spangenberg","character":"Self - Owner of a B&B in Troche, France","img":null,"order":9},{"name":"Iris Villas","character":"Self - Owner of a B&B in Sparto, Greece","img":null,"order":13},{"name":"Robert Jan van Rheenen","character":"Self - Owner of a B&B in Dornoch, Scotland","img":null,"order":14},{"name":"Arno van Wilpe","character":"Self - Owner of a B&B in Payzac, France","img":null,"order":15},{"name":"Mike Verkoelen","character":"Self - Owner of a B&B in Ma\u00e7anet de la Selva, Spain","img":null,"order":16},{"name":"Paul Visser","character":"Self - Partner of Debbie de Jong","img":null,"order":48},{"name":"Dani Zijlstra","character":"Self - Partner of Joy van Swieten","img":null,"order":49}],"tv:136315":[{"name":"Jeremy Allen White","character":"Carmen 'Carmy' Berzatto","img":null,"order":0},{"name":"Ebon Moss-Bachrach","character":"Richard 'Richie' Jerimovich","img":null,"order":1},{"name":"Ayo Edebiri","character":"Sydney Adamu","img":null,"order":2},{"name":"Lionel Boyce","character":"Marcus Brooks","img":null,"order":3},{"name":"Abby Elliott","character":"Natalie 'Sugar' Berzatto","img":null,"order":4},{"name":"Matty Matheson","character":"Neil Fak","img":null,"order":5},{"name":"Liza Col\u00f3n-Zayas","character":"Bettina 'Tina' Marrero","img":null,"order":6},{"name":"Edwin Lee Gibson","character":"Ebraheim","img":null,"order":8},{"name":"Oliver Platt","character":"Uncle Jimmy 'Cicero' Kalinowski","img":null,"order":500},{"name":"Christopher Zucchero","character":"Chi-Chi","img":null,"order":505},{"name":"Chris Witaske","character":"Pete Katinsky","img":null,"order":513},{"name":"Corey Hendrix","character":"Gary 'Sweeps' Woods","img":null,"order":536},{"name":"Jose M. Cervantes","character":"Angel","img":null,"order":537},{"name":"Richard Esteras","character":"Manny","img":null,"order":538},{"name":"Ricky Staffieri","character":"Theodore Fak","img":null,"order":548}],"tv:74313":[{"name":"David Attenborough","character":"Self - Presenter","img":null,"order":0}],"tv:93290":[{"name":"Martin Freeman","character":"Paul Worsley","img":null,"order":0},{"name":"Daisy Haggard","character":"Ally Grant","img":null,"order":1},{"name":"Eve Prenelle","character":"Ava Worsley","img":null,"order":4},{"name":"Alex Eastwood","character":"Luke Worsley","img":null,"order":5},{"name":"Oscar Kennedy","character":"Luke Worsley","img":null,"order":6},{"name":"Zo\u00eb Athena","character":"Ava Worsley","img":null,"order":7},{"name":"George Wakeman","character":"Luke Worsley","img":null,"order":345},{"name":"Jayda Eyles","character":"Young Ava","img":null,"order":346},{"name":"Tim Steed","character":"Carl","img":null,"order":501},{"name":"Patrick Baladi","character":"Darren","img":null,"order":504},{"name":"Alun Armstrong","character":"Jim","img":null,"order":514},{"name":"Joanna Bacon","character":"Jackie","img":null,"order":515},{"name":"Stella Gonet","character":"Leah","img":null,"order":516},{"name":"Hugh Quarshie","character":"Alex","img":null,"order":519},{"name":"Aliyah Sesay","character":"Grace","img":null,"order":520}],"tv:87108":[{"name":"Jared Harris","character":"Valery Legasov","img":null,"order":0},{"name":"Stellan Skarsg\u00e5rd","character":"Boris Shcherbina","img":"mW7xmtGV4y79kQGn0zkKVGDMAmw.jpg","order":1},{"name":"Emily Watson","character":"Ulana Khomyuk","img":null,"order":2},{"name":"Paul Ritter","character":"Anatoly Dyatlov","img":null,"order":3},{"name":"Jessie Buckley","character":"Lyudmilla Ignatenko","img":null,"order":4},{"name":"Adam Nagaitis","character":"Vasily Ignatenko","img":null,"order":5},{"name":"Sam Troughton","character":"Alexandr Akimov","img":null,"order":6},{"name":"Robert Emms","character":"Leonid Toptunov","img":null,"order":7},{"name":"Con O'Neill","character":"Viktor Bryukhanov","img":null,"order":8},{"name":"Adrian Rawlins","character":"Nikolai Fomin","img":null,"order":9},{"name":"Alan Williams","character":"KGB Chairman Charkov","img":null,"order":10},{"name":"David Dencik","character":"Mikhail Gorbachev","img":null,"order":11},{"name":"Mark Lewis Jones","character":"General Pikalov","img":null,"order":12},{"name":"Ralph Ineson","character":"General Tarakanov","img":null,"order":13},{"name":"Barry Keoghan","character":"Pavel","img":null,"order":14}],"tv:18347":[{"name":"Joel McHale","character":"Jeff Winger","img":null,"order":0},{"name":"Gillian Jacobs","character":"Britta Perry","img":null,"order":1},{"name":"Alison Brie","character":"Annie Edison","img":null,"order":2},{"name":"Donald Glover","character":"Troy Barnes","img":null,"order":3},{"name":"Yvette Nicole Brown","character":"Shirley Bennett","img":null,"order":4},{"name":"Jim Rash","character":"Dean Craig Pelton","img":null,"order":5},{"name":"Danny Pudi","character":"Abed Nadir","img":null,"order":6},{"name":"Chevy Chase","character":"Pierce Hawthorne","img":null,"order":7},{"name":"Ken Jeong","character":"Ben Chang","img":null,"order":10},{"name":"John Oliver","character":"Professor Ian Duncan","img":null,"order":154},{"name":"Charley Koontz","character":"Neil","img":null,"order":1003},{"name":"Danielle Kaplowitz","character":"Vicki","img":null,"order":1034},{"name":"Erik Charles Nielsen","character":"Garrett Lambert","img":null,"order":1035},{"name":"Dino Stamatopoulos","character":"Star-Burns","img":null,"order":1046},{"name":"Richard Erdman","character":"Leonard","img":null,"order":1049}],"tv:289517":[{"name":"Lee Jae-wook","character":"Byeon Hyeok-jun","img":null,"order":0},{"name":"Go Min-si","character":"Eum Yeon-joo","img":null,"order":1},{"name":"Kim Min-ha","character":"Byeon Ji-yoon","img":null,"order":2},{"name":"Lee Hee-jun","character":"Head of Spider Staffing Agency","img":null,"order":3},{"name":"Choi Hyun-wook","character":"Choi Hee-dong","img":null,"order":500},{"name":"Yoon Kyung-ho","character":"Jo Jun-seop","img":null,"order":501},{"name":"Cho Hyun-chul","character":"Cinephile","img":null,"order":502},{"name":"Yoon Byung-hee","character":"Theater Manager","img":null,"order":503},{"name":"Seo Jae-hee","character":"Director of Yangcheon Bio Clinic","img":null,"order":504},{"name":"Ko Chang-seok","character":"Foreman","img":null,"order":505},{"name":"Kim Si-eun","character":"Woman on the bridge","img":null,"order":506}],"tv:110695":[{"name":"Michael Keaton","character":"Samuel Finnix","img":null,"order":0},{"name":"Peter Sarsgaard","character":"Rick Mountcastle","img":null,"order":1},{"name":"Michael Stuhlbarg","character":"Richard Sackler","img":null,"order":2},{"name":"Will Poulter","character":"Billy Cutler","img":null,"order":3},{"name":"John Hoogenakker","character":"Randy Ramseyer","img":null,"order":4},{"name":"Kaitlyn Dever","character":"Betsy Mallum","img":null,"order":5},{"name":"Rosario Dawson","character":"Bridget Meyer","img":null,"order":6},{"name":"Will Chase","character":"Michael Friedman","img":null,"order":7},{"name":"Cleopatra Coleman","character":"Grace Pell","img":null,"order":8},{"name":"Parker Sack","character":"Dirk","img":null,"order":9},{"name":"Mare Winningham","character":"Diane Mallum","img":null,"order":504},{"name":"Ian Unterman","character":"Jonathan Sackler","img":null,"order":505},{"name":"Jake McDorman","character":"John Brownlee","img":null,"order":506},{"name":"Phillipa Soo","character":"Amber Collins","img":null,"order":507},{"name":"Brendan Patrick Connor","character":"Howard Udell","img":null,"order":508}],"tv:90228":[{"name":"Emily Watson","character":"Mother Superior Valya Harkonnen","img":null,"order":0},{"name":"Olivia Williams","character":"Reverend Mother Tula Harkonnen","img":null,"order":1},{"name":"Travis Fimmel","character":"Desmond Hart","img":null,"order":2},{"name":"Jodhi May","character":"Empress Natalya Arat Corrino","img":null,"order":3},{"name":"Sarah-Sofie Boussnina","character":"Princess Ynez Corrino","img":null,"order":4},{"name":"Chloe Lea","character":"Sister Lila","img":null,"order":5},{"name":"Chris Mason","character":"Keiran Atreides","img":null,"order":6},{"name":"Shalom Brune-Franklin","character":"Mikaela","img":null,"order":7},{"name":"Jade Anouka","character":"Sister Theodosia","img":null,"order":9},{"name":"Edward Davis","character":"Harrow Harkonnen","img":null,"order":10},{"name":"Josh Heuston","character":"Constantine Corrino","img":null,"order":11},{"name":"Faoileann Cunningham","character":"Sister Jen","img":null,"order":12},{"name":"Aoife Hinds","character":"Sister Emeline","img":null,"order":13},{"name":"Indira Varma","character":"","img":null,"order":14},{"name":"Ashley Walters","character":"","img":null,"order":15}],"tv:258165":[{"name":"Florence Pugh","character":"Cathy Ames","img":null,"order":0},{"name":"Christopher Abbott","character":"Adam Trask","img":null,"order":1},{"name":"Mike Faist","character":"Charles Trask","img":null,"order":2},{"name":"Joseph Zada","character":"Caleb Trask","img":null,"order":253},{"name":"Robert Morgan","character":"Sheriff Quinn","img":null,"order":500},{"name":"Christopher Sommers","character":"Mr. Bacon","img":null,"order":501},{"name":"Brad McMurray","character":"Joe Valery","img":null,"order":502},{"name":"Vaughan Reilly","character":"Adolescent Cathy","img":null,"order":503},{"name":"Hoon Lee","character":"Lee","img":null,"order":505},{"name":"Ciar\u00e1n Hinds","character":"Samuel Hamilton","img":null,"order":506},{"name":"Tandi Wright","character":"Mrs. Garb","img":null,"order":507},{"name":"Anita Hegh","character":"Liza Hamilton","img":null,"order":508},{"name":"Oscar Redding","character":"Rabbit Holman","img":null,"order":509},{"name":"Amelia Reynolds","character":"Ethel","img":null,"order":510},{"name":"Jonah Wren Phillips","character":"Young Aron Trask","img":null,"order":512}],"tv:106379":[{"name":"Ella Purnell","character":"Lucy MacLean","img":null,"order":0},{"name":"Aaron Moten","character":"Maximus","img":null,"order":1},{"name":"Mois\u00e9s Arias","character":"Norm MacLean","img":null,"order":2},{"name":"Frances Turner","character":"Barb Howard","img":null,"order":3},{"name":"Kyle MacLachlan","character":"Overseer Hank MacLean","img":null,"order":4},{"name":"Walton Goggins","character":"The Ghoul / Cooper Howard","img":null,"order":5},{"name":"Leslie Uggams","character":"Betty Pearson","img":null,"order":501},{"name":"Michael Cristofer","character":"Elder Cleric Quintus","img":null,"order":502},{"name":"Johnny Pemberton","character":"Thaddeus","img":null,"order":503},{"name":"Zach Cherry","character":"Woody Thomas","img":null,"order":506},{"name":"Annabel O'Hagan","character":"Stephanie Harper","img":null,"order":507},{"name":"Dave Register","character":"Chet","img":null,"order":508},{"name":"Rodrigo Luzzi","character":"Reg McPhee","img":null,"order":509},{"name":"Leer Leary","character":"Davey","img":null,"order":515},{"name":"Amir Carr","character":"Young Maximus","img":null,"order":527}],"tv:2207":[{"name":"John Cleese","character":"Basil Fawlty","img":null,"order":0},{"name":"Prunella Scales","character":"Sybil Fawlty","img":null,"order":1},{"name":"Connie Booth","character":"Polly Sherman","img":null,"order":2},{"name":"Andrew Sachs","character":"Manuel","img":null,"order":3},{"name":"Ballard Berkeley","character":"Major Gowen","img":null,"order":4},{"name":"Brian Hall","character":"Terry the Chef","img":null,"order":5},{"name":"Gilly Flower","character":"Miss Tibbs","img":null,"order":6},{"name":"Renee Roberts","character":"Miss Gatsby","img":null,"order":7},{"name":"Michael Gwynn","character":"Lord Melbury","img":null,"order":500},{"name":"Diana King","character":"Mrs. Rachel Lloyd","img":null,"order":501},{"name":"David Kelly","character":"O'Reilly","img":null,"order":502},{"name":"Brenda Cowling","character":"Sister","img":null,"order":503},{"name":"Elizabeth Benson","character":"Mrs. Heath","img":null,"order":540},{"name":"Terence Conoley","character":"Mr. Johnston","img":null,"order":548},{"name":"George Lee","character":"Delivery Man","img":null,"order":565}],"tv:290720":[{"name":"Jose Coronado","character":"Basil","img":null,"order":0},{"name":"Mar\u00eda Valverde","character":"Adela Figueora","img":null,"order":1},{"name":"Marti\u00f1o Rivas","character":"Fox\u00e1","img":null,"order":2},{"name":"Maribel Verd\u00fa","character":"Raquel Auslander","img":null,"order":3},{"name":"Gonzalo de Castro","character":"Fonseca","img":null,"order":4},{"name":"Cristina Kovani","character":"Vicky","img":null,"order":5},{"name":"Jos\u00e9 Condessa","character":"Toni","img":null,"order":6},{"name":"Pep\u00f3n Nieto","character":"Seruya","img":null,"order":7},{"name":"Daniel Holgu\u00edn","character":"Gerard","img":null,"order":8},{"name":"Michael Stobbe","character":"Se\u00f1or Klemmer","img":null,"order":9},{"name":"Yaiza Guimar\u00e9","character":"Se\u00f1ora Klemmer","img":null,"order":10},{"name":"Almudena Salort","character":"Catalina","img":null,"order":11},{"name":"Paloma Bloyd","character":"Elisa","img":null,"order":12}],"tv:243316":[{"name":"Tina Fey","character":"Kate","img":null,"order":0},{"name":"Steve Carell","character":"Nick Pagano","img":null,"order":1},{"name":"Colman Domingo","character":"Danny","img":null,"order":2},{"name":"Erika Henningsen","character":"Ginny","img":null,"order":3},{"name":"Kerri Kenney","character":"Anne Pagano","img":null,"order":4},{"name":"Will Forte","character":"Jack","img":null,"order":5},{"name":"Marco Calvani","character":"Claude","img":null,"order":6},{"name":"Julia Lester","character":"Lila","img":null,"order":502},{"name":"Alan Alda","character":"Don","img":null,"order":503},{"name":"Ashlyn Maddox","character":"Beth","img":null,"order":509},{"name":"Eric Elizaga","character":"Desk Clerk","img":null,"order":513},{"name":"Toby Huss","character":"Terry","img":null,"order":519},{"name":"Blake Russell","character":"State Trooper","img":null,"order":528},{"name":"Steven Pasquale","character":"Mark Brett","img":null,"order":531},{"name":"Brielle Pribbernow","character":"Boardwalk Kid","img":null,"order":532}],"tv:65345":[{"name":"Justice Smith","character":"Ezekiel Figuero","img":null,"order":0},{"name":"Shameik Moore","character":"Shaolin Fantastic","img":null,"order":1},{"name":"Herizen F. Guardiola","character":"Mylene Cruz","img":null,"order":2},{"name":"Skylan Brooks","character":"Ra-Ra Kipling","img":null,"order":3},{"name":"Jaden Smith","character":"Marcus 'Dizzee' Kipling","img":null,"order":4},{"name":"Tremaine Brown Jr.","character":"Boo-Boo Kipling","img":null,"order":5},{"name":"Yahya Abdul-Mateen II","character":"Clarence 'Cadillac' Caldwell","img":null,"order":6},{"name":"Jimmy Smits","character":"Francisco 'Papa Fuerte' Cruz","img":null,"order":7},{"name":"Stefan\u00e9e Martin","character":"Yolanda Kipling","img":null,"order":8},{"name":"Shyrley Rodriguez","character":"Regina Diaz","img":null,"order":9},{"name":"Mamoudou Athie","character":"Grandmaster Flash","img":null,"order":10},{"name":"Giancarlo Esposito","character":"Pastor Ramon Cruz","img":null,"order":11},{"name":"Ron Cephas Jones","character":"Winston Kipling","img":null,"order":505},{"name":"RayJonaldy Rodriguez","character":"Silent Carlito","img":null,"order":506},{"name":"Zuri Reed","character":"Zulu Girl Yvonne","img":null,"order":508}],"tv:204304":[{"name":"Michael Pollan","character":"Self","img":null,"order":0},{"name":"Ann Shulgin","character":"Self - Author, Mentor & Guide Therapist","img":null,"order":500},{"name":"Alexander Shulgin","character":"Self - Chemist, Author & Professor (archive footage)","img":null,"order":501},{"name":"Rick Doblin","character":"Self - Founder, MAPS","img":null,"order":502},{"name":"Paul F. Daley","character":"Self","img":null,"order":503}],"tv:96488":[{"name":"Peter Sarsgaard","character":"David Russell","img":null,"order":0},{"name":"Kyle Gallner","character":"Eric Fisher","img":null,"order":1},{"name":"David Strathairn","character":"Henry Fisher","img":null,"order":2},{"name":"Kodi Smit-McPhee","character":"Chris Keller","img":null,"order":3},{"name":"Jersey Johnston","character":"Debbie Russell","img":null,"order":533},{"name":"Frank Whaley","character":"Detective James Connor","img":null,"order":577},{"name":"Ellen Humphreys","character":"Sharon Russell","img":null,"order":578},{"name":"Melinda McGraw","character":"Faith Turner","img":null,"order":579},{"name":"Chad L. Coleman","character":"Mr. Franklin","img":null,"order":604},{"name":"Joanna Going","character":"Mrs. Fisher","img":null,"order":621},{"name":"Ebon Moss-Bachrach","character":"Trey Carano","img":null,"order":622},{"name":"Autry Haydon-Wilson","character":"Young Amy Harlow","img":null,"order":623},{"name":"Vincent D'Onofrio","character":"Sgt. Ian Lynch","img":null,"order":624},{"name":"Andre Royo","character":"Charlie Shannon","img":null,"order":625},{"name":"Barbie Robertson","character":"Debbie Russell","img":null,"order":636}],"tv:2710":[{"name":"Charlie Day","character":"Charlie Kelly","img":null,"order":0},{"name":"Glenn Howerton","character":"Dennis Reynolds","img":null,"order":1},{"name":"Rob Mac","character":"Ronald 'Mac' McDonald","img":null,"order":2},{"name":"Kaitlin Olson","character":"Dee Reynolds","img":null,"order":3},{"name":"Danny DeVito","character":"Frank Reynolds","img":null,"order":4},{"name":"Artemis Pebdani","character":"Artemis","img":null,"order":6},{"name":"Mary Elizabeth Ellis","character":"Waitress","img":null,"order":7},{"name":"David Hornsby","character":"Matthew 'Rickety Cricket' Mara","img":null,"order":8},{"name":"Lynne Marie Stewart","character":"Charlie's Mom","img":null,"order":216},{"name":"Sandy Martin","character":"Mac's Mom","img":null,"order":847},{"name":"Jimmi Simpson","character":"Liam McPoyle","img":null,"order":1009},{"name":"Nate Mooney","character":"Ryan McPoyle","img":null,"order":1011},{"name":"Andrew Friedman","character":"Uncle Jack","img":null,"order":1140},{"name":"Lance Barber","character":"Bill Ponderosa","img":null,"order":1201},{"name":"Gregory Scott Cummins","character":"Luther","img":null,"order":1230}],"tv:224372":[{"name":"Peter Claffey","character":"Ser Duncan 'Dunk' the Tall","img":null,"order":0},{"name":"Dexter Sol Ansell","character":"Egg","img":null,"order":1},{"name":"Ross Anderson","character":"Ser Humfrey Hardyng","img":null,"order":500},{"name":"Daniel Monks","character":"Ser Manfred Dondarrion","img":null,"order":504},{"name":"Tom Vaughan-Lawlor","character":"Plummer","img":null,"order":505},{"name":"Sam Spruell","character":"Prince Maekar Targaryen","img":null,"order":510},{"name":"Finn Bennett","character":"Prince Aerion 'Brightflame' Targaryen","img":null,"order":511},{"name":"Bertie Carvel","character":"Prince Baelor 'Breakspear' Targaryen","img":null,"order":512},{"name":"Danny Webb","character":"Ser Arlan of Pennytree","img":null,"order":513},{"name":"Tanzyn Crawford","character":"Tanselle","img":null,"order":514},{"name":"Henry Ashton","character":"Prince Daeron 'the Drunken' Targaryen","img":null,"order":517},{"name":"Edward Ashley","character":"Ser Steffon Fossoway","img":null,"order":518},{"name":"Cara Harris","character":"Lady Gwin","img":null,"order":527},{"name":"Shaun Thomas","character":"Ser Raymun 'The Reluctant' Fossoway","img":null,"order":532},{"name":"Daniel Ings","character":"Ser Lyonel 'The Laughing Storm' Baratheon","img":null,"order":543}],"tv:157741":[{"name":"Billy Bob Thornton","character":"Tommy Norris","img":null,"order":0},{"name":"Demi Moore","character":"Cami Miller","img":null,"order":1},{"name":"Andy Garcia","character":"Gallino","img":null,"order":2},{"name":"Ali Larter","character":"Angela Norris","img":null,"order":3},{"name":"Jacob Lofland","character":"Cooper Norris","img":null,"order":4},{"name":"Michelle Randolph","character":"Ainsley Norris","img":null,"order":5},{"name":"Paulina Ch\u00e1vez","character":"Ariana Medina","img":null,"order":6},{"name":"Kayla Wallace","character":"Rebecca Falcone","img":null,"order":7},{"name":"Mark Collie","character":"Sheriff Walt Joeberg","img":null,"order":8},{"name":"James Jordan","character":"Dale Bradley","img":null,"order":9},{"name":"Jon Hamm","character":"Monty Miller","img":null,"order":10},{"name":"Sam Elliott","character":"Thomas 'T.L.' Norris","img":null,"order":11},{"name":"Colm Feore","character":"Nathan","img":null,"order":501},{"name":"Mustafa Speaks","character":"Boss","img":null,"order":531},{"name":"Caleb Martin","character":"Ben 'BR' Reynolds","img":null,"order":611}],"tv:100088":[{"name":"Bella Ramsey","character":"Ellie Williams","img":null,"order":1},{"name":"Gabriel Luna","character":"Tommy Miller","img":null,"order":2},{"name":"Isabela Merced","character":"Dina","img":null,"order":3},{"name":"Young Mazino","character":"Jesse","img":null,"order":4},{"name":"Pedro Pascal","character":"Joel Miller","img":null,"order":164},{"name":"Anna Torv","character":"Tess","img":null,"order":523},{"name":"Lamar Johnson","character":"Henry Burrell","img":null,"order":565},{"name":"Rutina Wesley","character":"Maria","img":null,"order":567},{"name":"Samuel Hoeksema","character":"Museum Clicker","img":null,"order":571},{"name":"Kaitlyn Dever","character":"Abby Anderson","img":null,"order":576},{"name":"Danny Ramirez","character":"Manny Alvarez","img":null,"order":577},{"name":"Tati Gabrielle","character":"Nora","img":null,"order":578},{"name":"Spencer Lord","character":"Owen","img":null,"order":579},{"name":"Robert John Burke","character":"Seth","img":null,"order":580},{"name":"Ariela Barer","character":"Mel","img":null,"order":581}],"tv:252193":[{"name":"Junichi Okada","character":"Shujiro Saga","img":null,"order":0},{"name":"Yumia Fujisaki","character":"Futaba Katsuki","img":null,"order":1},{"name":"Kaya Kiyohara","character":"Iroha Kinugasa","img":null,"order":2},{"name":"Masahiro Higashide","character":"Kyojin Tsuge","img":null,"order":3},{"name":"Taichi Saotome","character":"Shikura Adashino","img":null,"order":4},{"name":"Yuya Endo","character":"Sansuke Gion","img":null,"order":5},{"name":"Hideaki Ito","character":"Bukotsu Kanjiya","img":null,"order":6},{"name":"Hiroshi Abe","character":"Okabe Gentosai","img":null,"order":7},{"name":"Gaku Hamada","character":"Kawaji Toshiyoshi","img":null,"order":501},{"name":"Arata Iura","character":"Okubo Toshimichi","img":null,"order":502},{"name":"Yuya Matsuura","character":"Kouemon Tachikawa","img":null,"order":504},{"name":"Nobi Nakanishi","character":"Narrator","img":null,"order":505},{"name":"Tetsushi Tanaka","character":"Hisoka Maejima","img":null,"order":506},{"name":"Kairi Jo","character":"Shinjiro Sayama","img":null,"order":514},{"name":"Taiiku Okazaki","character":"Keage Jinroku","img":null,"order":519}],"tv:270572":[{"name":"Winston Sawyers","character":"Ralph","img":null,"order":0},{"name":"David McKenna","character":"Nicholas \"Piggy\"","img":null,"order":1},{"name":"Lox Pratt","character":"Jack Merridew","img":null,"order":2},{"name":"Ike Talbut","character":"Simon Camborne","img":null,"order":3},{"name":"Thomas Connor","character":"Roger","img":null,"order":4},{"name":"Cornelius Brandreth","character":"Maurice","img":null,"order":5},{"name":"Cassius Flemyng","character":"Eric","img":null,"order":6},{"name":"Noah Flemyng","character":"Sam","img":null,"order":7},{"name":"Harrison Metcalf","character":"Frankie","img":null,"order":8},{"name":"Rafael de Belligny","character":"Robert","img":null,"order":9},{"name":"Felix Tandon","character":"William","img":null,"order":10},{"name":"Beau Thompson","character":"Philip","img":null,"order":11},{"name":"Kai Wilson","character":"Jasper","img":null,"order":12},{"name":"Freddie Lee-Grey","character":"Percival","img":null,"order":13},{"name":"Tom Page-Turner","character":"Bill","img":null,"order":14}],"tv:84773":[{"name":"Morfydd Clark","character":"Galadriel","img":null,"order":1},{"name":"Charlie Vickers","character":"Halbrand","img":null,"order":1},{"name":"Robert Aramayo","character":"Elrond","img":null,"order":3},{"name":"Charles Edwards","character":"Lord Celebrimbor","img":null,"order":4},{"name":"Owain Arthur","character":"Durin IV","img":null,"order":5},{"name":"Sophia Nomvete","character":"Disa","img":null,"order":6},{"name":"Daniel Weyman","character":"The Stranger","img":null,"order":7},{"name":"Markella Kavenagh","character":"Elanor 'Nori' Brandyfoot","img":null,"order":8},{"name":"Megan Richards","character":"Poppy Proudfellow","img":null,"order":9},{"name":"Ismael Cruz Cordova","character":"Arondir","img":null,"order":10},{"name":"Lloyd Owen","character":"Elendil","img":null,"order":11},{"name":"Benjamin Walker","character":"High King Gil-Galad","img":null,"order":16},{"name":"Cynthia Addai-Robinson","character":"M\u00edriel","img":null,"order":17},{"name":"Trystan Gravelle","character":"Pharaz\u00f4n","img":null,"order":18},{"name":"Ema Horvath","character":"E\u00e4rien","img":null,"order":19}],"tv:73411":[{"name":"Emma Stone","character":"Annie Landsberg","img":null,"order":0},{"name":"Jonah Hill","character":"Owen Milgrim","img":null,"order":1},{"name":"Sonoya Mizuno","character":"Dr. Azumi Fujita","img":null,"order":2},{"name":"Justin Theroux","character":"Dr. James K. Mantleray","img":null,"order":8},{"name":"Sally Field","character":"Dr. Greta Mantleray","img":null,"order":9},{"name":"Aaralyn Anderson","character":"Australia","img":null,"order":347},{"name":"James Monroe Iglehart","character":"Carl","img":null,"order":539},{"name":"Dai Ishiguro","character":"Head Control Tech","img":null,"order":540},{"name":"Gabriel Byrne","character":"Porter Milgrim","img":null,"order":546},{"name":"Kathleen Choe","character":"3","img":null,"order":547},{"name":"Allyce Beasley","character":"11","img":null,"order":550},{"name":"Stephen Hill","character":"7","img":null,"order":553},{"name":"Danny Hoch","character":"5","img":null,"order":556},{"name":"Billy Magnussen","character":"Jed Milgrim","img":null,"order":559},{"name":"Sejal Shah","character":"First Medical Tech","img":null,"order":562}],"tv:212333":[{"name":"Luca Marinelli","character":"Benito Mussolini","img":null,"order":0},{"name":"Francesco Russo","character":"Cesare Rossi","img":null,"order":1},{"name":"Barbara Chichiarelli","character":"Margherita Sarfatti","img":null,"order":2},{"name":"Benedetta Cimatti","character":"Rachele Mussolini","img":null,"order":3},{"name":"Gaetano Bruno","character":"Giacomo Matteotti","img":null,"order":4},{"name":"Maurizio Lombardi","character":"Emilio De Bono","img":null,"order":5},{"name":"Gianmarco Vettori","character":"Dino Grandi","img":null,"order":6},{"name":"Massimo De Lorenzo","character":"Alfredo Rocco","img":null,"order":7},{"name":"Fulvio Falzarano","character":"Giovanni Giolitti","img":null,"order":8},{"name":"Amedeo Gull\u00e0","character":"Augusto Malacria","img":null,"order":9},{"name":"Federico Majorana","character":"Amerigo Dumini","img":null,"order":500},{"name":"Lorenzo Zurzolo","character":"Italo Balbo","img":null,"order":501},{"name":"Vincenzo Nemolato","character":"King Vittorio Emanuele III","img":null,"order":502},{"name":"Giovanni Alfieri","character":"Amleto Poverno","img":null,"order":503},{"name":"Gabriele Falsetta","character":"Roberto Farinacci","img":null,"order":504}],"tv:61859":[{"name":"Tom Hiddleston","character":"Jonathan Pine","img":null,"order":0},{"name":"Hugh Laurie","character":"Richard Roper","img":null,"order":1},{"name":"Diego Calva","character":"Teddy Dos Santos","img":null,"order":2},{"name":"Camila Morrone","character":"Roxana Bola\u00f1os","img":null,"order":3},{"name":"Douglas Hodge","character":"Rex Mayhew","img":null,"order":5},{"name":"Elizabeth Debicki","character":"Jed Marshall","img":null,"order":6},{"name":"Paul Chahidi","character":"Basil Karapetian","img":null,"order":7},{"name":"David Harewood","character":"Joel Steadman","img":null,"order":8},{"name":"Hayley Squires","character":"Sally Price-Jones","img":null,"order":9},{"name":"Tom Hollander","character":"Lance Corkoran","img":null,"order":14},{"name":"Olivia Colman","character":"Angela Burr","img":"lawJUdbLb1YW0niaYjiVGR9IBG8.jpg","order":19},{"name":"Michael Nardone","character":"Frisky","img":null,"order":20},{"name":"Alistair Petrie","character":"Sandy Langbourne","img":null,"order":21},{"name":"Aure Atika","character":"","img":null,"order":281},{"name":"Noah Jupe","character":"","img":null,"order":380}],"tv:111110":[{"name":"I\u00f1aki Godoy","character":"Monkey D. Luffy","img":null,"order":0},{"name":"Emily Rudd","character":"Nami","img":null,"order":1},{"name":"Mackenyu","character":"Roronoa Zoro","img":null,"order":2},{"name":"Jacob Gibson","character":"Usopp","img":null,"order":3},{"name":"Vincent Regan","character":"Vice-Admiral Garp","img":null,"order":4},{"name":"Jeff Ward","character":"Buggy the Clown","img":null,"order":5},{"name":"Taz Skylar","character":"Sanji","img":null,"order":6},{"name":"Charithra Chandran","character":"Miss Wednesday / Nefertari Vivi","img":null,"order":7},{"name":"Mikaela Hoover","character":"Tony Tony Chopper (voice)","img":null,"order":8},{"name":"Morgan Davies","character":"Koby","img":null,"order":10},{"name":"Lera Abova","character":"Miss All Sunday","img":null,"order":11},{"name":"Armand Aucamp","character":"Bogard","img":null,"order":510},{"name":"McKinley Belcher III","character":"Captain Arlong","img":null,"order":546},{"name":"Jandre le Roux","character":"Kuroobi","img":null,"order":551},{"name":"Aidan Scott","character":"Helmeppo","img":null,"order":592}],"tv:61617":[{"name":"Elijah Wood","character":"Wirt (voice)","img":null,"order":0},{"name":"Collin Dean","character":"Gregory (voice)","img":null,"order":1},{"name":"Melanie Lynskey","character":"Beatrice (voice)","img":null,"order":2},{"name":"Samuel Ramey","character":"The Beast (voice)","img":null,"order":3},{"name":"Christopher Lloyd","character":"The Woodsman (voice)","img":null,"order":4},{"name":"Janet Klein","character":"Miss Langtree (voice)","img":null,"order":500},{"name":"Deborah Voigt","character":"Queen of the Clouds / Additional Voices (voice)","img":null,"order":501},{"name":"Chris Isaak","character":"Enoch / Additional Voices (voice)","img":null,"order":503},{"name":"John Cleese","character":"Adelaide (voice)","img":null,"order":510},{"name":"Sam Marin","character":"Old Man Langtree (voice)","img":null,"order":512},{"name":"Emily Brundige","character":"Sara / Additional Voices (voice)","img":null,"order":519},{"name":"Fred Stoller","character":"Fred The Horse (voice)","img":null,"order":521},{"name":"Cole Sanchez","character":"Jason Funderberker / Additional Voices (voice)","img":null,"order":521},{"name":"Shirley Jones","character":"Beatrice's Mother / Additional Voices (voice)","img":null,"order":523},{"name":"Jack Jones","character":"Gregory's Frog (voice)","img":null,"order":526}],"tv:60574":[{"name":"Cillian Murphy","character":"Thomas Shelby","img":null,"order":0},{"name":"Paul Anderson","character":"Arthur Shelby","img":null,"order":1},{"name":"Joe Cole","character":"John Shelby","img":null,"order":2},{"name":"Helen McCrory","character":"Polly Gray","img":null,"order":4},{"name":"Sophie Rundle","character":"Ada Shelby","img":null,"order":6},{"name":"Natasha O'Keeffe","character":"Lizzie Stark","img":null,"order":12},{"name":"Finn Cole","character":"Michael Gray","img":null,"order":14},{"name":"Ian Peck","character":"Curly","img":null,"order":15},{"name":"Tom Hardy","character":"Alfie Solomons","img":"d81K0RH8UX7tZj49tZaQhZ9ewH.jpg","order":16},{"name":"Ned Dennehy","character":"Charlie Strong","img":null,"order":17},{"name":"Harry Kirton","character":"Finn Shelby","img":null,"order":87},{"name":"Kate Phillips","character":"Linda Shelby","img":null,"order":104},{"name":"Annabelle Wallis","character":"Grace Shelby","img":null,"order":181},{"name":"Aimee-Ffion Edwards","character":"Esme Shelby","img":null,"order":606},{"name":"Packy Lee","character":"Johnny Dogs","img":null,"order":621}],"tv:250307":[{"name":"Noah Wyle","character":"Dr. Michael 'Robby' Robinavitch","img":null,"order":0},{"name":"Patrick Ball","character":"Dr. Frank Langdon","img":null,"order":2},{"name":"Katherine LaNasa","character":"Charge Nurse Dana Evans","img":null,"order":3},{"name":"Supriya Ganesh","character":"Dr. Samira Mohan","img":null,"order":4},{"name":"Fiona Dourif","character":"Dr. Cassie McKay","img":null,"order":5},{"name":"Taylor Dearden","character":"Dr. Melissa King","img":null,"order":6},{"name":"Isa Briones","character":"Dr. Trinity Santos","img":null,"order":7},{"name":"Gerran Howell","character":"Student Doctor Dennis Whitaker","img":null,"order":8},{"name":"Shabana Azeez","character":"Student Doctor Victoria Javadi","img":null,"order":9},{"name":"Alexandra Metz","character":"Dr. Yolanda Garcia","img":null,"order":508},{"name":"Ned Brower","character":"Nurse Jesse","img":null,"order":523},{"name":"Amielynn Abellera","character":"Nurse Perlah Alawi","img":null,"order":707},{"name":"Jalen Thomas Brooks","character":"Nurse Mateo Diaz","img":null,"order":708},{"name":"Brandon Mendez Homer","character":"Nurse Donald 'Donnie' Donahue","img":null,"order":709},{"name":"Kristin Villanueva","character":"Nurse Princess","img":null,"order":710}],"tv:225171":[{"name":"Rhea Seehorn","character":"Carol Sturka","img":null,"order":0},{"name":"Karolina Wydra","character":"Zosia","img":null,"order":1},{"name":"Carlos-Manuel Vesga","character":"Manousos Oviedo","img":null,"order":2},{"name":"Miriam Shor","character":"Helen","img":null,"order":500},{"name":"Samba Schutte","character":"Mr. Diabat\u00e9","img":null,"order":524},{"name":"Menik Gooneratne","character":"Laxmi","img":null,"order":525},{"name":"Darinka Arones","character":"Kusimayu","img":null,"order":526},{"name":"Anna Mhairi","character":"Vesper","img":null,"order":527},{"name":"Max Reeves","character":"Margaux","img":null,"order":528},{"name":"Olivia Rouyre","character":"Genevieve","img":null,"order":529},{"name":"Rayaan Kamal Khan","character":"Ravi","img":null,"order":532},{"name":"Elena Est\u00e9r","character":"T'ika","img":null,"order":537},{"name":"Soledad Campos","character":"Maternal Other","img":null,"order":559},{"name":"Jennifer Esquivel","character":"Sisa","img":null,"order":581},{"name":"Patrick Fabian","character":"Others' Phone Answering Service (voice) (uncredited)","img":null,"order":591}],"tv:94028":[{"name":"Andrew Scott","character":"Tom Ripley","img":"4F8XpjyQCvtuu21WFm5d8RF5Rl.jpg","order":0},{"name":"Dakota Fanning","character":"Marge Sherwood","img":null,"order":1},{"name":"Johnny Flynn","character":"Dickie Greenleaf","img":null,"order":2},{"name":"Kenneth Lonergan","character":"Herbert Greenleaf","img":null,"order":500},{"name":"Francesca Romana Bergamo","character":"Ermelinda","img":null,"order":511},{"name":"Pasquale Esposito","character":"Pucci","img":null,"order":512},{"name":"Arcangelo Iannace","character":"Giulio","img":null,"order":513},{"name":"Vittorio Viviani","character":"Matteo","img":null,"order":514},{"name":"Eliot Sumner","character":"Frederick 'Freddie' Miles","img":null,"order":515},{"name":"Bokeem Woodbine","character":"Alvin MacCarron","img":null,"order":516},{"name":"Renato Solpietro","character":"Carlo","img":null,"order":519},{"name":"Francesco Formichetti","character":"Sanremo Desk Clerk","img":null,"order":523},{"name":"Margherita Buy","character":"Sig. Silvana Buffi","img":null,"order":540},{"name":"Maurizio Lombardi","character":"Inspector Pietro Ravini","img":null,"order":544},{"name":"Gennaro Arena","character":"Naples Kid","img":null,"order":578}],"tv:245256":[{"name":"Lola Petticrew","character":"Dolours Price","img":null,"order":0},{"name":"Maxine Peake","character":"Older Dolours Price","img":null,"order":1},{"name":"Hazel Doupe","character":"Marian Price","img":null,"order":2},{"name":"Anthony Boyle","character":"Brendan Hughes","img":null,"order":3},{"name":"Tom Vaughan-Lawlor","character":"Older Brendan Hughes","img":null,"order":4},{"name":"Josh Finan","character":"Gerry Adams","img":null,"order":5},{"name":"Rory Kinnear","character":"Frank Kitson","img":null,"order":6},{"name":"Seamus O'Hara","character":"Mackers","img":null,"order":500},{"name":"Helen Behan","character":"Older Marian Price","img":null,"order":501},{"name":"Michael Colgan","character":"Older Gerry Adams","img":null,"order":502},{"name":"Conor O'Donnell","character":"Eamon","img":null,"order":503},{"name":"James Doherty","character":"Chief Inspector","img":null,"order":504},{"name":"Bill Jones","character":"Ian","img":null,"order":505},{"name":"Shannon Watson","character":"Make-up Artist","img":null,"order":506},{"name":"Emma Canning","character":"Kathleen","img":null,"order":508}],"tv:95396":[{"name":"Adam Scott","character":"Mark Scout","img":null,"order":0},{"name":"Britt Lower","character":"Helly Riggs","img":null,"order":1},{"name":"Tramell Tillman","character":"Seth Milchick","img":null,"order":2},{"name":"Zach Cherry","character":"Dylan George","img":null,"order":3},{"name":"Patricia Arquette","character":"Harmony Cobel","img":null,"order":4},{"name":"Jen Tullock","character":"Devon Scout-Hale","img":null,"order":5},{"name":"Michael Chernus","character":"Ricken Hale","img":null,"order":6},{"name":"Dichen Lachman","character":"Ms. Casey","img":null,"order":7},{"name":"Sarah Bock","character":"Eustice Huang","img":null,"order":8},{"name":"John Turturro","character":"Irving Bailiff","img":null,"order":9},{"name":"Christopher Walken","character":"Burt Goodman","img":null,"order":10},{"name":"Sydney Cole Alexander","character":"Natalie Kalen","img":null,"order":515},{"name":"Karen Aldridge","character":"Asal Regabhi","img":null,"order":522},{"name":"Michael Cumpsty","character":"Doug Graner","img":null,"order":529},{"name":"Claudia Robinson","character":"Felicia","img":null,"order":537}],"tv:1274":[{"name":"Peter Krause","character":"Nate Fisher","img":null,"order":0},{"name":"Michael C. Hall","character":"David Fisher","img":null,"order":1},{"name":"Frances Conroy","character":"Ruth Fisher","img":null,"order":2},{"name":"Lauren Ambrose","character":"Claire Fisher","img":null,"order":3},{"name":"Freddy Rodr\u00edguez","character":"Federico Diaz","img":null,"order":4},{"name":"Mathew St. Patrick","character":"Keith Charles","img":null,"order":5},{"name":"Rachel Griffiths","character":"Brenda Chenowith","img":null,"order":6},{"name":"Ben Foster","character":"Russell Corwin","img":null,"order":7},{"name":"Justina Machado","character":"Vanessa Diaz","img":null,"order":8},{"name":"Jeremy Sisto","character":"Billy Chenowith","img":null,"order":10},{"name":"Richard Jenkins","character":"Nathaniel Fisher","img":null,"order":11},{"name":"Lili Taylor","character":"Lisa Kimmel Fisher","img":null,"order":12},{"name":"James Cromwell","character":"George Sibley","img":null,"order":13},{"name":"Bronwyn Tosh","character":"Maya Fisher","img":null,"order":559},{"name":"Brenna Tosh","character":"Maya Fisher","img":null,"order":608}],"tv:86942":[{"name":"Tom Waes","character":"Bob Lemmens","img":null,"order":0},{"name":"Frank Lammers","character":"Ferry Bouman","img":null,"order":1},{"name":"Raymond Thiry","character":"John Zwart","img":null,"order":2},{"name":"Elise Schaap","character":"Danielle Bouman","img":null,"order":4},{"name":"Anna Drijver","character":"Kim De Rooij","img":null,"order":5},{"name":"Jeroen Van der Ven","character":"Patrick Dierickx","img":null,"order":6},{"name":"Ruth Becquart","character":"Nathalie Geudens","img":null,"order":7},{"name":"Manou Kersting","character":"Nick Janssens","img":null,"order":8},{"name":"Wim Willaert","character":"Laurent Berger","img":null,"order":10},{"name":"Sebastien Dewaele","character":"Jean-Pierre Berger","img":null,"order":11},{"name":"Emma Verlinden","character":"Polly","img":null,"order":187},{"name":"Katrien De Ruysscher","character":"Liesbeth Mertens","img":null,"order":553},{"name":"Robbie Cleiren","character":"Marc Gevers","img":null,"order":554},{"name":"Lieke van den Broek","character":"Sonja Van Kamp","img":null,"order":562},{"name":"Celest Henri Cornelis","character":"Jackson Geudens","img":null,"order":582}],"tv:86248":[{"name":"Robbie Amell","character":"Nathan Brown","img":null,"order":0},{"name":"Andy Allo","character":"Nora Antony","img":null,"order":1},{"name":"Allegra Edwards","character":"Ingrid Kannerman","img":null,"order":2},{"name":"Zainab Johnson","character":"Aleesha","img":null,"order":3},{"name":"Kevin Bigley","character":"Luke","img":null,"order":4},{"name":"Owen Daniels","character":"A.I. Guy","img":null,"order":5},{"name":"Andrea Rosen","character":"Lucy Slack","img":null,"order":6},{"name":"Josh Banday","character":"Ivan Spelich","img":null,"order":8},{"name":"Mackenzie Cardwell","character":"Tinsley","img":null,"order":9},{"name":"Andy Thompson","character":"Lionel Winter","img":null,"order":600},{"name":"Barclay Hope","character":"Oliver Kannerman","img":null,"order":607},{"name":"William B. Davis","character":"David Choak","img":null,"order":624},{"name":"Chloe Coleman","character":"Nevaeh","img":null,"order":632},{"name":"Yvetta Fisher","character":"Batia","img":null,"order":633},{"name":"Jessica Tuck","character":"Viv","img":null,"order":651}],"tv:210664":[{"name":"Stephen Graham","character":"Matthew Collins","img":null,"order":0},{"name":"Jason Flemyng","character":"Nick","img":null,"order":1},{"name":"Leanne Best","character":"Alison","img":null,"order":2},{"name":"Andrew Ellis","character":"Robbie","img":null,"order":3},{"name":"Chris Coghill","character":"Chris","img":null,"order":4},{"name":"Dean-Charles Chapman","character":"Jack","img":null,"order":5},{"name":"Sami Amber","character":"Billy","img":null,"order":6},{"name":"Steven Miller","character":"Young Lenny","img":null,"order":500}],"tv:270476":[{"name":"Matthew Rhys","character":"Mayor Tom Loftis","img":null,"order":0},{"name":"Kate O'Flynn","character":"Patricia Moyer","img":null,"order":1},{"name":"Kevin Carroll","character":"Sheriff Bechir Clemmons","img":null,"order":2},{"name":"Dale Dickey","character":"Rosemary","img":null,"order":3},{"name":"Kingston Rumi Southwick","character":"Evan Loftis","img":null,"order":4},{"name":"Stephen Root","character":"Wyck Crawford","img":null,"order":5},{"name":"Neil Casey","character":"Kurt","img":null,"order":500},{"name":"Jeff Hiller","character":"Dale","img":null,"order":501},{"name":"K Callan","character":"Ruth","img":null,"order":503},{"name":"Kylie McNeill","character":"Kelly","img":null,"order":504},{"name":"Beck Nolan","character":"PJ","img":null,"order":505},{"name":"Charles Van Flaherty","character":"Gil","img":null,"order":506},{"name":"Nancy Lenehan","character":"Gerrie","img":null,"order":508},{"name":"Christian Clemenson","character":"Dr. Morgan","img":null,"order":509},{"name":"Sipiwe Moyo","character":"Chelle","img":null,"order":529}],"tv:71912":[{"name":"Henry Cavill","character":"Geralt of Rivia","img":null,"order":0},{"name":"Anya Chalotra","character":"Yennefer of Vengerberg","img":null,"order":2},{"name":"Freya Allan","character":"Princess Cirilla 'Ciri' of Cintra","img":null,"order":3},{"name":"Joey Batey","character":"Jaskier / The Sandpiper","img":null,"order":4},{"name":"Eamon Farren","character":"Cahir","img":null,"order":5},{"name":"Mim\u00ee M. Khayisa","character":"Fringilla Vigo","img":null,"order":6},{"name":"Anna Shaffer","character":"Triss Merigold","img":null,"order":7},{"name":"Mahesh Jadu","character":"Vilgefortz of Roggeveen","img":null,"order":8},{"name":"Cassie Clare","character":"Philippa Eilhart","img":null,"order":11},{"name":"MyAnna Buring","character":"Tissaia De Vries","img":null,"order":14},{"name":"Mecia Simson","character":"Francesca Findabair","img":null,"order":18},{"name":"Bart Edwards","character":"The White Flame","img":null,"order":345},{"name":"Wilson Mbomio","character":"Dara","img":null,"order":500},{"name":"Therica Wilson-Read","character":"Sabrina","img":null,"order":542},{"name":"Royce Pierreson","character":"Istredd","img":null,"order":671}],"movie:76203":[{"name":"Chiwetel Ejiofor","character":"Solomon Northup","img":null,"order":0},{"name":"Michael Fassbender","character":"Edwin Epps","img":null,"order":1},{"name":"Lupita Nyong'o","character":"Patsey","img":null,"order":2},{"name":"Benedict Cumberbatch","character":"William Ford","img":null,"order":3},{"name":"Paul Dano","character":"John Tibeats","img":null,"order":4},{"name":"Sarah Paulson","character":"Mary Epps","img":null,"order":5},{"name":"Adepero Oduye","character":"Eliza","img":null,"order":6},{"name":"Scoot McNairy","character":"Brown","img":null,"order":7},{"name":"Paul Giamatti","character":"Theophilus Freeman","img":null,"order":8},{"name":"Brad Pitt","character":"Samuel Bass","img":null,"order":9},{"name":"Michael Kenneth Williams","character":"Robert","img":null,"order":10},{"name":"Alfre Woodard","character":"Mistress Shaw","img":null,"order":11},{"name":"Chris Chalk","character":"Clemens","img":null,"order":12},{"name":"Taran Killam","character":"Hamilton","img":null,"order":13},{"name":"Bill Camp","character":"Radburn","img":null,"order":14}],"movie:13654":[{"name":"Barry Bostwick","character":"Thunderbolt (voice)","img":null,"order":0},{"name":"Jason Alexander","character":"Lightning (voice)","img":null,"order":1},{"name":"Martin Short","character":"Lars (voice)","img":null,"order":2},{"name":"Bobby Lockwood","character":"Patch (voice)","img":null,"order":3},{"name":"Susanne Blakeslee","character":"Cruella (voice)","img":null,"order":4},{"name":"Samuel West","character":"Pongo (voice)","img":null,"order":5},{"name":"Maurice LaMarche","character":"Horace (voice)","img":null,"order":6},{"name":"Jeff Bennett","character":"Jasper (voice)","img":null,"order":7},{"name":"Jodi Benson","character":"Anita (voice)","img":null,"order":8},{"name":"Tim Bentinck","character":"Roger (voice)","img":null,"order":9},{"name":"Kath Soucie","character":"Perdita (voice)","img":null,"order":10},{"name":"Mary MacLeod","character":"Nanny (voice)","img":null,"order":11},{"name":"Michael Lerner","character":"Producer (voice)","img":null,"order":12},{"name":"Kathryn Beaumont","character":"Additional Voices (voice)","img":null,"order":13},{"name":"Nicolette Little","character":"Additional Voices (voice)","img":null,"order":14}],"movie:974453":[{"name":"Liam Neeson","character":"Thug","img":null,"order":0},{"name":"Ron Perlman","character":"Charlie Conner","img":null,"order":1},{"name":"Yolonda Ross","character":"Woman","img":null,"order":2},{"name":"Frankie Shaw","character":"Daisy","img":null,"order":3},{"name":"Daniel Diemer","character":"Kyle Conner","img":null,"order":4},{"name":"Jimmy Gonzales","character":"Diego Machado","img":null,"order":5},{"name":"Josh Drennen","character":"Thug's Dad","img":null,"order":6},{"name":"Deanna Tarraza","character":"Araceli","img":null,"order":7},{"name":"Terrence Pulliam","character":"Dre","img":null,"order":8},{"name":"Omar Moustafa Ghonim","character":"Armando","img":null,"order":9},{"name":"Tom Kemp","character":"Burt","img":null,"order":10},{"name":"Ryan Homchick","character":"Dr. Gruber","img":null,"order":11},{"name":"William Xifaras","character":"Kiko","img":null,"order":12},{"name":"Kris Eivers","character":"Priest","img":null,"order":13},{"name":"Ryan Caraway","character":"George","img":null,"order":14}],"movie:446791":[{"name":"Michelle Williams","character":"Gail Harris","img":null,"order":0},{"name":"Mark Wahlberg","character":"Fletcher Chase","img":null,"order":1},{"name":"Christopher Plummer","character":"Jean Paul Getty","img":null,"order":2},{"name":"Charlie Plummer","character":"John Paul Getty III","img":null,"order":3},{"name":"Romain Duris","character":"Cinquanta","img":null,"order":4},{"name":"Timothy Hutton","character":"Oswald Hinge","img":null,"order":5},{"name":"Charlie Shotwell","character":"John Paul Getty III (Age 7)","img":null,"order":6},{"name":"Andrew Buchan","character":"John Paul Getty II","img":null,"order":7},{"name":"Marco Leonardi","character":"Saverio Mammoliti","img":null,"order":8},{"name":"Giuseppe Bonifati","character":"Giovanni Iacovoni","img":null,"order":9},{"name":"Nicolas Vaporidis","character":"Il Tamia 'Chipmunk'","img":null,"order":10},{"name":"Andrea Piedimonte Bodini","character":"Corvo","img":null,"order":11},{"name":"Guglielmo Favilla","character":"Piccolino","img":null,"order":12},{"name":"Adele Tirante","character":"Maria","img":null,"order":13},{"name":"Stacy Martin","character":"Nancy","img":null,"order":14}],"movie:1013601":[{"name":"Robert De Niro","character":"Vito Genovese / Frank Costello","img":null,"order":0},{"name":"Debra Messing","character":"Bobbie Costello","img":null,"order":1},{"name":"Cosmo Jarvis","character":"Vincent Gigante","img":null,"order":2},{"name":"Kathrine Narducci","character":"Anna Genovese","img":null,"order":3},{"name":"Michael Rispoli","character":"Albert Anastasia","img":null,"order":4},{"name":"Michael Adler","character":"Senator Tobey","img":null,"order":5},{"name":"Ed Amatrudo","character":"Rudolph Halley","img":null,"order":6},{"name":"Joe Bacino","character":"Joe Profaci","img":null,"order":7},{"name":"Anthony J. Gallo","character":"Tommy Lucchese","img":null,"order":8},{"name":"Wallace Langham","character":"Senator Estes Kefauver","img":null,"order":9},{"name":"Louis Mustillo","character":"Joe Bonanno","img":null,"order":10},{"name":"Frank Piccirillo","character":"Richie Boiardo","img":null,"order":11},{"name":"Matt Servitto","character":"George Wolf","img":null,"order":12},{"name":"Robert Uricola","character":"Tony Bender","img":null,"order":13},{"name":"Belmont Cameli","character":"Frankie Boy","img":null,"order":14}],"movie:416153":[{"name":"James Franco","character":"Lemmy (voice)","img":null,"order":0},{"name":"Jeremy Renner","character":"Swifty (voice)","img":null,"order":1},{"name":"Alec Baldwin","character":"PB (voice)","img":null,"order":2},{"name":"Anjelica Huston","character":"Magda (voice)","img":null,"order":3},{"name":"Michael Madsen","character":"Duke (voice)","img":null,"order":4},{"name":"Heidi Klum","character":"Jade / Bertha (voice)","img":null,"order":5},{"name":"John Cleese","character":"Otto von Walrus (voice)","img":null,"order":6},{"name":"Omar Sy","character":"Leopold (voice)","img":null,"order":7},{"name":"Laurie Holden","character":"Dakota (voice)","img":null,"order":8},{"name":"Donny Falsetti","character":"Dusty (voice)","img":null,"order":9},{"name":"Susan Spano","character":"Mary (voice)","img":null,"order":10},{"name":"Jason Deline","character":"Naz Narwahl (voice)","img":null,"order":11},{"name":"Aaron Woodley","character":"Puffin Leader (voice)","img":null,"order":12},{"name":"Lucie Hager","character":"Countdown Inka (voice)","img":null,"order":13},{"name":"Lillian Moloy","character":"Young Jade","img":null,"order":14}],"movie:1607":[{"name":"Robert De Niro","character":"Lorenzo Anello","img":null,"order":0},{"name":"Chazz Palminteri","character":"Sonny LoSpecchio","img":null,"order":1},{"name":"Lillo Brancato","character":"Calogero 'C' Anello (Age 17)","img":null,"order":2},{"name":"Francis Capra","character":"Calogero 'C' Anello (Age 9)","img":null,"order":3},{"name":"Taral Hicks","character":"Jane Williams","img":null,"order":4},{"name":"Kathrine Narducci","character":"Rosina Anello","img":null,"order":5},{"name":"Clem Caserta","character":"Jimmy Whispers","img":null,"order":6},{"name":"Alfred Sauchelli, Jr.","character":"Bobby Bars","img":null,"order":7},{"name":"Frank Pietrangolare","character":"Danny K.O.","img":null,"order":8},{"name":"Joe Pesci","character":"Carmine","img":null,"order":9},{"name":"Robert D'Andrea","character":"Tony Toupee","img":null,"order":10},{"name":"Eddie Montanaro","character":"Eddie Mush","img":null,"order":11},{"name":"Fred Fischer","character":"JoJo 'The Whale'","img":null,"order":12},{"name":"Dave Salerno","character":"Frankie Coffeecake","img":null,"order":13},{"name":"Joseph D'Onofrio","character":"Slick (Age 17)","img":null,"order":14}],"movie:1380417":[{"name":"Yahya Abdul-Mateen II","character":"Wayne Strider","img":null,"order":0},{"name":"Mark Wahlberg","character":"Gregory Scarpa","img":null,"order":1},{"name":"Nicole Beharie","character":"Allison Strider","img":null,"order":2},{"name":"Josh Lucas","character":"Special Agent Everett Rhodes","img":null,"order":3},{"name":"David Strathairn","character":"Special Agent Roy K. Moore","img":null,"order":4},{"name":"Giancarlo Esposito","character":"Vernon Dahmer","img":null,"order":5},{"name":"Ethan Embry","character":"Sam Bowers","img":null,"order":6},{"name":"LisaGay Hamilton","character":"Ms. Rebecca Brewer","img":null,"order":7},{"name":"LaChanze","character":"Hattie Dahmer","img":null,"order":8},{"name":"Biko Eisen-Martin","character":"Special Agent Archie Crawford","img":null,"order":9},{"name":"Will Brittain","character":"Billy Roy Pitts","img":null,"order":10},{"name":"DeVere Jehl","character":"Edgar Ray Killen","img":null,"order":11},{"name":"Jody Thompson","character":"Lawrence Byrd","img":null,"order":12},{"name":"Zach Lane","character":"Howard Styles","img":null,"order":13},{"name":"Lee Perkins","character":"Sheriff Mitchell","img":null,"order":14}],"movie:271110":[{"name":"Chris Evans","character":"Steve Rogers / Captain America","img":null,"order":0},{"name":"Robert Downey Jr.","character":"Tony Stark / Iron Man","img":null,"order":1},{"name":"Scarlett Johansson","character":"Natasha Romanoff / Black Widow","img":null,"order":2},{"name":"Sebastian Stan","character":"Bucky Barnes / Winter Soldier","img":null,"order":3},{"name":"Anthony Mackie","character":"Sam Wilson / Falcon","img":null,"order":4},{"name":"Don Cheadle","character":"Lieutenant James Rhodes / War Machine","img":null,"order":5},{"name":"Jeremy Renner","character":"Clint Barton / Hawkeye","img":null,"order":6},{"name":"Chadwick Boseman","character":"T'Challa / Black Panther","img":null,"order":7},{"name":"Paul Bettany","character":"Vision","img":null,"order":8},{"name":"Elizabeth Olsen","character":"Wanda Maximoff / Scarlet Witch","img":null,"order":9},{"name":"Paul Rudd","character":"Scott Lang / Ant-Man","img":null,"order":10},{"name":"Emily VanCamp","character":"Sharon Carter","img":null,"order":11},{"name":"Tom Holland","character":"Peter Parker / Spider-Man","img":"xKBAaPIa1c7tzZD3Y0MhBLv4hPE.jpg","order":12},{"name":"Daniel Br\u00fchl","character":"Zemo","img":null,"order":13},{"name":"Frank Grillo","character":"Brock Rumlow / Crossbones","img":null,"order":14}],"movie:1771":[{"name":"Chris Evans","character":"Captain America / Steve Rogers","img":null,"order":0},{"name":"Hayley Atwell","character":"Peggy Carter","img":null,"order":1},{"name":"Sebastian Stan","character":"James Buchanan 'Bucky' Barnes","img":null,"order":2},{"name":"Tommy Lee Jones","character":"Colonel Chester Phillips","img":null,"order":3},{"name":"Hugo Weaving","character":"Johann Schmidt / Red Skull","img":null,"order":4},{"name":"Dominic Cooper","character":"Howard Stark","img":null,"order":5},{"name":"Richard Armitage","character":"Heinz Kruger","img":null,"order":6},{"name":"Stanley Tucci","character":"Dr. Abraham Erskine","img":null,"order":7},{"name":"Samuel L. Jackson","character":"Nick Fury","img":null,"order":8},{"name":"Toby Jones","character":"Dr. Arnim Zola","img":null,"order":9},{"name":"Neal McDonough","character":"Timothy 'Dum Dum' Dugan","img":null,"order":10},{"name":"Derek Luke","character":"Gabe Jones","img":null,"order":11},{"name":"Kenneth Choi","character":"Jim Morita","img":null,"order":12},{"name":"JJ Feild","character":"James Montgomery Falsworth","img":null,"order":13},{"name":"Bruno Ricci","character":"Jacques Dernier","img":null,"order":14}],"movie:100402":[{"name":"Chris Evans","character":"Steve Rogers / Captain America","img":null,"order":0},{"name":"Samuel L. Jackson","character":"Nick Fury","img":null,"order":1},{"name":"Scarlett Johansson","character":"Natasha Romanoff / Black Widow","img":null,"order":2},{"name":"Robert Redford","character":"Alexander Pierce","img":null,"order":3},{"name":"Sebastian Stan","character":"Bucky Barnes / Winter Soldier","img":null,"order":4},{"name":"Anthony Mackie","character":"Sam Wilson / Falcon","img":null,"order":5},{"name":"Cobie Smulders","character":"Maria Hill","img":null,"order":6},{"name":"Frank Grillo","character":"Brock Rumlow","img":null,"order":7},{"name":"Maximiliano Hern\u00e1ndez","character":"Jasper Sitwell","img":null,"order":8},{"name":"Emily VanCamp","character":"Kate / Agent 13","img":null,"order":9},{"name":"Hayley Atwell","character":"Peggy Carter","img":null,"order":10},{"name":"Toby Jones","character":"Dr. Arnim Zola","img":null,"order":11},{"name":"Stan Lee","character":"Smithsonian Guard","img":null,"order":12},{"name":"Callan Mulvey","character":"Jack Rollins","img":null,"order":13},{"name":"Jenny Agutter","character":"Councilwoman Hawley","img":null,"order":14}],"tv:60948":[{"name":"Aaron Stanford","character":"James Cole","img":null,"order":0},{"name":"Amanda Schull","character":"Cassandra Railly","img":null,"order":1},{"name":"Kirk Acevedo","character":"Jos\u00e9 Ramse","img":null,"order":2},{"name":"Barbara Sukowa","character":"Katarina Jones","img":null,"order":3},{"name":"Emily Hampshire","character":"Jennifer Goines","img":null,"order":4},{"name":"Todd Stashwick","character":"Deacon","img":null,"order":6},{"name":"Noah Bean","character":"Aaron Marker","img":null,"order":7},{"name":"Alisen Richmond-Peck","character":"Striking Woman","img":null,"order":366},{"name":"Scottie Thompson","character":"Vivian Rutledge","img":null,"order":519},{"name":"Peter DaCunha","character":"Samuel Ramse","img":null,"order":760},{"name":"Murray Furrow","character":"Lasky","img":null,"order":797},{"name":"Andrew Gillies","character":"Julian Adler","img":null,"order":800},{"name":"Tom Noonan","character":"Pallid Man","img":null,"order":805},{"name":"Demore Barnes","character":"Marcus Whitley","img":null,"order":806},{"name":"Brooke Williams","character":"Hannah Jones","img":null,"order":807}],"tv:202097":[{"name":"Jill Hennessy","character":"Lynn Harmon","img":null,"order":501},{"name":"Oakes Fegley","character":"Devin Harmon","img":null,"order":502},{"name":"Robert Wisdom","character":"Mitch Becker","img":null,"order":503},{"name":"J. Harrison Ghee","character":"Kevin Milstead","img":null,"order":504},{"name":"Evan Marsh","character":"Alex Harmon","img":null,"order":505},{"name":"Sonny McKnight","character":"Young Devin (Age 3)","img":null,"order":506},{"name":"Coleby Wojtak-Hissong","character":"Young Devin (Age 5)","img":null,"order":507},{"name":"Athan Giazitzidis","character":"Young Alex","img":null,"order":508},{"name":"Ali Momen","character":"Principal Sam Canosa","img":null,"order":509},{"name":"Tara Rosling","character":"Dr. Laurie Grotstein","img":null,"order":510},{"name":"Deklon Roberts","character":"Captain Kramer","img":null,"order":511},{"name":"Seema Doad","character":"Uniformed Officer","img":null,"order":512},{"name":"Michael Chiklis","character":"Dr. Scott Harmon","img":null,"order":596},{"name":"Daniel Maslany","character":"Public Defender Eli Demille","img":null,"order":633},{"name":"Matthew James Thomas","character":"Alexei","img":null,"order":639}],"tv:79410":[{"name":"Ricky Gervais","character":"Tony","img":null,"order":0},{"name":"Tom Basden","character":"Matt","img":null,"order":1},{"name":"Kerry Godliman","character":"Lisa","img":null,"order":2},{"name":"David Bradley","character":"Ray","img":null,"order":3},{"name":"Joe Wilkinson","character":"Pat","img":null,"order":4},{"name":"Roisin Conaty","character":"Daphne \"Roxy\"","img":null,"order":6},{"name":"Tony Way","character":"Lenny","img":null,"order":7},{"name":"Diane Morgan","character":"Kath","img":null,"order":9},{"name":"Ashley Jensen","character":"Emma","img":null,"order":11},{"name":"Tommy Finnegan","character":"George","img":null,"order":12},{"name":"Jo Hartley","character":"June","img":null,"order":13},{"name":"Penelope Wilton","character":"Anne","img":null,"order":14},{"name":"David Earl","character":"Brian","img":null,"order":15},{"name":"Ethan Lawrence","character":"James","img":null,"order":16},{"name":"Michelle Greenidge","character":"Valerie","img":null,"order":17}],"tv:7406":[{"name":"Lynda Bellingham","character":"Helen Herriot","img":null,"order":0},{"name":"Robert Hardy","character":"Siegfried Farnon","img":null,"order":1},{"name":"Christopher Timothy","character":"James Herriot","img":null,"order":2},{"name":"Carol Drinkwater","character":"Helen Herriot","img":null,"order":3},{"name":"Mary Hignett","character":"Mrs. Hall","img":null,"order":4},{"name":"Margaretta Scott","character":"Mrs. Pumphrey","img":null,"order":7},{"name":"Teddy Turner","character":"Hodgekin","img":null,"order":8},{"name":"Peter Davison","character":"Tristan Farnon","img":null,"order":10},{"name":"John McGlynn","character":"Calum Buchanan","img":null,"order":11},{"name":"Jean Heywood","character":"Mrs Alton","img":null,"order":12},{"name":"Peter Martin","character":"Handshaw","img":null,"order":839},{"name":"Oliver Wilson","character":"Jimmy Herriot","img":null,"order":928},{"name":"Rebecca Smith","character":"Rosie Herriot","img":null,"order":929},{"name":"John Sharp","character":"Mr. Biggins","img":null,"order":952},{"name":"Andrea Gibb","character":"Deidre Buchanan","img":null,"order":971}],"tv:67117":[{"name":"Katy Mixon","character":"Katie Otto","img":null,"order":0},{"name":"Diedrich Bader","character":"Greg Otto","img":null,"order":1},{"name":"Meg Donnelly","character":"Taylor Otto","img":null,"order":2},{"name":"Giselle Eisenberg","character":"Anna-Kat Otto","img":null,"order":3},{"name":"Julia Butters","character":"Anna-Kat Otto","img":null,"order":4},{"name":"Daniel DiMaggio","character":"Oliver Otto","img":null,"order":5},{"name":"Carly Hughes","character":"Angela","img":null,"order":6},{"name":"Ali Wong","character":"Doris","img":null,"order":7},{"name":"Jerry Lambert","character":"Principal Ablin","img":null,"order":515},{"name":"Logan Pepper","character":"Cooper Bradford","img":null,"order":518},{"name":"Peyton Meyer","character":"Trip Windsor","img":null,"order":519},{"name":"Wendie Malick","character":"Kathryn","img":null,"order":532},{"name":"Carly Craig","character":"Tara","img":null,"order":541},{"name":"Evan O'Toole","character":"Franklin","img":null,"order":565},{"name":"Julie Meyer","character":"Maria","img":null,"order":634}],"tv:47054":[{"name":"Mark Addy","character":"Hercules","img":null,"order":0},{"name":"Jack Donnelly","character":"Jason","img":null,"order":1},{"name":"Robert Emms","character":"Pythagoras","img":null,"order":2},{"name":"Aiysha Hart","character":"Ariadne","img":null,"order":3},{"name":"Sarah Parish","character":"Pasiphae","img":null,"order":4},{"name":"Juliet Stevenson","character":"The Oracle","img":null,"order":5},{"name":"Jemima Rooper","character":"Medusa","img":null,"order":6},{"name":"Amy Manson","character":"Medea","img":null,"order":7},{"name":"Alexander Siddig","character":"Minos","img":null,"order":8},{"name":"Vincent Regan","character":"Dion","img":null,"order":9},{"name":"Lorcan Cranitch","character":"Cilix","img":null,"order":10},{"name":"Robert Lindsay","character":"Daedalus","img":null,"order":11},{"name":"Anya Taylor-Joy","character":"Cassandra","img":null,"order":514},{"name":"Stuart Davidson","character":"Lysis's Masseur","img":null,"order":516},{"name":"Kate Davies-Speak","character":"Atlantean","img":null,"order":533}],"tv:62481":[{"name":"Bobby Flay","character":"Self","img":null,"order":0},{"name":"Giada De Laurentiis","character":"Self","img":null,"order":475},{"name":"Michael Symon","character":"Self","img":null,"order":493},{"name":"Scott Conant","character":"Self - Guest Judge","img":null,"order":503},{"name":"Alex Guarnaschelli","character":"Self - Guest Judge","img":null,"order":512},{"name":"Eddie Jackson","character":"Self","img":null,"order":512},{"name":"Sunny Anderson","character":"Self","img":null,"order":515},{"name":"Jet Tila","character":"Self","img":null,"order":524},{"name":"Anne Burrell","character":"Self","img":null,"order":526},{"name":"Ted Allen","character":"Self","img":null,"order":534},{"name":"Simon Majumdar","character":"Self","img":null,"order":536},{"name":"Geoffrey Zakarian","character":"Self","img":null,"order":537},{"name":"Michael Voltaggio","character":"Self","img":null,"order":549},{"name":"Amanda Freitag","character":"Self","img":null,"order":569},{"name":"Katie Lee Biegel","character":"Self","img":null,"order":645}],"tv:1849":[{"name":"Robert Guillaume","character":"Benson DuBois","img":null,"order":0},{"name":"James Noble","character":"Eugene Gatling","img":null,"order":1},{"name":"Inga Swenson","character":"Gretchen Kraus","img":null,"order":2},{"name":"Caroline McWilliams","character":"Marcy Hill","img":null,"order":3},{"name":"Missy Gold","character":"Katie Gatling","img":null,"order":4},{"name":"Ethan Phillips","character":"Pete Downey","img":null,"order":5},{"name":"Didi Conn","character":"Denise Stevens","img":null,"order":6},{"name":"Lewis J. Stadlen","character":"John Taylor","img":null,"order":7},{"name":"Ren\u00e9 Auberjonois","character":"Clayton Endicott III","img":null,"order":8},{"name":"Billie Bird","character":"Rose Cassidy","img":null,"order":9},{"name":"Beverly Todd","character":"Casey Turner","img":null,"order":507},{"name":"Ren\u00e9 Enr\u00edquez","character":"","img":null,"order":509},{"name":"Norman Bartold","character":"","img":null,"order":513},{"name":"G.W. Bailey","character":"","img":null,"order":539},{"name":"Jerry Seinfeld","character":"Frankie","img":null,"order":552}],"tv:249039":[{"name":"Jason Bateman","character":"Vince Friedken","img":null,"order":0},{"name":"Jude Law","character":"Jake Friedken","img":null,"order":1},{"name":"Chris Coy","character":"Babbitt","img":null,"order":2},{"name":"Troy Kotsur","character":"Joe Mancuso","img":null,"order":3},{"name":"Abbey Lee","character":"Anna","img":null,"order":4},{"name":"Odessa Young","character":"Gen","img":null,"order":5},{"name":"Robin de Jes\u00fas","character":"Tony","img":null,"order":6},{"name":"Cleopatra Coleman","character":"Estelle","img":null,"order":500},{"name":"\u1e62\u1ecdp\u1eb9\u0301 D\u00ecr\u00eds\u00f9","character":"Wes","img":null,"order":501},{"name":"Amaka Okafor","character":"Roxie","img":null,"order":502},{"name":"Dagmara Dominczyk","character":"Val","img":null,"order":503},{"name":"Don Harvey","character":"Matt","img":null,"order":504},{"name":"Gus Birney","character":"Mel Whitney","img":null,"order":505},{"name":"Forrest Weber","character":"Junior","img":null,"order":506},{"name":"Michael Cash","character":"Hunter","img":null,"order":510}],"tv:61381":[{"name":"Anthony Anderson","character":"Andre Johnson","img":null,"order":0},{"name":"Tracee Ellis Ross","character":"Rainbow Johnson","img":null,"order":1},{"name":"Yara Shahidi","character":"Zoey Johnson","img":null,"order":2},{"name":"Marcus Scribner","character":"Junior Johnson","img":null,"order":3},{"name":"Marsai Martin","character":"Diane Johnson","img":null,"order":4},{"name":"Miles Brown","character":"Jack Johnson","img":null,"order":5},{"name":"Jenifer Lewis","character":"Ruby Johnson","img":null,"order":6},{"name":"Deon Cole","character":"Charlie Telphy","img":null,"order":7},{"name":"Peter MacKenzie","character":"Leslie Stevens","img":null,"order":8},{"name":"Jeff Meacham","character":"Josh Oppenhol","img":null,"order":9},{"name":"Katlyn Nichol","character":"Olivia Lockhart","img":null,"order":10},{"name":"Laurence Fishburne","character":"Pops Johnson","img":null,"order":500},{"name":"Nelson Franklin","character":"Connor Stevens","img":null,"order":534},{"name":"Berlin Gross","character":"Devante Johnson","img":null,"order":562},{"name":"August Gross","character":"Devante Johnson","img":null,"order":563}],"tv:1396":[{"name":"Bryan Cranston","character":"Walter White","img":null,"order":0},{"name":"Aaron Paul","character":"Jesse Pinkman","img":null,"order":1},{"name":"Anna Gunn","character":"Skyler White","img":null,"order":2},{"name":"RJ Mitte","character":"Walter White Jr.","img":null,"order":3},{"name":"Dean Norris","character":"Hank Schrader","img":null,"order":4},{"name":"Betsy Brandt","character":"Marie Schrader","img":null,"order":5},{"name":"Giancarlo Esposito","character":"Gustavo Fring","img":null,"order":6},{"name":"Bob Odenkirk","character":"Saul Goodman","img":null,"order":7},{"name":"Steven Michael Quezada","character":"Steven Gomez","img":null,"order":8},{"name":"Jonathan Banks","character":"Mike Ehrmantraut","img":null,"order":9},{"name":"Christopher Cousins","character":"Ted Beneke","img":null,"order":604},{"name":"Michael Shamus Wiles","character":"ASAC George Merkert","img":null,"order":606},{"name":"Lavell Crawford","character":"Huell","img":null,"order":637},{"name":"Charles Baker","character":"Skinny Pete","img":null,"order":656},{"name":"Matt Jones","character":"Badger","img":null,"order":658}],"tv:93166":[{"name":"Holliday Grainger","character":"DI Rachel Carey","img":null,"order":0},{"name":"Callum Turner","character":"Shaun Emery","img":null,"order":1},{"name":"Ben Miles","character":"Commander Danny Hart","img":null,"order":2},{"name":"Lia Williams","character":"DSU Gemma Garland","img":null,"order":3},{"name":"Ron Perlman","character":"Frank Napier","img":null,"order":4},{"name":"Laura Haddock","character":"Hannah Roberts","img":null,"order":5},{"name":"Barry Ward","character":"Charlie Hall","img":null,"order":6},{"name":"Ginny Holder","character":"DC / DI Nadia Latif","img":null,"order":7},{"name":"Cavan Clerkin","character":"DS Patrick Flynn","img":null,"order":8},{"name":"Indira Varma","character":"Khadija Khan","img":null,"order":10},{"name":"Tessa Wong","character":"DC Chloe Tan","img":null,"order":12},{"name":"Andy Nyman","character":"Rowan Gill","img":null,"order":13},{"name":"Daisy Waterstone","character":"Abigail Carey","img":null,"order":15},{"name":"Nigel Lindsay","character":"DSI / DSU Tom Kendricks","img":null,"order":106},{"name":"Paapa Essiedu","character":"Isaac Turner","img":null,"order":160}]},"availableArt":["assets/cast/26R1LBiSOkkP08saSsz6LmVTY16.jpg","assets/cast/2tFblvjBRUYwcVT1V1i79Ppd6wG.jpg","assets/cast/320qW5yEbxpmyxQ3evmClJbtKag.jpg","assets/cast/4F8XpjyQCvtuu21WFm5d8RF5Rl.jpg","assets/cast/4eOoW1PNBZfxRW0g8RmYH8bL6mq.jpg","assets/cast/4gyHyg6FJ1oFczOm5pmMkdEEo2J.jpg","assets/cast/5L0kzTVITmOQdQ94NhicKM8ecCX.jpg","assets/cast/5VbadQsYCKdiJysP01LJFPmYB8A.jpg","assets/cast/5eIRHUbNOH7ibXa0IfUfFvj5I5L.jpg","assets/cast/5hn7WeXi6wguwxTPTSmcmzHAs9.jpg","assets/cast/6hmUs5Q1EETapn32yKNt3c3i1sn.jpg","assets/cast/7LVYeFTgUpjYDrxnU7Wm5ZQUX9t.jpg","assets/cast/7MHdNxS1gRnx0ZQGPrfS5eRjMe3.jpg","assets/cast/7Y96dAfg0HcFrcLjlD5eD9N0uj4.jpg","assets/cast/8v3lDa0QCJlDtOx9flqlMNIA3uf.jpg","assets/cast/9pxaoasotR1pdCXYSfN1pkm0geO.jpg","assets/cast/aHQk6XxqyJinfvrVRADEIg31nOk.jpg","assets/cast/aW6vCxkUZtwb6iH2Wf88Uq0XNVv.jpg","assets/cast/bLgmpSFgEiSFNshqmdl3EIZkRZm.jpg","assets/cast/biov5jENp2XYfehkcdnRvi796Wi.jpg","assets/cast/d81K0RH8UX7tZj49tZaQhZ9ewH.jpg","assets/cast/fD8GuLHOOSSAG98VjwN3NhAmqAJ.jpg","assets/cast/fbWWkhe7GVSlhBljY89rJd01OnA.jpg","assets/cast/fdFVatb9pt5dfT9tDK8tikKWafS.jpg","assets/cast/fjJc03z1cOlMxLZbC1qihsq3C37.jpg","assets/cast/hOntuFYAMwn9QaXT0AwLCPU79ce.jpg","assets/cast/hrTwOPWek7nkPJgFhh6inFu7vSS.jpg","assets/cast/hzu7OqTmNCT1xdCdmwBSf2yJvaO.jpg","assets/cast/iQLEawIP2593yrGy22GzLSpnfgl.jpg","assets/cast/j0GXzLelO1dOzI7d1WVIwQXhLz8.jpg","assets/cast/jUuUbPuMGonFT5E2pcs4alfqaCN.jpg","assets/cast/lF06PTNYrlXeJ3DYApvOcPXJr87.jpg","assets/cast/lUhVV9u5VGMCNdCAVhGzg8GFSdo.jpg","assets/cast/lawJUdbLb1YW0niaYjiVGR9IBG8.jpg","assets/cast/lfbyJWNWGbiYfU0Yr1tjn6Trd2V.jpg","assets/cast/lpEs9yDsMQlsbm0RVsvDIleCXcI.jpg","assets/cast/mF5YJxApTYKBVFJDrEC9IrJ5ooV.jpg","assets/cast/mW7xmtGV4y79kQGn0zkKVGDMAmw.jpg","assets/cast/mk5vpYLmER7asqOhEwVKXD3P3YE.jpg","assets/cast/mnKYU7HIsuRkx3YjdRO5FLXCdX5.jpg","assets/cast/msqe5A1q5YUUND0RhzB9dw1AEAO.jpg","assets/cast/nAxS5l9vb1C8ltCp9yAa0f6lazu.jpg","assets/cast/nmgOd3X2Xn3jIp9OLCRJzLExRWN.jpg","assets/cast/o7splcOIVAdbHnwohJOUAvXWVlk.jpg","assets/cast/oMHMLhoV3ry8aOfdvs1kxyowhNq.jpg","assets/cast/omWXGbeRR32MWuYhpnLOSqJ6xkO.jpg","assets/cast/pVwR9hsEiHzVTo9giCjR3vIfa8W.jpg","assets/cast/phEIvq0Ay2KjI5ewmVvpQ1a29GJ.jpg","assets/cast/qP5vQMIbLNvSsSFkEMLZRVt4ZW5.jpg","assets/cast/qiWu2gphSg64igYl3Nx0hEIOQF3.jpg","assets/cast/qwbjcyDN37OHiln4a6P4LP31o7F.jpg","assets/cast/r6s7dkYZUJpd00C7p9itT6Gp8XB.jpg","assets/cast/rDTxblyw0AwU5oSeksgP7GwMyrF.jpg","assets/cast/rIqcwewXdkrDTMTwX56QPa7MNTC.jpg","assets/cast/rLzduQpYJnZJKkXv3jRc7MDHwoI.jpg","assets/cast/rbxBK2m6fEq0oHeMoBUMVYkJEdJ.jpg","assets/cast/sG6CWLdENCtzukNFkFYyPxqyRmS.jpg","assets/cast/sh4ANkKoIHgmHtkKQbJvF8y0Fjq.jpg","assets/cast/tqFHQiJUycuob3ytvilaAWDlbQ8.jpg","assets/cast/uL8yfcm0dCFYFQt052kczVQVvac.jpg","assets/cast/ub2IuMWFNQGYghHTPq0lpmn2Ue0.jpg","assets/cast/ukDNHgvEgdU95eaw6pngiAPucv4.jpg","assets/cast/v4sRxLpRpHEd9vbk43wm9VL0v0K.jpg","assets/cast/wWcby4ARYqr8d92ZdjyQcfaiJBW.jpg","assets/cast/waayy0jpNbxLDQ8JO1uRDng8SLF.jpg","assets/cast/x0lmqgkmphvOCSTHk2oxsaxA9Ra.jpg","assets/cast/xKBAaPIa1c7tzZD3Y0MhBLv4hPE.jpg","assets/cast/xV9UrP8kZdxOiTI2efDFhp3t4iA.jpg","assets/cast/xm2pYFBggiXSkFBV2I612i3fDd3.jpg","assets/cast/xx3As5SWcE8vYOKZgtjDjqmT3jc.jpg","assets/cast/yU0OXeZ0K1ppe1o9SpHiAMHy1rc.jpg","assets/cast/yWZILsr2mBQBCG1LOcCYYshIbts.jpg","assets/cast/yxGsAKnrJZs2g6q4unNgkfm7NAA.jpg","assets/cast/ztxDIZvuPreUixO6ZPxwkCg2UlO.jpg","assets/episode-all-hands-on-deck-class-1-a-2021-s5e1-backdrop.jpg","assets/episode-all-hands-on-deck-class-1-a-2021-s5e1-poster.jpg","assets/episode-announcement-2022-s1e7-backdrop.jpg","assets/episode-announcement-2022-s1e7-poster.jpg","assets/episode-episode-1-2025-s1e1-backdrop.jpg","assets/episode-episode-1-2025-s1e1-poster.jpg","assets/episode-episode-2-2016-s1e2-backdrop.jpg","assets/episode-episode-2-2016-s1e2-poster.jpg","assets/episode-erickerhead-2026-s9e6-backdrop.jpg","assets/episode-erickerhead-2026-s9e6-poster.jpg","assets/episode-girls-interrupted-2007-s1e7-backdrop.jpg","assets/episode-girls-interrupted-2007-s1e7-poster.jpg","assets/episode-i-heart-ny-2002-s4e18-backdrop.jpg","assets/episode-i-heart-ny-2002-s4e18-poster.jpg","assets/episode-new-day-2021-s1e2-backdrop.jpg","assets/episode-new-day-2021-s1e2-poster.jpg","assets/episode-no-honeymoon-2020-s1e8-backdrop.jpg","assets/episode-no-honeymoon-2020-s1e8-poster.jpg","assets/episode-notapusy-2005-s3e4-backdrop.jpg","assets/episode-notapusy-2005-s3e4-poster.jpg","assets/episode-one-of-us-2024-s1e7-backdrop.jpg","assets/episode-one-of-us-2024-s1e7-poster.jpg","assets/episode-remembrance-day-2026-s2e1-backdrop.jpg","assets/episode-remembrance-day-2026-s2e1-poster.jpg","assets/episode-sex-and-the-country-2001-s4e9-backdrop.jpg","assets/episode-sex-and-the-country-2001-s4e9-poster.jpg","assets/episode-south-american-biker-gangs-2026-s29e1-backdrop.jpg","assets/episode-south-american-biker-gangs-2026-s29e1-poster.jpg","assets/episode-the-breakup-part-2-2001-s1e17-backdrop.jpg","assets/episode-the-breakup-part-2-2001-s1e17-poster.jpg","assets/episode-the-man-who-would-be-vogue-2018-s2e1-backdrop.jpg","assets/episode-the-man-who-would-be-vogue-2018-s2e1-poster.jpg","assets/episode-the-uncomfortability-2010-s1e2-backdrop.jpg","assets/episode-the-uncomfortability-2010-s1e2-poster.jpg","assets/episode-three-monsters-1992-s1e6-backdrop.jpg","assets/episode-three-monsters-1992-s1e6-poster.jpg","assets/episode-tomorrow-2024-s3e1-backdrop.jpg","assets/episode-tomorrow-2024-s3e1-poster.jpg","assets/episode-what-more-do-i-need-2008-s5e7-backdrop.jpg","assets/episode-what-more-do-i-need-2008-s5e7-poster.jpg","assets/movie-101-dalmatians-ii-patch-s-london-adventure-2003-backdrop.jpg","assets/movie-101-dalmatians-ii-patch-s-london-adventure-2003-poster.jpg","assets/movie-a-bronx-tale-1993-backdrop.jpg","assets/movie-a-bronx-tale-1993-poster.jpg","assets/movie-a-silent-voice-the-movie-2016-backdrop.jpg","assets/movie-a-silent-voice-the-movie-2016-poster.jpg","assets/movie-absolution-2024-backdrop.jpg","assets/movie-absolution-2024-poster.jpg","assets/movie-across-the-hall-2009-backdrop.jpg","assets/movie-across-the-hall-2009-poster.jpg","assets/movie-addicted-2014-backdrop.jpg","assets/movie-addicted-2014-poster.jpg","assets/movie-adulterers-2016-backdrop.jpg","assets/movie-adulterers-2016-poster.jpg","assets/movie-all-the-money-in-the-world-2017-backdrop.jpg","assets/movie-all-the-money-in-the-world-2017-poster.jpg","assets/movie-alone-with-her-2006-backdrop.jpg","assets/movie-alone-with-her-2006-poster.jpg","assets/movie-american-gangster-2007-backdrop.jpg","assets/movie-american-gangster-2007-poster.jpg","assets/movie-annie-hall-1977-backdrop.jpg","assets/movie-annie-hall-1977-poster.jpg","assets/movie-ant-man-and-the-wasp-quantumania-2023-backdrop.jpg","assets/movie-ant-man-and-the-wasp-quantumania-2023-poster.jpg","assets/movie-appleseed-alpha-2014-backdrop.jpg","assets/movie-appleseed-alpha-2014-poster.jpg","assets/movie-aquaman-and-the-lost-kingdom-2023-backdrop.jpg","assets/movie-aquaman-and-the-lost-kingdom-2023-poster.jpg","assets/movie-arctic-dogs-2019-backdrop.jpg","assets/movie-arctic-dogs-2019-poster.jpg","assets/movie-arrival-2016-backdrop.jpg","assets/movie-arrival-2016-poster.jpg","assets/movie-avatar-aang-the-last-airbender-2026-backdrop.jpg","assets/movie-avatar-aang-the-last-airbender-2026-poster.jpg","assets/movie-avengers-age-of-ultron-2015-backdrop.jpg","assets/movie-avengers-age-of-ultron-2015-poster.jpg","assets/movie-avengers-confidential-black-widow-punisher-2014-backdrop.jpg","assets/movie-avengers-confidential-black-widow-punisher-2014-poster.jpg","assets/movie-avengers-infinity-war-2018-backdrop.jpg","assets/movie-avengers-infinity-war-2018-poster.jpg","assets/movie-awake-2007-backdrop.jpg","assets/movie-awake-2007-poster.jpg","assets/movie-batman-ninja-2018-backdrop.jpg","assets/movie-batman-ninja-2018-poster.jpg","assets/movie-batman-the-dark-knight-returns-part-1-2012-backdrop.jpg","assets/movie-batman-the-dark-knight-returns-part-1-2012-poster.jpg","assets/movie-batman-v-superman-dawn-of-justice-2016-backdrop.jpg","assets/movie-batman-v-superman-dawn-of-justice-2016-poster.jpg","assets/movie-black-adam-2022-backdrop.jpg","assets/movie-black-adam-2022-poster.jpg","assets/movie-black-bear-2020-backdrop.jpg","assets/movie-black-bear-2020-poster.jpg","assets/movie-black-panther-2018-backdrop.jpg","assets/movie-black-panther-2018-poster.jpg","assets/movie-black-panther-wakanda-forever-2022-backdrop.jpg","assets/movie-black-panther-wakanda-forever-2022-poster.jpg","assets/movie-blame-2017-backdrop.jpg","assets/movie-blame-2017-poster.jpg","assets/movie-bleach-the-movie-fade-to-black-2008-backdrop.jpg","assets/movie-bleach-the-movie-fade-to-black-2008-poster.jpg","assets/movie-butterfly-on-a-wheel-2007-backdrop.jpg","assets/movie-butterfly-on-a-wheel-2007-poster.jpg","assets/movie-captain-america-civil-war-2016-backdrop.jpg","assets/movie-captain-america-civil-war-2016-poster.jpg","assets/movie-careful-what-you-wish-for-2015-backdrop.jpg","assets/movie-careful-what-you-wish-for-2015-poster.jpg","assets/movie-castle-in-the-sky-1986-backdrop.jpg","assets/movie-castle-in-the-sky-1986-poster.jpg","assets/movie-chicago-2002-backdrop.jpg","assets/movie-chicago-2002-poster.jpg","assets/movie-citizen-kane-1941-backdrop.jpg","assets/movie-citizen-kane-1941-poster.jpg","assets/movie-conclave-2024-backdrop.jpg","assets/movie-conclave-2024-poster.jpg","assets/movie-crime-of-passion-1956-backdrop.jpg","assets/movie-crime-of-passion-1956-poster.jpg","assets/movie-deep-water-2022-backdrop.jpg","assets/movie-deep-water-2022-poster.jpg","assets/movie-derailed-2005-backdrop.jpg","assets/movie-derailed-2005-poster.jpg","assets/movie-dream-house-2011-backdrop.jpg","assets/movie-dream-house-2011-poster.jpg","assets/movie-dream-lover-1994-backdrop.jpg","assets/movie-dream-lover-1994-poster.jpg","assets/movie-drop-2025-backdrop.jpg","assets/movie-drop-2025-poster.jpg","assets/movie-eastern-promises-2007-backdrop.jpg","assets/movie-eastern-promises-2007-poster.jpg","assets/movie-el-camino-a-breaking-bad-movie-2019-backdrop.jpg","assets/movie-el-camino-a-breaking-bad-movie-2019-poster.jpg","assets/movie-fatale-2020-backdrop.jpg","assets/movie-fatale-2020-poster.jpg","assets/movie-force-of-nature-the-dry-2-2024-backdrop.jpg","assets/movie-force-of-nature-the-dry-2-2024-poster.jpg","assets/movie-ghost-in-the-shell-1995-backdrop.jpg","assets/movie-ghost-in-the-shell-1995-poster.jpg","assets/movie-ghost-in-the-shell-2-innocence-2004-backdrop.jpg","assets/movie-ghost-in-the-shell-2-innocence-2004-poster.jpg","assets/movie-gosford-park-2001-backdrop.jpg","assets/movie-gosford-park-2001-poster.jpg","assets/movie-howl-s-moving-castle-2004-backdrop.jpg","assets/movie-howl-s-moving-castle-2004-poster.jpg","assets/movie-in-the-heights-2021-backdrop.jpg","assets/movie-in-the-heights-2021-poster.jpg","assets/movie-kiki-s-delivery-service-1989-backdrop.jpg","assets/movie-kiki-s-delivery-service-1989-poster.jpg","assets/movie-lemony-snicket-s-a-series-of-unfortunate-events-2004-backdrop.jpg","assets/movie-lemony-snicket-s-a-series-of-unfortunate-events-2004-poster.jpg","assets/movie-locke-2014-backdrop.jpg","assets/movie-locke-2014-poster.jpg","assets/movie-memories-1995-backdrop.jpg","assets/movie-memories-1995-poster.jpg","assets/movie-night-is-short-walk-on-girl-2017-backdrop.jpg","assets/movie-night-is-short-walk-on-girl-2017-poster.jpg","assets/movie-panic-room-2002-backdrop.jpg","assets/movie-panic-room-2002-poster.jpg","assets/movie-ponyo-2008-backdrop.jpg","assets/movie-ponyo-2008-poster.jpg","assets/movie-porco-rosso-1992-backdrop.jpg","assets/movie-porco-rosso-1992-poster.jpg","assets/movie-princess-mononoke-1997-backdrop.jpg","assets/movie-princess-mononoke-1997-poster.jpg","assets/movie-prisoners-2013-backdrop.jpg","assets/movie-prisoners-2013-poster.jpg","assets/movie-racing-stripes-2005-backdrop.jpg","assets/movie-racing-stripes-2005-poster.jpg","assets/movie-secondhand-lions-2003-backdrop.jpg","assets/movie-secondhand-lions-2003-poster.jpg","assets/movie-shaft-2000-backdrop.jpg","assets/movie-shaft-2000-poster.jpg","assets/movie-sinbad-legend-of-the-seven-seas-2003-backdrop.jpg","assets/movie-sinbad-legend-of-the-seven-seas-2003-poster.jpg","assets/movie-sleeping-with-other-people-2015-backdrop.jpg","assets/movie-sleeping-with-other-people-2015-poster.jpg","assets/movie-snowpiercer-2013-backdrop.jpg","assets/movie-snowpiercer-2013-poster.jpg","assets/movie-spider-man-brand-new-day-2026-backdrop.jpg","assets/movie-spider-man-brand-new-day-2026-poster.jpg","assets/movie-spider-man-far-from-home-2019-backdrop.jpg","assets/movie-spider-man-far-from-home-2019-poster.jpg","assets/movie-spider-man-homecoming-2017-backdrop.jpg","assets/movie-spider-man-homecoming-2017-poster.jpg","assets/movie-spider-man-no-way-home-2021-backdrop.jpg","assets/movie-spider-man-no-way-home-2021-poster.jpg","assets/movie-spirited-away-2001-backdrop.jpg","assets/movie-spirited-away-2001-poster.jpg","assets/movie-the-alto-knights-2025-backdrop.jpg","assets/movie-the-alto-knights-2025-poster.jpg","assets/movie-the-amazing-spider-man-2-2014-backdrop.jpg","assets/movie-the-amazing-spider-man-2-2014-poster.jpg","assets/movie-the-amazing-spider-man-2012-backdrop.jpg","assets/movie-the-amazing-spider-man-2012-poster.jpg","assets/movie-the-animatrix-2003-backdrop.jpg","assets/movie-the-animatrix-2003-poster.jpg","assets/movie-the-avengers-2012-backdrop.jpg","assets/movie-the-avengers-2012-poster.jpg","assets/movie-the-boy-and-the-heron-2023-backdrop.jpg","assets/movie-the-boy-and-the-heron-2023-poster.jpg","assets/movie-the-breakfast-club-1985-backdrop.jpg","assets/movie-the-breakfast-club-1985-poster.jpg","assets/movie-the-dry-2021-backdrop.jpg","assets/movie-the-dry-2021-poster.jpg","assets/movie-the-girl-who-leapt-through-time-2006-backdrop.jpg","assets/movie-the-girl-who-leapt-through-time-2006-poster.jpg","assets/movie-the-godfather-1972-backdrop.jpg","assets/movie-the-godfather-1972-poster.jpg","assets/movie-the-godfather-part-iii-1990-backdrop.jpg","assets/movie-the-godfather-part-iii-1990-poster.jpg","assets/movie-the-great-gatsby-2013-backdrop.jpg","assets/movie-the-great-gatsby-2013-poster.jpg","assets/movie-the-killing-of-a-sacred-deer-2017-backdrop.jpg","assets/movie-the-killing-of-a-sacred-deer-2017-poster.jpg","assets/movie-the-lighthouse-2019-backdrop.jpg","assets/movie-the-lighthouse-2019-poster.jpg","assets/movie-the-secret-life-of-pets-2-2019-backdrop.jpg","assets/movie-the-secret-life-of-pets-2-2019-poster.jpg","assets/movie-the-tale-of-the-princess-kaguya-2013-backdrop.jpg","assets/movie-the-tale-of-the-princess-kaguya-2013-poster.jpg","assets/movie-the-wild-robot-2024-backdrop.jpg","assets/movie-the-wild-robot-2024-poster.jpg","assets/movie-the-witcher-nightmare-of-the-wolf-2021-backdrop.jpg","assets/movie-the-witcher-nightmare-of-the-wolf-2021-poster.jpg","assets/movie-the-witcher-sirens-of-the-deep-2025-backdrop.jpg","assets/movie-the-witcher-sirens-of-the-deep-2025-poster.jpg","assets/movie-thelma-louise-1991-backdrop.jpg","assets/movie-thelma-louise-1991-poster.jpg","assets/movie-triangle-of-sadness-2022-backdrop.jpg","assets/movie-triangle-of-sadness-2022-poster.jpg","assets/movie-vice-2018-backdrop.jpg","assets/movie-vice-2018-poster.jpg","assets/tv-12-monkeys-2015-backdrop.jpg","assets/tv-12-monkeys-2015-poster.jpg","assets/tv-56-days-2026-backdrop.jpg","assets/tv-56-days-2026-poster.jpg","assets/tv-a-knight-of-the-seven-kingdoms-2026-backdrop.jpg","assets/tv-a-knight-of-the-seven-kingdoms-2026-poster.jpg","assets/tv-absolutely-fabulous-1992-backdrop.jpg","assets/tv-absolutely-fabulous-1992-poster.jpg","assets/tv-accel-world-2012-backdrop.jpg","assets/tv-accel-world-2012-poster.jpg","assets/tv-accused-2023-backdrop.jpg","assets/tv-accused-2023-poster.jpg","assets/tv-after-life-2019-backdrop.jpg","assets/tv-after-life-2019-poster.jpg","assets/tv-agatha-christie-s-marple-2004-backdrop.jpg","assets/tv-agatha-christie-s-marple-2004-poster.jpg","assets/tv-ahsoka-2023-backdrop.jpg","assets/tv-ahsoka-2023-poster.jpg","assets/tv-all-creatures-great-and-small-1978-backdrop.jpg","assets/tv-all-creatures-great-and-small-1978-poster.jpg","assets/tv-all-creatures-great-small-2020-backdrop.jpg","assets/tv-all-creatures-great-small-2020-poster.jpg","assets/tv-american-dad-2005-backdrop.jpg","assets/tv-american-dad-2005-poster.jpg","assets/tv-american-gods-2017-backdrop.jpg","assets/tv-american-gods-2017-poster.jpg","assets/tv-american-housewife-2016-backdrop.jpg","assets/tv-american-housewife-2016-poster.jpg","assets/tv-american-primeval-2025-backdrop.jpg","assets/tv-american-primeval-2025-poster.jpg","assets/tv-and-just-like-that-2021-backdrop.jpg","assets/tv-and-just-like-that-2021-poster.jpg","assets/tv-andor-2022-backdrop.jpg","assets/tv-andor-2022-poster.jpg","assets/tv-andromeda-2000-backdrop.jpg","assets/tv-andromeda-2000-poster.jpg","assets/tv-anne-with-an-e-2017-backdrop.jpg","assets/tv-anne-with-an-e-2017-poster.jpg","assets/tv-aqua-teen-hunger-force-2000-backdrop.jpg","assets/tv-aqua-teen-hunger-force-2000-poster.jpg","assets/tv-arifureta-from-commonplace-to-world-s-strongest-2019-backdrop.jpg","assets/tv-arifureta-from-commonplace-to-world-s-strongest-2019-poster.jpg","assets/tv-arrow-2012-backdrop.jpg","assets/tv-arrow-2012-poster.jpg","assets/tv-atlantis-2013-backdrop.jpg","assets/tv-atlantis-2013-poster.jpg","assets/tv-avatar-seven-havens-2026-backdrop.jpg","assets/tv-avatar-seven-havens-2026-poster.jpg","assets/tv-avatar-the-last-airbender-2005-backdrop.jpg","assets/tv-avatar-the-last-airbender-2005-poster.jpg","assets/tv-avatar-the-last-airbender-2024-backdrop.jpg","assets/tv-avatar-the-last-airbender-2024-poster.jpg","assets/tv-awkward-2011-backdrop.jpg","assets/tv-awkward-2011-poster.jpg","assets/tv-back-to-life-2019-backdrop.jpg","assets/tv-back-to-life-2019-poster.jpg","assets/tv-ballers-2015-backdrop.jpg","assets/tv-ballers-2015-poster.jpg","assets/tv-baretta-1975-backdrop.jpg","assets/tv-baretta-1975-poster.jpg","assets/tv-based-on-a-true-story-2023-backdrop.jpg","assets/tv-based-on-a-true-story-2023-poster.jpg","assets/tv-batman-the-brave-and-the-bold-2008-backdrop.jpg","assets/tv-batman-the-brave-and-the-bold-2008-poster.jpg","assets/tv-batwoman-2019-backdrop.jpg","assets/tv-batwoman-2019-poster.jpg","assets/tv-big-boys-2022-backdrop.jpg","assets/tv-big-boys-2022-poster.jpg","assets/tv-big-city-greens-2018-backdrop.jpg","assets/tv-big-city-greens-2018-poster.jpg","assets/tv-big-mouth-2017-backdrop.jpg","assets/tv-big-mouth-2017-poster.jpg","assets/tv-black-lightning-2018-backdrop.jpg","assets/tv-black-lightning-2018-poster.jpg","assets/tv-black-rabbit-2025-backdrop.jpg","assets/tv-black-rabbit-2025-poster.jpg","assets/tv-bleach-2004-backdrop.jpg","assets/tv-bleach-2004-poster.jpg","assets/tv-brassic-2019-backdrop.jpg","assets/tv-brassic-2019-poster.jpg","assets/tv-breaking-bad-2008-backdrop.jpg","assets/tv-breaking-bad-2008-poster.jpg","assets/tv-californication-2007-backdrop.jpg","assets/tv-californication-2007-poster.jpg","assets/tv-chainsaw-man-2022-backdrop.jpg","assets/tv-chainsaw-man-2022-poster.jpg","assets/tv-cyberpunk-edgerunners-2022-backdrop.jpg","assets/tv-cyberpunk-edgerunners-2022-poster.jpg","assets/tv-derry-girls-2018-backdrop.jpg","assets/tv-derry-girls-2018-poster.jpg","assets/tv-desperate-housewives-2004-backdrop.jpg","assets/tv-desperate-housewives-2004-poster.jpg","assets/tv-dune-prophecy-2024-backdrop.jpg","assets/tv-dune-prophecy-2024-poster.jpg","assets/tv-etoile-2025-backdrop.jpg","assets/tv-etoile-2025-poster.jpg","assets/tv-fallout-2024-backdrop.jpg","assets/tv-fallout-2024-poster.jpg","assets/tv-firefly-2002-backdrop.jpg","assets/tv-firefly-2002-poster.jpg","assets/tv-fleabag-2016-backdrop.jpg","assets/tv-fleabag-2016-poster.jpg","assets/tv-gilmore-girls-2000-backdrop.jpg","assets/tv-gilmore-girls-2000-poster.jpg","assets/tv-high-potential-2024-backdrop.jpg","assets/tv-high-potential-2024-poster.jpg","assets/tv-invincible-2021-backdrop.jpg","assets/tv-invincible-2021-poster.jpg","assets/tv-last-samurai-standing-2025-backdrop.jpg","assets/tv-last-samurai-standing-2025-poster.jpg","assets/tv-lord-of-the-flies-2026-backdrop.jpg","assets/tv-lord-of-the-flies-2026-poster.jpg","assets/tv-love-death-robots-2019-backdrop.jpg","assets/tv-love-death-robots-2019-poster.jpg","assets/tv-maniac-2018-backdrop.jpg","assets/tv-maniac-2018-poster.jpg","assets/tv-neon-genesis-evangelion-1995-backdrop.jpg","assets/tv-neon-genesis-evangelion-1995-poster.jpg","assets/tv-norsemen-2016-backdrop.jpg","assets/tv-norsemen-2016-poster.jpg","assets/tv-one-piece-2023-backdrop.jpg","assets/tv-one-piece-2023-poster.jpg","assets/tv-only-murders-in-the-building-2021-backdrop.jpg","assets/tv-only-murders-in-the-building-2021-poster.jpg","assets/tv-over-the-garden-wall-2014-backdrop.jpg","assets/tv-over-the-garden-wall-2014-poster.jpg","assets/tv-pluribus-2025-backdrop.jpg","assets/tv-pluribus-2025-poster.jpg","assets/tv-rick-and-morty-2013-backdrop.jpg","assets/tv-rick-and-morty-2013-poster.jpg","assets/tv-secret-level-2024-backdrop.jpg","assets/tv-secret-level-2024-poster.jpg","assets/tv-severance-2022-backdrop.jpg","assets/tv-severance-2022-poster.jpg","assets/tv-sex-and-the-city-1998-backdrop.jpg","assets/tv-sex-and-the-city-1998-poster.jpg","assets/tv-the-100-2014-backdrop.jpg","assets/tv-the-100-2014-poster.jpg","assets/tv-the-abbott-and-costello-show-1952-backdrop.jpg","assets/tv-the-abbott-and-costello-show-1952-poster.jpg","assets/tv-the-afterparty-2022-backdrop.jpg","assets/tv-the-afterparty-2022-poster.jpg","assets/tv-the-bear-2022-backdrop.jpg","assets/tv-the-bear-2022-poster.jpg","assets/tv-the-beast-in-me-2025-backdrop.jpg","assets/tv-the-beast-in-me-2025-poster.jpg","assets/tv-the-bold-type-2017-backdrop.jpg","assets/tv-the-bold-type-2017-poster.jpg","assets/tv-the-boys-2019-backdrop.jpg","assets/tv-the-boys-2019-poster.jpg","assets/tv-the-capture-2019-backdrop.jpg","assets/tv-the-capture-2019-poster.jpg","assets/tv-the-durrells-2016-backdrop.jpg","assets/tv-the-durrells-2016-poster.jpg","assets/tv-the-final-problem-2026-backdrop.jpg","assets/tv-the-final-problem-2026-poster.jpg","assets/tv-the-legend-of-korra-2012-backdrop.jpg","assets/tv-the-legend-of-korra-2012-poster.jpg","assets/tv-the-lord-of-the-rings-the-rings-of-power-2022-backdrop.jpg","assets/tv-the-lord-of-the-rings-the-rings-of-power-2022-poster.jpg","assets/tv-the-night-manager-2016-backdrop.jpg","assets/tv-the-night-manager-2016-poster.jpg","assets/tv-the-tatami-galaxy-2010-backdrop.jpg","assets/tv-the-tatami-galaxy-2010-poster.jpg","assets/tv-the-white-lotus-2021-backdrop.jpg","assets/tv-the-white-lotus-2021-poster.jpg","assets/tv-the-witcher-2019-backdrop.jpg","assets/tv-the-witcher-2019-poster.jpg","assets/tv-upload-2020-backdrop.jpg","assets/tv-upload-2020-poster.jpg","assets/tv-widow-s-bay-2026-backdrop.jpg","assets/tv-widow-s-bay-2026-poster.jpg","assets/tv-yellowjackets-2021-backdrop.jpg","assets/tv-yellowjackets-2021-poster.jpg"]} diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/26R1LBiSOkkP08saSsz6LmVTY16.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/26R1LBiSOkkP08saSsz6LmVTY16.jpg new file mode 100644 index 00000000..12a79fbe Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/26R1LBiSOkkP08saSsz6LmVTY16.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/2tFblvjBRUYwcVT1V1i79Ppd6wG.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/2tFblvjBRUYwcVT1V1i79Ppd6wG.jpg new file mode 100644 index 00000000..51c11420 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/2tFblvjBRUYwcVT1V1i79Ppd6wG.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/320qW5yEbxpmyxQ3evmClJbtKag.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/320qW5yEbxpmyxQ3evmClJbtKag.jpg new file mode 100644 index 00000000..0c5b151f Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/320qW5yEbxpmyxQ3evmClJbtKag.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/4F8XpjyQCvtuu21WFm5d8RF5Rl.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/4F8XpjyQCvtuu21WFm5d8RF5Rl.jpg new file mode 100644 index 00000000..a639becf Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/4F8XpjyQCvtuu21WFm5d8RF5Rl.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/4eOoW1PNBZfxRW0g8RmYH8bL6mq.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/4eOoW1PNBZfxRW0g8RmYH8bL6mq.jpg new file mode 100644 index 00000000..f0a4e83a Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/4eOoW1PNBZfxRW0g8RmYH8bL6mq.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/4gyHyg6FJ1oFczOm5pmMkdEEo2J.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/4gyHyg6FJ1oFczOm5pmMkdEEo2J.jpg new file mode 100644 index 00000000..b28de566 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/4gyHyg6FJ1oFczOm5pmMkdEEo2J.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/5L0kzTVITmOQdQ94NhicKM8ecCX.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/5L0kzTVITmOQdQ94NhicKM8ecCX.jpg new file mode 100644 index 00000000..35a785df Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/5L0kzTVITmOQdQ94NhicKM8ecCX.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/5VbadQsYCKdiJysP01LJFPmYB8A.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/5VbadQsYCKdiJysP01LJFPmYB8A.jpg new file mode 100644 index 00000000..41618a2e Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/5VbadQsYCKdiJysP01LJFPmYB8A.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/5eIRHUbNOH7ibXa0IfUfFvj5I5L.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/5eIRHUbNOH7ibXa0IfUfFvj5I5L.jpg new file mode 100644 index 00000000..5c6e94de Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/5eIRHUbNOH7ibXa0IfUfFvj5I5L.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/5hn7WeXi6wguwxTPTSmcmzHAs9.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/5hn7WeXi6wguwxTPTSmcmzHAs9.jpg new file mode 100644 index 00000000..1b59f62f Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/5hn7WeXi6wguwxTPTSmcmzHAs9.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/6hmUs5Q1EETapn32yKNt3c3i1sn.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/6hmUs5Q1EETapn32yKNt3c3i1sn.jpg new file mode 100644 index 00000000..21dc4e89 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/6hmUs5Q1EETapn32yKNt3c3i1sn.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/7LVYeFTgUpjYDrxnU7Wm5ZQUX9t.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/7LVYeFTgUpjYDrxnU7Wm5ZQUX9t.jpg new file mode 100644 index 00000000..dde817a1 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/7LVYeFTgUpjYDrxnU7Wm5ZQUX9t.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/7MHdNxS1gRnx0ZQGPrfS5eRjMe3.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/7MHdNxS1gRnx0ZQGPrfS5eRjMe3.jpg new file mode 100644 index 00000000..5094cb73 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/7MHdNxS1gRnx0ZQGPrfS5eRjMe3.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/7Y96dAfg0HcFrcLjlD5eD9N0uj4.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/7Y96dAfg0HcFrcLjlD5eD9N0uj4.jpg new file mode 100644 index 00000000..1f88cd10 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/7Y96dAfg0HcFrcLjlD5eD9N0uj4.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/8v3lDa0QCJlDtOx9flqlMNIA3uf.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/8v3lDa0QCJlDtOx9flqlMNIA3uf.jpg new file mode 100644 index 00000000..5d5930b7 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/8v3lDa0QCJlDtOx9flqlMNIA3uf.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/9pxaoasotR1pdCXYSfN1pkm0geO.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/9pxaoasotR1pdCXYSfN1pkm0geO.jpg new file mode 100644 index 00000000..6a483975 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/9pxaoasotR1pdCXYSfN1pkm0geO.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/aHQk6XxqyJinfvrVRADEIg31nOk.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/aHQk6XxqyJinfvrVRADEIg31nOk.jpg new file mode 100644 index 00000000..a1df3481 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/aHQk6XxqyJinfvrVRADEIg31nOk.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/aW6vCxkUZtwb6iH2Wf88Uq0XNVv.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/aW6vCxkUZtwb6iH2Wf88Uq0XNVv.jpg new file mode 100644 index 00000000..50197dbe Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/aW6vCxkUZtwb6iH2Wf88Uq0XNVv.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/bLgmpSFgEiSFNshqmdl3EIZkRZm.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/bLgmpSFgEiSFNshqmdl3EIZkRZm.jpg new file mode 100644 index 00000000..5aa08a58 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/bLgmpSFgEiSFNshqmdl3EIZkRZm.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/biov5jENp2XYfehkcdnRvi796Wi.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/biov5jENp2XYfehkcdnRvi796Wi.jpg new file mode 100644 index 00000000..07813572 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/biov5jENp2XYfehkcdnRvi796Wi.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/d81K0RH8UX7tZj49tZaQhZ9ewH.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/d81K0RH8UX7tZj49tZaQhZ9ewH.jpg new file mode 100644 index 00000000..77d5fe66 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/d81K0RH8UX7tZj49tZaQhZ9ewH.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/fD8GuLHOOSSAG98VjwN3NhAmqAJ.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/fD8GuLHOOSSAG98VjwN3NhAmqAJ.jpg new file mode 100644 index 00000000..3c66e9a4 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/fD8GuLHOOSSAG98VjwN3NhAmqAJ.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/fbWWkhe7GVSlhBljY89rJd01OnA.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/fbWWkhe7GVSlhBljY89rJd01OnA.jpg new file mode 100644 index 00000000..15a25098 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/fbWWkhe7GVSlhBljY89rJd01OnA.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/fdFVatb9pt5dfT9tDK8tikKWafS.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/fdFVatb9pt5dfT9tDK8tikKWafS.jpg new file mode 100644 index 00000000..60531535 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/fdFVatb9pt5dfT9tDK8tikKWafS.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/fjJc03z1cOlMxLZbC1qihsq3C37.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/fjJc03z1cOlMxLZbC1qihsq3C37.jpg new file mode 100644 index 00000000..989ce70d Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/fjJc03z1cOlMxLZbC1qihsq3C37.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/hOntuFYAMwn9QaXT0AwLCPU79ce.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/hOntuFYAMwn9QaXT0AwLCPU79ce.jpg new file mode 100644 index 00000000..783d7043 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/hOntuFYAMwn9QaXT0AwLCPU79ce.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/hrTwOPWek7nkPJgFhh6inFu7vSS.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/hrTwOPWek7nkPJgFhh6inFu7vSS.jpg new file mode 100644 index 00000000..5f9dc239 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/hrTwOPWek7nkPJgFhh6inFu7vSS.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/hzu7OqTmNCT1xdCdmwBSf2yJvaO.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/hzu7OqTmNCT1xdCdmwBSf2yJvaO.jpg new file mode 100644 index 00000000..2b3d2015 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/hzu7OqTmNCT1xdCdmwBSf2yJvaO.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/iQLEawIP2593yrGy22GzLSpnfgl.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/iQLEawIP2593yrGy22GzLSpnfgl.jpg new file mode 100644 index 00000000..5965e06d Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/iQLEawIP2593yrGy22GzLSpnfgl.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/j0GXzLelO1dOzI7d1WVIwQXhLz8.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/j0GXzLelO1dOzI7d1WVIwQXhLz8.jpg new file mode 100644 index 00000000..0921d96c Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/j0GXzLelO1dOzI7d1WVIwQXhLz8.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/jUuUbPuMGonFT5E2pcs4alfqaCN.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/jUuUbPuMGonFT5E2pcs4alfqaCN.jpg new file mode 100644 index 00000000..7e03f82b Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/jUuUbPuMGonFT5E2pcs4alfqaCN.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/lF06PTNYrlXeJ3DYApvOcPXJr87.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/lF06PTNYrlXeJ3DYApvOcPXJr87.jpg new file mode 100644 index 00000000..01f41d25 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/lF06PTNYrlXeJ3DYApvOcPXJr87.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/lUhVV9u5VGMCNdCAVhGzg8GFSdo.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/lUhVV9u5VGMCNdCAVhGzg8GFSdo.jpg new file mode 100644 index 00000000..8baff3f2 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/lUhVV9u5VGMCNdCAVhGzg8GFSdo.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/lawJUdbLb1YW0niaYjiVGR9IBG8.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/lawJUdbLb1YW0niaYjiVGR9IBG8.jpg new file mode 100644 index 00000000..11d18b7a Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/lawJUdbLb1YW0niaYjiVGR9IBG8.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/lfbyJWNWGbiYfU0Yr1tjn6Trd2V.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/lfbyJWNWGbiYfU0Yr1tjn6Trd2V.jpg new file mode 100644 index 00000000..64a37106 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/lfbyJWNWGbiYfU0Yr1tjn6Trd2V.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/lpEs9yDsMQlsbm0RVsvDIleCXcI.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/lpEs9yDsMQlsbm0RVsvDIleCXcI.jpg new file mode 100644 index 00000000..5ff2d6a1 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/lpEs9yDsMQlsbm0RVsvDIleCXcI.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/mF5YJxApTYKBVFJDrEC9IrJ5ooV.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/mF5YJxApTYKBVFJDrEC9IrJ5ooV.jpg new file mode 100644 index 00000000..2a4445ce Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/mF5YJxApTYKBVFJDrEC9IrJ5ooV.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/mW7xmtGV4y79kQGn0zkKVGDMAmw.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/mW7xmtGV4y79kQGn0zkKVGDMAmw.jpg new file mode 100644 index 00000000..21dd5ffe Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/mW7xmtGV4y79kQGn0zkKVGDMAmw.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/mk5vpYLmER7asqOhEwVKXD3P3YE.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/mk5vpYLmER7asqOhEwVKXD3P3YE.jpg new file mode 100644 index 00000000..b4189cd0 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/mk5vpYLmER7asqOhEwVKXD3P3YE.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/mnKYU7HIsuRkx3YjdRO5FLXCdX5.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/mnKYU7HIsuRkx3YjdRO5FLXCdX5.jpg new file mode 100644 index 00000000..40aee939 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/mnKYU7HIsuRkx3YjdRO5FLXCdX5.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/msqe5A1q5YUUND0RhzB9dw1AEAO.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/msqe5A1q5YUUND0RhzB9dw1AEAO.jpg new file mode 100644 index 00000000..afc0e401 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/msqe5A1q5YUUND0RhzB9dw1AEAO.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/nAxS5l9vb1C8ltCp9yAa0f6lazu.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/nAxS5l9vb1C8ltCp9yAa0f6lazu.jpg new file mode 100644 index 00000000..2e179e76 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/nAxS5l9vb1C8ltCp9yAa0f6lazu.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/nmgOd3X2Xn3jIp9OLCRJzLExRWN.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/nmgOd3X2Xn3jIp9OLCRJzLExRWN.jpg new file mode 100644 index 00000000..5a261d60 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/nmgOd3X2Xn3jIp9OLCRJzLExRWN.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/o7splcOIVAdbHnwohJOUAvXWVlk.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/o7splcOIVAdbHnwohJOUAvXWVlk.jpg new file mode 100644 index 00000000..4cdadf08 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/o7splcOIVAdbHnwohJOUAvXWVlk.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/oMHMLhoV3ry8aOfdvs1kxyowhNq.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/oMHMLhoV3ry8aOfdvs1kxyowhNq.jpg new file mode 100644 index 00000000..99b5bcd6 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/oMHMLhoV3ry8aOfdvs1kxyowhNq.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/omWXGbeRR32MWuYhpnLOSqJ6xkO.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/omWXGbeRR32MWuYhpnLOSqJ6xkO.jpg new file mode 100644 index 00000000..1ee336bd Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/omWXGbeRR32MWuYhpnLOSqJ6xkO.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/pVwR9hsEiHzVTo9giCjR3vIfa8W.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/pVwR9hsEiHzVTo9giCjR3vIfa8W.jpg new file mode 100644 index 00000000..4dbe126b Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/pVwR9hsEiHzVTo9giCjR3vIfa8W.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/phEIvq0Ay2KjI5ewmVvpQ1a29GJ.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/phEIvq0Ay2KjI5ewmVvpQ1a29GJ.jpg new file mode 100644 index 00000000..b673a5b2 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/phEIvq0Ay2KjI5ewmVvpQ1a29GJ.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/qP5vQMIbLNvSsSFkEMLZRVt4ZW5.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/qP5vQMIbLNvSsSFkEMLZRVt4ZW5.jpg new file mode 100644 index 00000000..ed34c316 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/qP5vQMIbLNvSsSFkEMLZRVt4ZW5.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/qiWu2gphSg64igYl3Nx0hEIOQF3.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/qiWu2gphSg64igYl3Nx0hEIOQF3.jpg new file mode 100644 index 00000000..e5fd3f84 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/qiWu2gphSg64igYl3Nx0hEIOQF3.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/qwbjcyDN37OHiln4a6P4LP31o7F.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/qwbjcyDN37OHiln4a6P4LP31o7F.jpg new file mode 100644 index 00000000..4132aac4 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/qwbjcyDN37OHiln4a6P4LP31o7F.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/r6s7dkYZUJpd00C7p9itT6Gp8XB.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/r6s7dkYZUJpd00C7p9itT6Gp8XB.jpg new file mode 100644 index 00000000..8ae18ac0 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/r6s7dkYZUJpd00C7p9itT6Gp8XB.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/rDTxblyw0AwU5oSeksgP7GwMyrF.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/rDTxblyw0AwU5oSeksgP7GwMyrF.jpg new file mode 100644 index 00000000..8d6c9a83 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/rDTxblyw0AwU5oSeksgP7GwMyrF.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/rIqcwewXdkrDTMTwX56QPa7MNTC.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/rIqcwewXdkrDTMTwX56QPa7MNTC.jpg new file mode 100644 index 00000000..0b985c84 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/rIqcwewXdkrDTMTwX56QPa7MNTC.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/rLzduQpYJnZJKkXv3jRc7MDHwoI.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/rLzduQpYJnZJKkXv3jRc7MDHwoI.jpg new file mode 100644 index 00000000..7377c541 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/rLzduQpYJnZJKkXv3jRc7MDHwoI.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/rbxBK2m6fEq0oHeMoBUMVYkJEdJ.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/rbxBK2m6fEq0oHeMoBUMVYkJEdJ.jpg new file mode 100644 index 00000000..f23bdc49 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/rbxBK2m6fEq0oHeMoBUMVYkJEdJ.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/sG6CWLdENCtzukNFkFYyPxqyRmS.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/sG6CWLdENCtzukNFkFYyPxqyRmS.jpg new file mode 100644 index 00000000..755a5276 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/sG6CWLdENCtzukNFkFYyPxqyRmS.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/sh4ANkKoIHgmHtkKQbJvF8y0Fjq.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/sh4ANkKoIHgmHtkKQbJvF8y0Fjq.jpg new file mode 100644 index 00000000..c1a9d397 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/sh4ANkKoIHgmHtkKQbJvF8y0Fjq.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/tqFHQiJUycuob3ytvilaAWDlbQ8.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/tqFHQiJUycuob3ytvilaAWDlbQ8.jpg new file mode 100644 index 00000000..5b2de159 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/tqFHQiJUycuob3ytvilaAWDlbQ8.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/uL8yfcm0dCFYFQt052kczVQVvac.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/uL8yfcm0dCFYFQt052kczVQVvac.jpg new file mode 100644 index 00000000..4f1e2f21 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/uL8yfcm0dCFYFQt052kczVQVvac.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/ub2IuMWFNQGYghHTPq0lpmn2Ue0.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/ub2IuMWFNQGYghHTPq0lpmn2Ue0.jpg new file mode 100644 index 00000000..725372ad Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/ub2IuMWFNQGYghHTPq0lpmn2Ue0.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/ukDNHgvEgdU95eaw6pngiAPucv4.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/ukDNHgvEgdU95eaw6pngiAPucv4.jpg new file mode 100644 index 00000000..7ed17793 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/ukDNHgvEgdU95eaw6pngiAPucv4.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/v4sRxLpRpHEd9vbk43wm9VL0v0K.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/v4sRxLpRpHEd9vbk43wm9VL0v0K.jpg new file mode 100644 index 00000000..2118c505 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/v4sRxLpRpHEd9vbk43wm9VL0v0K.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/wWcby4ARYqr8d92ZdjyQcfaiJBW.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/wWcby4ARYqr8d92ZdjyQcfaiJBW.jpg new file mode 100644 index 00000000..3a609d1e Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/wWcby4ARYqr8d92ZdjyQcfaiJBW.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/waayy0jpNbxLDQ8JO1uRDng8SLF.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/waayy0jpNbxLDQ8JO1uRDng8SLF.jpg new file mode 100644 index 00000000..b650362b Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/waayy0jpNbxLDQ8JO1uRDng8SLF.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/x0lmqgkmphvOCSTHk2oxsaxA9Ra.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/x0lmqgkmphvOCSTHk2oxsaxA9Ra.jpg new file mode 100644 index 00000000..3d3f33ee Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/x0lmqgkmphvOCSTHk2oxsaxA9Ra.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/xKBAaPIa1c7tzZD3Y0MhBLv4hPE.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/xKBAaPIa1c7tzZD3Y0MhBLv4hPE.jpg new file mode 100644 index 00000000..fba488ba Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/xKBAaPIa1c7tzZD3Y0MhBLv4hPE.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/xV9UrP8kZdxOiTI2efDFhp3t4iA.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/xV9UrP8kZdxOiTI2efDFhp3t4iA.jpg new file mode 100644 index 00000000..eb015896 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/xV9UrP8kZdxOiTI2efDFhp3t4iA.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/xm2pYFBggiXSkFBV2I612i3fDd3.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/xm2pYFBggiXSkFBV2I612i3fDd3.jpg new file mode 100644 index 00000000..bc482f04 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/xm2pYFBggiXSkFBV2I612i3fDd3.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/xx3As5SWcE8vYOKZgtjDjqmT3jc.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/xx3As5SWcE8vYOKZgtjDjqmT3jc.jpg new file mode 100644 index 00000000..dd70f23a Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/xx3As5SWcE8vYOKZgtjDjqmT3jc.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/yU0OXeZ0K1ppe1o9SpHiAMHy1rc.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/yU0OXeZ0K1ppe1o9SpHiAMHy1rc.jpg new file mode 100644 index 00000000..dd0796e7 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/yU0OXeZ0K1ppe1o9SpHiAMHy1rc.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/yWZILsr2mBQBCG1LOcCYYshIbts.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/yWZILsr2mBQBCG1LOcCYYshIbts.jpg new file mode 100644 index 00000000..04d476bb Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/yWZILsr2mBQBCG1LOcCYYshIbts.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/yxGsAKnrJZs2g6q4unNgkfm7NAA.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/yxGsAKnrJZs2g6q4unNgkfm7NAA.jpg new file mode 100644 index 00000000..6e7a492b Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/yxGsAKnrJZs2g6q4unNgkfm7NAA.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/cast/ztxDIZvuPreUixO6ZPxwkCg2UlO.jpg b/app/src/debug/assets/wolfskin-titles/assets/cast/ztxDIZvuPreUixO6ZPxwkCg2UlO.jpg new file mode 100644 index 00000000..6883cc09 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/cast/ztxDIZvuPreUixO6ZPxwkCg2UlO.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/episode-all-hands-on-deck-class-1-a-2021-s5e1-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/episode-all-hands-on-deck-class-1-a-2021-s5e1-backdrop.jpg new file mode 100644 index 00000000..f5b2f94c Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/episode-all-hands-on-deck-class-1-a-2021-s5e1-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/episode-all-hands-on-deck-class-1-a-2021-s5e1-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/episode-all-hands-on-deck-class-1-a-2021-s5e1-poster.jpg new file mode 100644 index 00000000..cf571b93 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/episode-all-hands-on-deck-class-1-a-2021-s5e1-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/episode-announcement-2022-s1e7-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/episode-announcement-2022-s1e7-backdrop.jpg new file mode 100644 index 00000000..a874a0c0 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/episode-announcement-2022-s1e7-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/episode-announcement-2022-s1e7-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/episode-announcement-2022-s1e7-poster.jpg new file mode 100644 index 00000000..df5dc498 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/episode-announcement-2022-s1e7-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/episode-episode-1-2025-s1e1-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/episode-episode-1-2025-s1e1-backdrop.jpg new file mode 100644 index 00000000..f2519b04 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/episode-episode-1-2025-s1e1-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/episode-episode-1-2025-s1e1-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/episode-episode-1-2025-s1e1-poster.jpg new file mode 100644 index 00000000..77febd79 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/episode-episode-1-2025-s1e1-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/episode-episode-2-2016-s1e2-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/episode-episode-2-2016-s1e2-backdrop.jpg new file mode 100644 index 00000000..3f8bdeec Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/episode-episode-2-2016-s1e2-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/episode-episode-2-2016-s1e2-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/episode-episode-2-2016-s1e2-poster.jpg new file mode 100644 index 00000000..d29448bb Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/episode-episode-2-2016-s1e2-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/episode-erickerhead-2026-s9e6-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/episode-erickerhead-2026-s9e6-backdrop.jpg new file mode 100644 index 00000000..1c4c0ffc Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/episode-erickerhead-2026-s9e6-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/episode-erickerhead-2026-s9e6-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/episode-erickerhead-2026-s9e6-poster.jpg new file mode 100644 index 00000000..b95c4890 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/episode-erickerhead-2026-s9e6-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/episode-girls-interrupted-2007-s1e7-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/episode-girls-interrupted-2007-s1e7-backdrop.jpg new file mode 100644 index 00000000..ffff979b Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/episode-girls-interrupted-2007-s1e7-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/episode-girls-interrupted-2007-s1e7-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/episode-girls-interrupted-2007-s1e7-poster.jpg new file mode 100644 index 00000000..38428e76 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/episode-girls-interrupted-2007-s1e7-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/episode-i-heart-ny-2002-s4e18-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/episode-i-heart-ny-2002-s4e18-backdrop.jpg new file mode 100644 index 00000000..57beacc1 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/episode-i-heart-ny-2002-s4e18-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/episode-i-heart-ny-2002-s4e18-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/episode-i-heart-ny-2002-s4e18-poster.jpg new file mode 100644 index 00000000..e546cc6d Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/episode-i-heart-ny-2002-s4e18-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/episode-new-day-2021-s1e2-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/episode-new-day-2021-s1e2-backdrop.jpg new file mode 100644 index 00000000..1f747323 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/episode-new-day-2021-s1e2-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/episode-new-day-2021-s1e2-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/episode-new-day-2021-s1e2-poster.jpg new file mode 100644 index 00000000..2f23d1fa Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/episode-new-day-2021-s1e2-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/episode-no-honeymoon-2020-s1e8-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/episode-no-honeymoon-2020-s1e8-backdrop.jpg new file mode 100644 index 00000000..9d95ba77 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/episode-no-honeymoon-2020-s1e8-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/episode-no-honeymoon-2020-s1e8-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/episode-no-honeymoon-2020-s1e8-poster.jpg new file mode 100644 index 00000000..49c61208 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/episode-no-honeymoon-2020-s1e8-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/episode-notapusy-2005-s3e4-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/episode-notapusy-2005-s3e4-backdrop.jpg new file mode 100644 index 00000000..ecb7e8cd Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/episode-notapusy-2005-s3e4-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/episode-notapusy-2005-s3e4-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/episode-notapusy-2005-s3e4-poster.jpg new file mode 100644 index 00000000..02b0dd43 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/episode-notapusy-2005-s3e4-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/episode-one-of-us-2024-s1e7-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/episode-one-of-us-2024-s1e7-backdrop.jpg new file mode 100644 index 00000000..66bb4d00 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/episode-one-of-us-2024-s1e7-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/episode-one-of-us-2024-s1e7-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/episode-one-of-us-2024-s1e7-poster.jpg new file mode 100644 index 00000000..00a07ca7 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/episode-one-of-us-2024-s1e7-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/episode-remembrance-day-2026-s2e1-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/episode-remembrance-day-2026-s2e1-backdrop.jpg new file mode 100644 index 00000000..23a242da Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/episode-remembrance-day-2026-s2e1-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/episode-remembrance-day-2026-s2e1-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/episode-remembrance-day-2026-s2e1-poster.jpg new file mode 100644 index 00000000..930943b0 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/episode-remembrance-day-2026-s2e1-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/episode-sex-and-the-country-2001-s4e9-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/episode-sex-and-the-country-2001-s4e9-backdrop.jpg new file mode 100644 index 00000000..57beacc1 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/episode-sex-and-the-country-2001-s4e9-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/episode-sex-and-the-country-2001-s4e9-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/episode-sex-and-the-country-2001-s4e9-poster.jpg new file mode 100644 index 00000000..e546cc6d Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/episode-sex-and-the-country-2001-s4e9-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/episode-south-american-biker-gangs-2026-s29e1-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/episode-south-american-biker-gangs-2026-s29e1-backdrop.jpg new file mode 100644 index 00000000..cd0aec39 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/episode-south-american-biker-gangs-2026-s29e1-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/episode-south-american-biker-gangs-2026-s29e1-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/episode-south-american-biker-gangs-2026-s29e1-poster.jpg new file mode 100644 index 00000000..d8568d54 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/episode-south-american-biker-gangs-2026-s29e1-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/episode-the-breakup-part-2-2001-s1e17-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/episode-the-breakup-part-2-2001-s1e17-backdrop.jpg new file mode 100644 index 00000000..b42ba953 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/episode-the-breakup-part-2-2001-s1e17-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/episode-the-breakup-part-2-2001-s1e17-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/episode-the-breakup-part-2-2001-s1e17-poster.jpg new file mode 100644 index 00000000..23b668cb Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/episode-the-breakup-part-2-2001-s1e17-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/episode-the-man-who-would-be-vogue-2018-s2e1-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/episode-the-man-who-would-be-vogue-2018-s2e1-backdrop.jpg new file mode 100644 index 00000000..84944d39 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/episode-the-man-who-would-be-vogue-2018-s2e1-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/episode-the-man-who-would-be-vogue-2018-s2e1-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/episode-the-man-who-would-be-vogue-2018-s2e1-poster.jpg new file mode 100644 index 00000000..4086bf17 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/episode-the-man-who-would-be-vogue-2018-s2e1-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/episode-the-uncomfortability-2010-s1e2-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/episode-the-uncomfortability-2010-s1e2-backdrop.jpg new file mode 100644 index 00000000..bc22e11a Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/episode-the-uncomfortability-2010-s1e2-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/episode-the-uncomfortability-2010-s1e2-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/episode-the-uncomfortability-2010-s1e2-poster.jpg new file mode 100644 index 00000000..ae305043 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/episode-the-uncomfortability-2010-s1e2-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/episode-three-monsters-1992-s1e6-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/episode-three-monsters-1992-s1e6-backdrop.jpg new file mode 100644 index 00000000..ba65ca2d Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/episode-three-monsters-1992-s1e6-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/episode-three-monsters-1992-s1e6-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/episode-three-monsters-1992-s1e6-poster.jpg new file mode 100644 index 00000000..f5843766 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/episode-three-monsters-1992-s1e6-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/episode-tomorrow-2024-s3e1-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/episode-tomorrow-2024-s3e1-backdrop.jpg new file mode 100644 index 00000000..9c9cca57 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/episode-tomorrow-2024-s3e1-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/episode-tomorrow-2024-s3e1-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/episode-tomorrow-2024-s3e1-poster.jpg new file mode 100644 index 00000000..bbf0ab28 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/episode-tomorrow-2024-s3e1-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/episode-what-more-do-i-need-2008-s5e7-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/episode-what-more-do-i-need-2008-s5e7-backdrop.jpg new file mode 100644 index 00000000..40ec3001 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/episode-what-more-do-i-need-2008-s5e7-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/episode-what-more-do-i-need-2008-s5e7-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/episode-what-more-do-i-need-2008-s5e7-poster.jpg new file mode 100644 index 00000000..13f0f7b3 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/episode-what-more-do-i-need-2008-s5e7-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-101-dalmatians-ii-patch-s-london-adventure-2003-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-101-dalmatians-ii-patch-s-london-adventure-2003-backdrop.jpg new file mode 100644 index 00000000..f0d6f752 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-101-dalmatians-ii-patch-s-london-adventure-2003-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-101-dalmatians-ii-patch-s-london-adventure-2003-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-101-dalmatians-ii-patch-s-london-adventure-2003-poster.jpg new file mode 100644 index 00000000..b9b72894 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-101-dalmatians-ii-patch-s-london-adventure-2003-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-a-bronx-tale-1993-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-a-bronx-tale-1993-backdrop.jpg new file mode 100644 index 00000000..15c11ff7 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-a-bronx-tale-1993-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-a-bronx-tale-1993-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-a-bronx-tale-1993-poster.jpg new file mode 100644 index 00000000..f7444271 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-a-bronx-tale-1993-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-a-silent-voice-the-movie-2016-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-a-silent-voice-the-movie-2016-backdrop.jpg new file mode 100644 index 00000000..b386b136 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-a-silent-voice-the-movie-2016-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-a-silent-voice-the-movie-2016-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-a-silent-voice-the-movie-2016-poster.jpg new file mode 100644 index 00000000..580b22f4 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-a-silent-voice-the-movie-2016-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-absolution-2024-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-absolution-2024-backdrop.jpg new file mode 100644 index 00000000..eb28037c Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-absolution-2024-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-absolution-2024-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-absolution-2024-poster.jpg new file mode 100644 index 00000000..3ce49112 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-absolution-2024-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-across-the-hall-2009-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-across-the-hall-2009-backdrop.jpg new file mode 100644 index 00000000..6c1ee8ac Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-across-the-hall-2009-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-across-the-hall-2009-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-across-the-hall-2009-poster.jpg new file mode 100644 index 00000000..52362b4e Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-across-the-hall-2009-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-addicted-2014-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-addicted-2014-backdrop.jpg new file mode 100644 index 00000000..5c016976 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-addicted-2014-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-addicted-2014-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-addicted-2014-poster.jpg new file mode 100644 index 00000000..e9a03c14 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-addicted-2014-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-adulterers-2016-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-adulterers-2016-backdrop.jpg new file mode 100644 index 00000000..331391ed Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-adulterers-2016-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-adulterers-2016-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-adulterers-2016-poster.jpg new file mode 100644 index 00000000..8b65745b Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-adulterers-2016-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-all-the-money-in-the-world-2017-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-all-the-money-in-the-world-2017-backdrop.jpg new file mode 100644 index 00000000..ac4b828a Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-all-the-money-in-the-world-2017-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-all-the-money-in-the-world-2017-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-all-the-money-in-the-world-2017-poster.jpg new file mode 100644 index 00000000..8beb2f7f Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-all-the-money-in-the-world-2017-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-alone-with-her-2006-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-alone-with-her-2006-backdrop.jpg new file mode 100644 index 00000000..ddf8f1dc Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-alone-with-her-2006-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-alone-with-her-2006-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-alone-with-her-2006-poster.jpg new file mode 100644 index 00000000..7ce6fa96 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-alone-with-her-2006-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-american-gangster-2007-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-american-gangster-2007-backdrop.jpg new file mode 100644 index 00000000..cb5c5de7 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-american-gangster-2007-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-american-gangster-2007-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-american-gangster-2007-poster.jpg new file mode 100644 index 00000000..0f41d299 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-american-gangster-2007-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-annie-hall-1977-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-annie-hall-1977-backdrop.jpg new file mode 100644 index 00000000..16d0b27d Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-annie-hall-1977-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-annie-hall-1977-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-annie-hall-1977-poster.jpg new file mode 100644 index 00000000..9023a691 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-annie-hall-1977-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-ant-man-and-the-wasp-quantumania-2023-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-ant-man-and-the-wasp-quantumania-2023-backdrop.jpg new file mode 100644 index 00000000..2a99846d Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-ant-man-and-the-wasp-quantumania-2023-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-ant-man-and-the-wasp-quantumania-2023-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-ant-man-and-the-wasp-quantumania-2023-poster.jpg new file mode 100644 index 00000000..030addf0 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-ant-man-and-the-wasp-quantumania-2023-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-appleseed-alpha-2014-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-appleseed-alpha-2014-backdrop.jpg new file mode 100644 index 00000000..82579b86 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-appleseed-alpha-2014-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-appleseed-alpha-2014-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-appleseed-alpha-2014-poster.jpg new file mode 100644 index 00000000..62bd0afa Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-appleseed-alpha-2014-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-aquaman-and-the-lost-kingdom-2023-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-aquaman-and-the-lost-kingdom-2023-backdrop.jpg new file mode 100644 index 00000000..6693cb6d Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-aquaman-and-the-lost-kingdom-2023-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-aquaman-and-the-lost-kingdom-2023-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-aquaman-and-the-lost-kingdom-2023-poster.jpg new file mode 100644 index 00000000..4550bdaa Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-aquaman-and-the-lost-kingdom-2023-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-arctic-dogs-2019-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-arctic-dogs-2019-backdrop.jpg new file mode 100644 index 00000000..1794c99d Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-arctic-dogs-2019-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-arctic-dogs-2019-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-arctic-dogs-2019-poster.jpg new file mode 100644 index 00000000..07552443 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-arctic-dogs-2019-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-arrival-2016-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-arrival-2016-backdrop.jpg new file mode 100644 index 00000000..605724e7 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-arrival-2016-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-arrival-2016-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-arrival-2016-poster.jpg new file mode 100644 index 00000000..fe224a15 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-arrival-2016-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-avatar-aang-the-last-airbender-2026-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-avatar-aang-the-last-airbender-2026-backdrop.jpg new file mode 100644 index 00000000..d3b12fe0 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-avatar-aang-the-last-airbender-2026-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-avatar-aang-the-last-airbender-2026-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-avatar-aang-the-last-airbender-2026-poster.jpg new file mode 100644 index 00000000..f57f1052 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-avatar-aang-the-last-airbender-2026-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-avengers-age-of-ultron-2015-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-avengers-age-of-ultron-2015-backdrop.jpg new file mode 100644 index 00000000..f739d620 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-avengers-age-of-ultron-2015-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-avengers-age-of-ultron-2015-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-avengers-age-of-ultron-2015-poster.jpg new file mode 100644 index 00000000..300840ff Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-avengers-age-of-ultron-2015-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-avengers-confidential-black-widow-punisher-2014-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-avengers-confidential-black-widow-punisher-2014-backdrop.jpg new file mode 100644 index 00000000..8163931a Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-avengers-confidential-black-widow-punisher-2014-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-avengers-confidential-black-widow-punisher-2014-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-avengers-confidential-black-widow-punisher-2014-poster.jpg new file mode 100644 index 00000000..b096fff2 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-avengers-confidential-black-widow-punisher-2014-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-avengers-infinity-war-2018-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-avengers-infinity-war-2018-backdrop.jpg new file mode 100644 index 00000000..90dc4672 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-avengers-infinity-war-2018-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-avengers-infinity-war-2018-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-avengers-infinity-war-2018-poster.jpg new file mode 100644 index 00000000..57df9298 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-avengers-infinity-war-2018-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-awake-2007-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-awake-2007-backdrop.jpg new file mode 100644 index 00000000..6ddd7f59 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-awake-2007-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-awake-2007-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-awake-2007-poster.jpg new file mode 100644 index 00000000..32595897 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-awake-2007-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-batman-ninja-2018-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-batman-ninja-2018-backdrop.jpg new file mode 100644 index 00000000..9b538d9f Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-batman-ninja-2018-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-batman-ninja-2018-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-batman-ninja-2018-poster.jpg new file mode 100644 index 00000000..7f59127b Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-batman-ninja-2018-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-batman-the-dark-knight-returns-part-1-2012-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-batman-the-dark-knight-returns-part-1-2012-backdrop.jpg new file mode 100644 index 00000000..9d385801 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-batman-the-dark-knight-returns-part-1-2012-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-batman-the-dark-knight-returns-part-1-2012-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-batman-the-dark-knight-returns-part-1-2012-poster.jpg new file mode 100644 index 00000000..ce5623fe Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-batman-the-dark-knight-returns-part-1-2012-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-batman-v-superman-dawn-of-justice-2016-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-batman-v-superman-dawn-of-justice-2016-backdrop.jpg new file mode 100644 index 00000000..b4fa63b9 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-batman-v-superman-dawn-of-justice-2016-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-batman-v-superman-dawn-of-justice-2016-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-batman-v-superman-dawn-of-justice-2016-poster.jpg new file mode 100644 index 00000000..f8115170 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-batman-v-superman-dawn-of-justice-2016-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-black-adam-2022-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-black-adam-2022-backdrop.jpg new file mode 100644 index 00000000..3232fb22 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-black-adam-2022-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-black-adam-2022-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-black-adam-2022-poster.jpg new file mode 100644 index 00000000..dde008b5 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-black-adam-2022-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-black-bear-2020-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-black-bear-2020-backdrop.jpg new file mode 100644 index 00000000..4b0b262f Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-black-bear-2020-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-black-bear-2020-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-black-bear-2020-poster.jpg new file mode 100644 index 00000000..61c8860f Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-black-bear-2020-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-black-panther-2018-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-black-panther-2018-backdrop.jpg new file mode 100644 index 00000000..f0b8de8a Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-black-panther-2018-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-black-panther-2018-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-black-panther-2018-poster.jpg new file mode 100644 index 00000000..6fdaa3d2 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-black-panther-2018-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-black-panther-wakanda-forever-2022-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-black-panther-wakanda-forever-2022-backdrop.jpg new file mode 100644 index 00000000..ac7ad532 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-black-panther-wakanda-forever-2022-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-black-panther-wakanda-forever-2022-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-black-panther-wakanda-forever-2022-poster.jpg new file mode 100644 index 00000000..d0219a75 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-black-panther-wakanda-forever-2022-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-blame-2017-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-blame-2017-backdrop.jpg new file mode 100644 index 00000000..f39cf5ce Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-blame-2017-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-blame-2017-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-blame-2017-poster.jpg new file mode 100644 index 00000000..8d50255f Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-blame-2017-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-bleach-the-movie-fade-to-black-2008-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-bleach-the-movie-fade-to-black-2008-backdrop.jpg new file mode 100644 index 00000000..f426d0ce Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-bleach-the-movie-fade-to-black-2008-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-bleach-the-movie-fade-to-black-2008-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-bleach-the-movie-fade-to-black-2008-poster.jpg new file mode 100644 index 00000000..d3619fbd Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-bleach-the-movie-fade-to-black-2008-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-butterfly-on-a-wheel-2007-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-butterfly-on-a-wheel-2007-backdrop.jpg new file mode 100644 index 00000000..e49fe1d5 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-butterfly-on-a-wheel-2007-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-butterfly-on-a-wheel-2007-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-butterfly-on-a-wheel-2007-poster.jpg new file mode 100644 index 00000000..b54cc5c7 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-butterfly-on-a-wheel-2007-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-captain-america-civil-war-2016-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-captain-america-civil-war-2016-backdrop.jpg new file mode 100644 index 00000000..5700c4e7 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-captain-america-civil-war-2016-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-captain-america-civil-war-2016-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-captain-america-civil-war-2016-poster.jpg new file mode 100644 index 00000000..426142ef Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-captain-america-civil-war-2016-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-careful-what-you-wish-for-2015-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-careful-what-you-wish-for-2015-backdrop.jpg new file mode 100644 index 00000000..988e20d5 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-careful-what-you-wish-for-2015-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-careful-what-you-wish-for-2015-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-careful-what-you-wish-for-2015-poster.jpg new file mode 100644 index 00000000..b58ce600 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-careful-what-you-wish-for-2015-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-castle-in-the-sky-1986-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-castle-in-the-sky-1986-backdrop.jpg new file mode 100644 index 00000000..f785c549 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-castle-in-the-sky-1986-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-castle-in-the-sky-1986-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-castle-in-the-sky-1986-poster.jpg new file mode 100644 index 00000000..a6a99fee Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-castle-in-the-sky-1986-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-chicago-2002-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-chicago-2002-backdrop.jpg new file mode 100644 index 00000000..6b3d02a3 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-chicago-2002-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-chicago-2002-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-chicago-2002-poster.jpg new file mode 100644 index 00000000..1def9414 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-chicago-2002-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-citizen-kane-1941-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-citizen-kane-1941-backdrop.jpg new file mode 100644 index 00000000..d41a10ef Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-citizen-kane-1941-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-citizen-kane-1941-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-citizen-kane-1941-poster.jpg new file mode 100644 index 00000000..f26414a7 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-citizen-kane-1941-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-conclave-2024-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-conclave-2024-backdrop.jpg new file mode 100644 index 00000000..db0a7fcd Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-conclave-2024-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-conclave-2024-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-conclave-2024-poster.jpg new file mode 100644 index 00000000..c6aecefa Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-conclave-2024-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-crime-of-passion-1956-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-crime-of-passion-1956-backdrop.jpg new file mode 100644 index 00000000..6c70a452 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-crime-of-passion-1956-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-crime-of-passion-1956-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-crime-of-passion-1956-poster.jpg new file mode 100644 index 00000000..4acfa871 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-crime-of-passion-1956-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-deep-water-2022-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-deep-water-2022-backdrop.jpg new file mode 100644 index 00000000..bec98992 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-deep-water-2022-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-deep-water-2022-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-deep-water-2022-poster.jpg new file mode 100644 index 00000000..018d4f4b Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-deep-water-2022-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-derailed-2005-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-derailed-2005-backdrop.jpg new file mode 100644 index 00000000..e958449b Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-derailed-2005-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-derailed-2005-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-derailed-2005-poster.jpg new file mode 100644 index 00000000..d93f3124 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-derailed-2005-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-dream-house-2011-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-dream-house-2011-backdrop.jpg new file mode 100644 index 00000000..29ecc103 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-dream-house-2011-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-dream-house-2011-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-dream-house-2011-poster.jpg new file mode 100644 index 00000000..d3444637 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-dream-house-2011-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-dream-lover-1994-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-dream-lover-1994-backdrop.jpg new file mode 100644 index 00000000..7f5a31ac Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-dream-lover-1994-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-dream-lover-1994-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-dream-lover-1994-poster.jpg new file mode 100644 index 00000000..3b563cf9 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-dream-lover-1994-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-drop-2025-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-drop-2025-backdrop.jpg new file mode 100644 index 00000000..ee642530 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-drop-2025-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-drop-2025-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-drop-2025-poster.jpg new file mode 100644 index 00000000..4cf7d66b Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-drop-2025-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-eastern-promises-2007-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-eastern-promises-2007-backdrop.jpg new file mode 100644 index 00000000..9096a0fa Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-eastern-promises-2007-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-eastern-promises-2007-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-eastern-promises-2007-poster.jpg new file mode 100644 index 00000000..01a26f3b Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-eastern-promises-2007-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-el-camino-a-breaking-bad-movie-2019-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-el-camino-a-breaking-bad-movie-2019-backdrop.jpg new file mode 100644 index 00000000..8edc02a6 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-el-camino-a-breaking-bad-movie-2019-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-el-camino-a-breaking-bad-movie-2019-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-el-camino-a-breaking-bad-movie-2019-poster.jpg new file mode 100644 index 00000000..7a62df45 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-el-camino-a-breaking-bad-movie-2019-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-fatale-2020-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-fatale-2020-backdrop.jpg new file mode 100644 index 00000000..b13c33c6 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-fatale-2020-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-fatale-2020-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-fatale-2020-poster.jpg new file mode 100644 index 00000000..dda9d622 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-fatale-2020-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-force-of-nature-the-dry-2-2024-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-force-of-nature-the-dry-2-2024-backdrop.jpg new file mode 100644 index 00000000..3735ee63 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-force-of-nature-the-dry-2-2024-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-force-of-nature-the-dry-2-2024-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-force-of-nature-the-dry-2-2024-poster.jpg new file mode 100644 index 00000000..93ba0d71 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-force-of-nature-the-dry-2-2024-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-ghost-in-the-shell-1995-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-ghost-in-the-shell-1995-backdrop.jpg new file mode 100644 index 00000000..716b8a87 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-ghost-in-the-shell-1995-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-ghost-in-the-shell-1995-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-ghost-in-the-shell-1995-poster.jpg new file mode 100644 index 00000000..58d221ba Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-ghost-in-the-shell-1995-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-ghost-in-the-shell-2-innocence-2004-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-ghost-in-the-shell-2-innocence-2004-backdrop.jpg new file mode 100644 index 00000000..4a9931ed Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-ghost-in-the-shell-2-innocence-2004-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-ghost-in-the-shell-2-innocence-2004-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-ghost-in-the-shell-2-innocence-2004-poster.jpg new file mode 100644 index 00000000..ae262147 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-ghost-in-the-shell-2-innocence-2004-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-gosford-park-2001-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-gosford-park-2001-backdrop.jpg new file mode 100644 index 00000000..42c4cea6 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-gosford-park-2001-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-gosford-park-2001-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-gosford-park-2001-poster.jpg new file mode 100644 index 00000000..6a6aa651 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-gosford-park-2001-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-howl-s-moving-castle-2004-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-howl-s-moving-castle-2004-backdrop.jpg new file mode 100644 index 00000000..0aeef2ba Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-howl-s-moving-castle-2004-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-howl-s-moving-castle-2004-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-howl-s-moving-castle-2004-poster.jpg new file mode 100644 index 00000000..042a6c80 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-howl-s-moving-castle-2004-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-in-the-heights-2021-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-in-the-heights-2021-backdrop.jpg new file mode 100644 index 00000000..7cd4ee24 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-in-the-heights-2021-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-in-the-heights-2021-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-in-the-heights-2021-poster.jpg new file mode 100644 index 00000000..e05bfdb0 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-in-the-heights-2021-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-kiki-s-delivery-service-1989-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-kiki-s-delivery-service-1989-backdrop.jpg new file mode 100644 index 00000000..2a108f0c Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-kiki-s-delivery-service-1989-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-kiki-s-delivery-service-1989-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-kiki-s-delivery-service-1989-poster.jpg new file mode 100644 index 00000000..80a59b1e Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-kiki-s-delivery-service-1989-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-lemony-snicket-s-a-series-of-unfortunate-events-2004-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-lemony-snicket-s-a-series-of-unfortunate-events-2004-backdrop.jpg new file mode 100644 index 00000000..38203b77 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-lemony-snicket-s-a-series-of-unfortunate-events-2004-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-lemony-snicket-s-a-series-of-unfortunate-events-2004-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-lemony-snicket-s-a-series-of-unfortunate-events-2004-poster.jpg new file mode 100644 index 00000000..4c78fee9 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-lemony-snicket-s-a-series-of-unfortunate-events-2004-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-locke-2014-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-locke-2014-backdrop.jpg new file mode 100644 index 00000000..a24e64ab Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-locke-2014-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-locke-2014-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-locke-2014-poster.jpg new file mode 100644 index 00000000..94ebe97d Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-locke-2014-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-memories-1995-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-memories-1995-backdrop.jpg new file mode 100644 index 00000000..2fcaeaad Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-memories-1995-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-memories-1995-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-memories-1995-poster.jpg new file mode 100644 index 00000000..f3725b42 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-memories-1995-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-night-is-short-walk-on-girl-2017-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-night-is-short-walk-on-girl-2017-backdrop.jpg new file mode 100644 index 00000000..da38be48 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-night-is-short-walk-on-girl-2017-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-night-is-short-walk-on-girl-2017-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-night-is-short-walk-on-girl-2017-poster.jpg new file mode 100644 index 00000000..c6fa6a26 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-night-is-short-walk-on-girl-2017-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-panic-room-2002-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-panic-room-2002-backdrop.jpg new file mode 100644 index 00000000..ec877751 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-panic-room-2002-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-panic-room-2002-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-panic-room-2002-poster.jpg new file mode 100644 index 00000000..0b2a0d30 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-panic-room-2002-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-ponyo-2008-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-ponyo-2008-backdrop.jpg new file mode 100644 index 00000000..8aa4ecbd Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-ponyo-2008-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-ponyo-2008-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-ponyo-2008-poster.jpg new file mode 100644 index 00000000..f548e831 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-ponyo-2008-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-porco-rosso-1992-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-porco-rosso-1992-backdrop.jpg new file mode 100644 index 00000000..63d8112e Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-porco-rosso-1992-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-porco-rosso-1992-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-porco-rosso-1992-poster.jpg new file mode 100644 index 00000000..4a6a2bd1 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-porco-rosso-1992-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-princess-mononoke-1997-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-princess-mononoke-1997-backdrop.jpg new file mode 100644 index 00000000..9486d2cf Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-princess-mononoke-1997-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-princess-mononoke-1997-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-princess-mononoke-1997-poster.jpg new file mode 100644 index 00000000..21dd9359 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-princess-mononoke-1997-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-prisoners-2013-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-prisoners-2013-backdrop.jpg new file mode 100644 index 00000000..724008c5 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-prisoners-2013-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-prisoners-2013-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-prisoners-2013-poster.jpg new file mode 100644 index 00000000..411b149b Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-prisoners-2013-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-racing-stripes-2005-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-racing-stripes-2005-backdrop.jpg new file mode 100644 index 00000000..1d332cec Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-racing-stripes-2005-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-racing-stripes-2005-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-racing-stripes-2005-poster.jpg new file mode 100644 index 00000000..cc2ef2ce Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-racing-stripes-2005-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-secondhand-lions-2003-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-secondhand-lions-2003-backdrop.jpg new file mode 100644 index 00000000..7ea43937 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-secondhand-lions-2003-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-secondhand-lions-2003-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-secondhand-lions-2003-poster.jpg new file mode 100644 index 00000000..33408fa0 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-secondhand-lions-2003-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-shaft-2000-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-shaft-2000-backdrop.jpg new file mode 100644 index 00000000..13f14f93 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-shaft-2000-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-shaft-2000-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-shaft-2000-poster.jpg new file mode 100644 index 00000000..6b2b79ce Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-shaft-2000-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-sinbad-legend-of-the-seven-seas-2003-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-sinbad-legend-of-the-seven-seas-2003-backdrop.jpg new file mode 100644 index 00000000..d04685fe Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-sinbad-legend-of-the-seven-seas-2003-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-sinbad-legend-of-the-seven-seas-2003-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-sinbad-legend-of-the-seven-seas-2003-poster.jpg new file mode 100644 index 00000000..428bb38b Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-sinbad-legend-of-the-seven-seas-2003-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-sleeping-with-other-people-2015-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-sleeping-with-other-people-2015-backdrop.jpg new file mode 100644 index 00000000..df5bb046 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-sleeping-with-other-people-2015-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-sleeping-with-other-people-2015-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-sleeping-with-other-people-2015-poster.jpg new file mode 100644 index 00000000..a5ffff1f Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-sleeping-with-other-people-2015-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-snowpiercer-2013-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-snowpiercer-2013-backdrop.jpg new file mode 100644 index 00000000..c1281a9c Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-snowpiercer-2013-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-snowpiercer-2013-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-snowpiercer-2013-poster.jpg new file mode 100644 index 00000000..be1873fd Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-snowpiercer-2013-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-spider-man-brand-new-day-2026-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-spider-man-brand-new-day-2026-backdrop.jpg new file mode 100644 index 00000000..2fdaadb4 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-spider-man-brand-new-day-2026-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-spider-man-brand-new-day-2026-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-spider-man-brand-new-day-2026-poster.jpg new file mode 100644 index 00000000..51fa155f Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-spider-man-brand-new-day-2026-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-spider-man-far-from-home-2019-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-spider-man-far-from-home-2019-backdrop.jpg new file mode 100644 index 00000000..d09f655a Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-spider-man-far-from-home-2019-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-spider-man-far-from-home-2019-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-spider-man-far-from-home-2019-poster.jpg new file mode 100644 index 00000000..28521997 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-spider-man-far-from-home-2019-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-spider-man-homecoming-2017-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-spider-man-homecoming-2017-backdrop.jpg new file mode 100644 index 00000000..6088fadf Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-spider-man-homecoming-2017-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-spider-man-homecoming-2017-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-spider-man-homecoming-2017-poster.jpg new file mode 100644 index 00000000..97fc9c05 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-spider-man-homecoming-2017-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-spider-man-no-way-home-2021-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-spider-man-no-way-home-2021-backdrop.jpg new file mode 100644 index 00000000..a76afec9 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-spider-man-no-way-home-2021-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-spider-man-no-way-home-2021-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-spider-man-no-way-home-2021-poster.jpg new file mode 100644 index 00000000..bc92a4cd Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-spider-man-no-way-home-2021-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-spirited-away-2001-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-spirited-away-2001-backdrop.jpg new file mode 100644 index 00000000..af91c123 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-spirited-away-2001-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-spirited-away-2001-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-spirited-away-2001-poster.jpg new file mode 100644 index 00000000..5a79da62 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-spirited-away-2001-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-the-alto-knights-2025-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-the-alto-knights-2025-backdrop.jpg new file mode 100644 index 00000000..ea619c14 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-the-alto-knights-2025-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-the-alto-knights-2025-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-the-alto-knights-2025-poster.jpg new file mode 100644 index 00000000..bb009cbf Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-the-alto-knights-2025-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-the-amazing-spider-man-2-2014-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-the-amazing-spider-man-2-2014-backdrop.jpg new file mode 100644 index 00000000..7c5878b7 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-the-amazing-spider-man-2-2014-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-the-amazing-spider-man-2-2014-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-the-amazing-spider-man-2-2014-poster.jpg new file mode 100644 index 00000000..4de2711f Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-the-amazing-spider-man-2-2014-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-the-amazing-spider-man-2012-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-the-amazing-spider-man-2012-backdrop.jpg new file mode 100644 index 00000000..75ae9b64 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-the-amazing-spider-man-2012-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-the-amazing-spider-man-2012-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-the-amazing-spider-man-2012-poster.jpg new file mode 100644 index 00000000..c1aec876 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-the-amazing-spider-man-2012-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-the-animatrix-2003-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-the-animatrix-2003-backdrop.jpg new file mode 100644 index 00000000..7d67ccb0 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-the-animatrix-2003-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-the-animatrix-2003-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-the-animatrix-2003-poster.jpg new file mode 100644 index 00000000..65553d47 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-the-animatrix-2003-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-the-avengers-2012-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-the-avengers-2012-backdrop.jpg new file mode 100644 index 00000000..83636f25 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-the-avengers-2012-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-the-avengers-2012-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-the-avengers-2012-poster.jpg new file mode 100644 index 00000000..be87067c Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-the-avengers-2012-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-the-boy-and-the-heron-2023-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-the-boy-and-the-heron-2023-backdrop.jpg new file mode 100644 index 00000000..a19dc77b Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-the-boy-and-the-heron-2023-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-the-boy-and-the-heron-2023-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-the-boy-and-the-heron-2023-poster.jpg new file mode 100644 index 00000000..094df64e Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-the-boy-and-the-heron-2023-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-the-breakfast-club-1985-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-the-breakfast-club-1985-backdrop.jpg new file mode 100644 index 00000000..9f979cd8 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-the-breakfast-club-1985-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-the-breakfast-club-1985-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-the-breakfast-club-1985-poster.jpg new file mode 100644 index 00000000..d1823120 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-the-breakfast-club-1985-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-the-dry-2021-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-the-dry-2021-backdrop.jpg new file mode 100644 index 00000000..2f016498 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-the-dry-2021-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-the-dry-2021-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-the-dry-2021-poster.jpg new file mode 100644 index 00000000..a0379f2f Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-the-dry-2021-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-the-girl-who-leapt-through-time-2006-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-the-girl-who-leapt-through-time-2006-backdrop.jpg new file mode 100644 index 00000000..6e920467 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-the-girl-who-leapt-through-time-2006-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-the-girl-who-leapt-through-time-2006-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-the-girl-who-leapt-through-time-2006-poster.jpg new file mode 100644 index 00000000..ded6cd2a Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-the-girl-who-leapt-through-time-2006-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-the-godfather-1972-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-the-godfather-1972-backdrop.jpg new file mode 100644 index 00000000..8fbb8f2a Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-the-godfather-1972-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-the-godfather-1972-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-the-godfather-1972-poster.jpg new file mode 100644 index 00000000..94111d9b Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-the-godfather-1972-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-the-godfather-part-iii-1990-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-the-godfather-part-iii-1990-backdrop.jpg new file mode 100644 index 00000000..d2080487 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-the-godfather-part-iii-1990-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-the-godfather-part-iii-1990-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-the-godfather-part-iii-1990-poster.jpg new file mode 100644 index 00000000..abbe5e99 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-the-godfather-part-iii-1990-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-the-great-gatsby-2013-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-the-great-gatsby-2013-backdrop.jpg new file mode 100644 index 00000000..7a4f8a32 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-the-great-gatsby-2013-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-the-great-gatsby-2013-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-the-great-gatsby-2013-poster.jpg new file mode 100644 index 00000000..e949fb3e Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-the-great-gatsby-2013-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-the-killing-of-a-sacred-deer-2017-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-the-killing-of-a-sacred-deer-2017-backdrop.jpg new file mode 100644 index 00000000..dd755ee8 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-the-killing-of-a-sacred-deer-2017-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-the-killing-of-a-sacred-deer-2017-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-the-killing-of-a-sacred-deer-2017-poster.jpg new file mode 100644 index 00000000..83464d4c Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-the-killing-of-a-sacred-deer-2017-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-the-lighthouse-2019-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-the-lighthouse-2019-backdrop.jpg new file mode 100644 index 00000000..862c064a Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-the-lighthouse-2019-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-the-lighthouse-2019-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-the-lighthouse-2019-poster.jpg new file mode 100644 index 00000000..15f26533 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-the-lighthouse-2019-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-the-secret-life-of-pets-2-2019-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-the-secret-life-of-pets-2-2019-backdrop.jpg new file mode 100644 index 00000000..698f4ad2 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-the-secret-life-of-pets-2-2019-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-the-secret-life-of-pets-2-2019-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-the-secret-life-of-pets-2-2019-poster.jpg new file mode 100644 index 00000000..fe50c2f8 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-the-secret-life-of-pets-2-2019-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-the-tale-of-the-princess-kaguya-2013-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-the-tale-of-the-princess-kaguya-2013-backdrop.jpg new file mode 100644 index 00000000..b9157b91 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-the-tale-of-the-princess-kaguya-2013-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-the-tale-of-the-princess-kaguya-2013-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-the-tale-of-the-princess-kaguya-2013-poster.jpg new file mode 100644 index 00000000..882621cb Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-the-tale-of-the-princess-kaguya-2013-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-the-wild-robot-2024-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-the-wild-robot-2024-backdrop.jpg new file mode 100644 index 00000000..bb48460b Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-the-wild-robot-2024-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-the-wild-robot-2024-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-the-wild-robot-2024-poster.jpg new file mode 100644 index 00000000..0894754d Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-the-wild-robot-2024-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-the-witcher-nightmare-of-the-wolf-2021-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-the-witcher-nightmare-of-the-wolf-2021-backdrop.jpg new file mode 100644 index 00000000..cb5bfb28 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-the-witcher-nightmare-of-the-wolf-2021-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-the-witcher-nightmare-of-the-wolf-2021-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-the-witcher-nightmare-of-the-wolf-2021-poster.jpg new file mode 100644 index 00000000..6db33db1 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-the-witcher-nightmare-of-the-wolf-2021-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-the-witcher-sirens-of-the-deep-2025-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-the-witcher-sirens-of-the-deep-2025-backdrop.jpg new file mode 100644 index 00000000..aad8ea2c Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-the-witcher-sirens-of-the-deep-2025-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-the-witcher-sirens-of-the-deep-2025-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-the-witcher-sirens-of-the-deep-2025-poster.jpg new file mode 100644 index 00000000..8a54bc7f Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-the-witcher-sirens-of-the-deep-2025-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-thelma-louise-1991-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-thelma-louise-1991-backdrop.jpg new file mode 100644 index 00000000..a35327a9 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-thelma-louise-1991-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-thelma-louise-1991-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-thelma-louise-1991-poster.jpg new file mode 100644 index 00000000..5a4ff0ab Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-thelma-louise-1991-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-triangle-of-sadness-2022-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-triangle-of-sadness-2022-backdrop.jpg new file mode 100644 index 00000000..7c9b445d Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-triangle-of-sadness-2022-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-triangle-of-sadness-2022-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-triangle-of-sadness-2022-poster.jpg new file mode 100644 index 00000000..aee092c6 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-triangle-of-sadness-2022-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-vice-2018-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-vice-2018-backdrop.jpg new file mode 100644 index 00000000..2918db3a Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-vice-2018-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/movie-vice-2018-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/movie-vice-2018-poster.jpg new file mode 100644 index 00000000..76855126 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/movie-vice-2018-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-12-monkeys-2015-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-12-monkeys-2015-backdrop.jpg new file mode 100644 index 00000000..3d2825f5 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-12-monkeys-2015-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-12-monkeys-2015-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-12-monkeys-2015-poster.jpg new file mode 100644 index 00000000..96e3596e Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-12-monkeys-2015-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-56-days-2026-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-56-days-2026-backdrop.jpg new file mode 100644 index 00000000..dcda667a Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-56-days-2026-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-56-days-2026-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-56-days-2026-poster.jpg new file mode 100644 index 00000000..64ca587b Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-56-days-2026-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-a-knight-of-the-seven-kingdoms-2026-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-a-knight-of-the-seven-kingdoms-2026-backdrop.jpg new file mode 100644 index 00000000..ce12fc71 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-a-knight-of-the-seven-kingdoms-2026-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-a-knight-of-the-seven-kingdoms-2026-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-a-knight-of-the-seven-kingdoms-2026-poster.jpg new file mode 100644 index 00000000..79f1351c Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-a-knight-of-the-seven-kingdoms-2026-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-absolutely-fabulous-1992-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-absolutely-fabulous-1992-backdrop.jpg new file mode 100644 index 00000000..2df9722d Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-absolutely-fabulous-1992-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-absolutely-fabulous-1992-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-absolutely-fabulous-1992-poster.jpg new file mode 100644 index 00000000..afd371a9 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-absolutely-fabulous-1992-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-accel-world-2012-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-accel-world-2012-backdrop.jpg new file mode 100644 index 00000000..1f5f6bdc Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-accel-world-2012-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-accel-world-2012-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-accel-world-2012-poster.jpg new file mode 100644 index 00000000..207b1dd1 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-accel-world-2012-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-accused-2023-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-accused-2023-backdrop.jpg new file mode 100644 index 00000000..d41c6397 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-accused-2023-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-accused-2023-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-accused-2023-poster.jpg new file mode 100644 index 00000000..74af010a Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-accused-2023-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-after-life-2019-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-after-life-2019-backdrop.jpg new file mode 100644 index 00000000..eaf9a4fa Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-after-life-2019-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-after-life-2019-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-after-life-2019-poster.jpg new file mode 100644 index 00000000..4fae4e33 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-after-life-2019-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-agatha-christie-s-marple-2004-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-agatha-christie-s-marple-2004-backdrop.jpg new file mode 100644 index 00000000..0c52f2e6 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-agatha-christie-s-marple-2004-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-agatha-christie-s-marple-2004-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-agatha-christie-s-marple-2004-poster.jpg new file mode 100644 index 00000000..ea7dda99 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-agatha-christie-s-marple-2004-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-ahsoka-2023-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-ahsoka-2023-backdrop.jpg new file mode 100644 index 00000000..7343fb32 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-ahsoka-2023-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-ahsoka-2023-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-ahsoka-2023-poster.jpg new file mode 100644 index 00000000..a29d6cb4 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-ahsoka-2023-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-all-creatures-great-and-small-1978-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-all-creatures-great-and-small-1978-backdrop.jpg new file mode 100644 index 00000000..909ae1ba Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-all-creatures-great-and-small-1978-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-all-creatures-great-and-small-1978-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-all-creatures-great-and-small-1978-poster.jpg new file mode 100644 index 00000000..5b1666e6 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-all-creatures-great-and-small-1978-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-all-creatures-great-small-2020-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-all-creatures-great-small-2020-backdrop.jpg new file mode 100644 index 00000000..d2bcc88d Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-all-creatures-great-small-2020-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-all-creatures-great-small-2020-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-all-creatures-great-small-2020-poster.jpg new file mode 100644 index 00000000..b506f990 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-all-creatures-great-small-2020-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-american-dad-2005-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-american-dad-2005-backdrop.jpg new file mode 100644 index 00000000..75a1948b Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-american-dad-2005-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-american-dad-2005-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-american-dad-2005-poster.jpg new file mode 100644 index 00000000..1f9e239a Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-american-dad-2005-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-american-gods-2017-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-american-gods-2017-backdrop.jpg new file mode 100644 index 00000000..4817c690 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-american-gods-2017-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-american-gods-2017-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-american-gods-2017-poster.jpg new file mode 100644 index 00000000..c02c46da Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-american-gods-2017-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-american-housewife-2016-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-american-housewife-2016-backdrop.jpg new file mode 100644 index 00000000..bf758ae0 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-american-housewife-2016-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-american-housewife-2016-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-american-housewife-2016-poster.jpg new file mode 100644 index 00000000..5f92bf05 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-american-housewife-2016-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-american-primeval-2025-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-american-primeval-2025-backdrop.jpg new file mode 100644 index 00000000..c3bfe5e1 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-american-primeval-2025-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-american-primeval-2025-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-american-primeval-2025-poster.jpg new file mode 100644 index 00000000..7f10e6aa Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-american-primeval-2025-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-and-just-like-that-2021-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-and-just-like-that-2021-backdrop.jpg new file mode 100644 index 00000000..59c981e5 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-and-just-like-that-2021-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-and-just-like-that-2021-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-and-just-like-that-2021-poster.jpg new file mode 100644 index 00000000..9904c74b Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-and-just-like-that-2021-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-andor-2022-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-andor-2022-backdrop.jpg new file mode 100644 index 00000000..a874a0c0 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-andor-2022-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-andor-2022-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-andor-2022-poster.jpg new file mode 100644 index 00000000..df5dc498 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-andor-2022-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-andromeda-2000-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-andromeda-2000-backdrop.jpg new file mode 100644 index 00000000..199249d7 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-andromeda-2000-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-andromeda-2000-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-andromeda-2000-poster.jpg new file mode 100644 index 00000000..67b766b0 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-andromeda-2000-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-anne-with-an-e-2017-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-anne-with-an-e-2017-backdrop.jpg new file mode 100644 index 00000000..15e325c9 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-anne-with-an-e-2017-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-anne-with-an-e-2017-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-anne-with-an-e-2017-poster.jpg new file mode 100644 index 00000000..55d443b4 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-anne-with-an-e-2017-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-aqua-teen-hunger-force-2000-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-aqua-teen-hunger-force-2000-backdrop.jpg new file mode 100644 index 00000000..d0e37959 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-aqua-teen-hunger-force-2000-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-aqua-teen-hunger-force-2000-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-aqua-teen-hunger-force-2000-poster.jpg new file mode 100644 index 00000000..e0c97321 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-aqua-teen-hunger-force-2000-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-arifureta-from-commonplace-to-world-s-strongest-2019-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-arifureta-from-commonplace-to-world-s-strongest-2019-backdrop.jpg new file mode 100644 index 00000000..9300e20f Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-arifureta-from-commonplace-to-world-s-strongest-2019-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-arifureta-from-commonplace-to-world-s-strongest-2019-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-arifureta-from-commonplace-to-world-s-strongest-2019-poster.jpg new file mode 100644 index 00000000..6a8f9a24 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-arifureta-from-commonplace-to-world-s-strongest-2019-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-arrow-2012-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-arrow-2012-backdrop.jpg new file mode 100644 index 00000000..b32f5aca Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-arrow-2012-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-arrow-2012-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-arrow-2012-poster.jpg new file mode 100644 index 00000000..adee3bb7 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-arrow-2012-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-atlantis-2013-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-atlantis-2013-backdrop.jpg new file mode 100644 index 00000000..39ecc0d6 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-atlantis-2013-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-atlantis-2013-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-atlantis-2013-poster.jpg new file mode 100644 index 00000000..5cd5f098 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-atlantis-2013-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-avatar-seven-havens-2026-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-avatar-seven-havens-2026-backdrop.jpg new file mode 100644 index 00000000..dacfd59e Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-avatar-seven-havens-2026-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-avatar-seven-havens-2026-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-avatar-seven-havens-2026-poster.jpg new file mode 100644 index 00000000..61f459c6 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-avatar-seven-havens-2026-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-avatar-the-last-airbender-2005-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-avatar-the-last-airbender-2005-backdrop.jpg new file mode 100644 index 00000000..f60120da Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-avatar-the-last-airbender-2005-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-avatar-the-last-airbender-2005-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-avatar-the-last-airbender-2005-poster.jpg new file mode 100644 index 00000000..6f99263a Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-avatar-the-last-airbender-2005-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-avatar-the-last-airbender-2024-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-avatar-the-last-airbender-2024-backdrop.jpg new file mode 100644 index 00000000..ad740218 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-avatar-the-last-airbender-2024-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-avatar-the-last-airbender-2024-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-avatar-the-last-airbender-2024-poster.jpg new file mode 100644 index 00000000..9d46c2ff Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-avatar-the-last-airbender-2024-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-awkward-2011-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-awkward-2011-backdrop.jpg new file mode 100644 index 00000000..1ca5e56c Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-awkward-2011-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-awkward-2011-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-awkward-2011-poster.jpg new file mode 100644 index 00000000..8da6e8e2 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-awkward-2011-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-back-to-life-2019-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-back-to-life-2019-backdrop.jpg new file mode 100644 index 00000000..7ffef681 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-back-to-life-2019-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-back-to-life-2019-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-back-to-life-2019-poster.jpg new file mode 100644 index 00000000..b00730a8 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-back-to-life-2019-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-ballers-2015-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-ballers-2015-backdrop.jpg new file mode 100644 index 00000000..c4685e84 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-ballers-2015-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-ballers-2015-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-ballers-2015-poster.jpg new file mode 100644 index 00000000..f1c18f69 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-ballers-2015-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-baretta-1975-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-baretta-1975-backdrop.jpg new file mode 100644 index 00000000..4d61dfbe Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-baretta-1975-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-baretta-1975-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-baretta-1975-poster.jpg new file mode 100644 index 00000000..ceef0c9d Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-baretta-1975-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-based-on-a-true-story-2023-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-based-on-a-true-story-2023-backdrop.jpg new file mode 100644 index 00000000..b59c0e58 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-based-on-a-true-story-2023-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-based-on-a-true-story-2023-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-based-on-a-true-story-2023-poster.jpg new file mode 100644 index 00000000..386d3d90 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-based-on-a-true-story-2023-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-batman-the-brave-and-the-bold-2008-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-batman-the-brave-and-the-bold-2008-backdrop.jpg new file mode 100644 index 00000000..69e567cb Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-batman-the-brave-and-the-bold-2008-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-batman-the-brave-and-the-bold-2008-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-batman-the-brave-and-the-bold-2008-poster.jpg new file mode 100644 index 00000000..a864f50c Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-batman-the-brave-and-the-bold-2008-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-batwoman-2019-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-batwoman-2019-backdrop.jpg new file mode 100644 index 00000000..d04a1a20 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-batwoman-2019-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-batwoman-2019-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-batwoman-2019-poster.jpg new file mode 100644 index 00000000..7ca86592 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-batwoman-2019-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-big-boys-2022-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-big-boys-2022-backdrop.jpg new file mode 100644 index 00000000..c7c91e2d Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-big-boys-2022-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-big-boys-2022-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-big-boys-2022-poster.jpg new file mode 100644 index 00000000..93e1e86a Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-big-boys-2022-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-big-city-greens-2018-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-big-city-greens-2018-backdrop.jpg new file mode 100644 index 00000000..381774e7 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-big-city-greens-2018-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-big-city-greens-2018-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-big-city-greens-2018-poster.jpg new file mode 100644 index 00000000..ef024946 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-big-city-greens-2018-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-big-mouth-2017-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-big-mouth-2017-backdrop.jpg new file mode 100644 index 00000000..760e0262 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-big-mouth-2017-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-big-mouth-2017-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-big-mouth-2017-poster.jpg new file mode 100644 index 00000000..4f535fec Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-big-mouth-2017-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-black-lightning-2018-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-black-lightning-2018-backdrop.jpg new file mode 100644 index 00000000..3a0854c9 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-black-lightning-2018-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-black-lightning-2018-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-black-lightning-2018-poster.jpg new file mode 100644 index 00000000..733f5cbc Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-black-lightning-2018-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-black-rabbit-2025-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-black-rabbit-2025-backdrop.jpg new file mode 100644 index 00000000..48df9d46 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-black-rabbit-2025-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-black-rabbit-2025-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-black-rabbit-2025-poster.jpg new file mode 100644 index 00000000..3ff9aeed Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-black-rabbit-2025-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-bleach-2004-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-bleach-2004-backdrop.jpg new file mode 100644 index 00000000..ef8eaaa3 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-bleach-2004-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-bleach-2004-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-bleach-2004-poster.jpg new file mode 100644 index 00000000..b233e033 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-bleach-2004-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-brassic-2019-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-brassic-2019-backdrop.jpg new file mode 100644 index 00000000..86d3d806 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-brassic-2019-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-brassic-2019-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-brassic-2019-poster.jpg new file mode 100644 index 00000000..73b77df2 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-brassic-2019-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-breaking-bad-2008-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-breaking-bad-2008-backdrop.jpg new file mode 100644 index 00000000..e4ac4ae3 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-breaking-bad-2008-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-breaking-bad-2008-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-breaking-bad-2008-poster.jpg new file mode 100644 index 00000000..c4f7217c Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-breaking-bad-2008-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-californication-2007-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-californication-2007-backdrop.jpg new file mode 100644 index 00000000..ffff979b Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-californication-2007-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-californication-2007-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-californication-2007-poster.jpg new file mode 100644 index 00000000..38428e76 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-californication-2007-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-chainsaw-man-2022-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-chainsaw-man-2022-backdrop.jpg new file mode 100644 index 00000000..f1fbee3e Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-chainsaw-man-2022-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-chainsaw-man-2022-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-chainsaw-man-2022-poster.jpg new file mode 100644 index 00000000..a3779772 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-chainsaw-man-2022-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-cyberpunk-edgerunners-2022-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-cyberpunk-edgerunners-2022-backdrop.jpg new file mode 100644 index 00000000..2920cf5a Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-cyberpunk-edgerunners-2022-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-cyberpunk-edgerunners-2022-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-cyberpunk-edgerunners-2022-poster.jpg new file mode 100644 index 00000000..8d338532 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-cyberpunk-edgerunners-2022-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-derry-girls-2018-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-derry-girls-2018-backdrop.jpg new file mode 100644 index 00000000..76fae98c Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-derry-girls-2018-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-derry-girls-2018-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-derry-girls-2018-poster.jpg new file mode 100644 index 00000000..56a8cd79 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-derry-girls-2018-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-desperate-housewives-2004-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-desperate-housewives-2004-backdrop.jpg new file mode 100644 index 00000000..40ec3001 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-desperate-housewives-2004-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-desperate-housewives-2004-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-desperate-housewives-2004-poster.jpg new file mode 100644 index 00000000..0c4c38bc Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-desperate-housewives-2004-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-dune-prophecy-2024-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-dune-prophecy-2024-backdrop.jpg new file mode 100644 index 00000000..5b940b9f Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-dune-prophecy-2024-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-dune-prophecy-2024-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-dune-prophecy-2024-poster.jpg new file mode 100644 index 00000000..eef2a4f3 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-dune-prophecy-2024-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-etoile-2025-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-etoile-2025-backdrop.jpg new file mode 100644 index 00000000..a8e9576c Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-etoile-2025-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-etoile-2025-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-etoile-2025-poster.jpg new file mode 100644 index 00000000..f078bc89 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-etoile-2025-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-fallout-2024-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-fallout-2024-backdrop.jpg new file mode 100644 index 00000000..c9d6a190 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-fallout-2024-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-fallout-2024-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-fallout-2024-poster.jpg new file mode 100644 index 00000000..5e87a07d Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-fallout-2024-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-firefly-2002-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-firefly-2002-backdrop.jpg new file mode 100644 index 00000000..fa3b7604 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-firefly-2002-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-firefly-2002-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-firefly-2002-poster.jpg new file mode 100644 index 00000000..9ad599b3 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-firefly-2002-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-fleabag-2016-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-fleabag-2016-backdrop.jpg new file mode 100644 index 00000000..e5a83462 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-fleabag-2016-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-fleabag-2016-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-fleabag-2016-poster.jpg new file mode 100644 index 00000000..bd3ccea5 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-fleabag-2016-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-gilmore-girls-2000-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-gilmore-girls-2000-backdrop.jpg new file mode 100644 index 00000000..b42ba953 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-gilmore-girls-2000-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-gilmore-girls-2000-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-gilmore-girls-2000-poster.jpg new file mode 100644 index 00000000..23b668cb Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-gilmore-girls-2000-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-high-potential-2024-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-high-potential-2024-backdrop.jpg new file mode 100644 index 00000000..66bb4d00 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-high-potential-2024-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-high-potential-2024-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-high-potential-2024-poster.jpg new file mode 100644 index 00000000..00a07ca7 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-high-potential-2024-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-invincible-2021-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-invincible-2021-backdrop.jpg new file mode 100644 index 00000000..e8120387 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-invincible-2021-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-invincible-2021-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-invincible-2021-poster.jpg new file mode 100644 index 00000000..c278e37e Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-invincible-2021-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-last-samurai-standing-2025-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-last-samurai-standing-2025-backdrop.jpg new file mode 100644 index 00000000..c85a210b Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-last-samurai-standing-2025-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-last-samurai-standing-2025-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-last-samurai-standing-2025-poster.jpg new file mode 100644 index 00000000..a9789909 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-last-samurai-standing-2025-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-lord-of-the-flies-2026-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-lord-of-the-flies-2026-backdrop.jpg new file mode 100644 index 00000000..1249a8f3 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-lord-of-the-flies-2026-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-lord-of-the-flies-2026-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-lord-of-the-flies-2026-poster.jpg new file mode 100644 index 00000000..b1229ed8 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-lord-of-the-flies-2026-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-love-death-robots-2019-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-love-death-robots-2019-backdrop.jpg new file mode 100644 index 00000000..3694bfc4 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-love-death-robots-2019-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-love-death-robots-2019-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-love-death-robots-2019-poster.jpg new file mode 100644 index 00000000..08449aa9 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-love-death-robots-2019-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-maniac-2018-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-maniac-2018-backdrop.jpg new file mode 100644 index 00000000..9d46de1d Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-maniac-2018-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-maniac-2018-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-maniac-2018-poster.jpg new file mode 100644 index 00000000..a1985217 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-maniac-2018-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-neon-genesis-evangelion-1995-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-neon-genesis-evangelion-1995-backdrop.jpg new file mode 100644 index 00000000..d80e17c1 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-neon-genesis-evangelion-1995-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-neon-genesis-evangelion-1995-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-neon-genesis-evangelion-1995-poster.jpg new file mode 100644 index 00000000..f86cd698 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-neon-genesis-evangelion-1995-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-norsemen-2016-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-norsemen-2016-backdrop.jpg new file mode 100644 index 00000000..58805e67 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-norsemen-2016-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-norsemen-2016-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-norsemen-2016-poster.jpg new file mode 100644 index 00000000..e7206b88 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-norsemen-2016-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-one-piece-2023-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-one-piece-2023-backdrop.jpg new file mode 100644 index 00000000..3fa4a282 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-one-piece-2023-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-one-piece-2023-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-one-piece-2023-poster.jpg new file mode 100644 index 00000000..286e6260 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-one-piece-2023-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-only-murders-in-the-building-2021-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-only-murders-in-the-building-2021-backdrop.jpg new file mode 100644 index 00000000..0b768d54 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-only-murders-in-the-building-2021-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-only-murders-in-the-building-2021-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-only-murders-in-the-building-2021-poster.jpg new file mode 100644 index 00000000..a6b147a4 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-only-murders-in-the-building-2021-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-over-the-garden-wall-2014-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-over-the-garden-wall-2014-backdrop.jpg new file mode 100644 index 00000000..43ac4428 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-over-the-garden-wall-2014-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-over-the-garden-wall-2014-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-over-the-garden-wall-2014-poster.jpg new file mode 100644 index 00000000..34b1ed84 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-over-the-garden-wall-2014-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-pluribus-2025-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-pluribus-2025-backdrop.jpg new file mode 100644 index 00000000..e64c0268 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-pluribus-2025-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-pluribus-2025-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-pluribus-2025-poster.jpg new file mode 100644 index 00000000..1ea4711b Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-pluribus-2025-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-rick-and-morty-2013-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-rick-and-morty-2013-backdrop.jpg new file mode 100644 index 00000000..1c4c0ffc Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-rick-and-morty-2013-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-rick-and-morty-2013-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-rick-and-morty-2013-poster.jpg new file mode 100644 index 00000000..b95c4890 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-rick-and-morty-2013-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-secret-level-2024-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-secret-level-2024-backdrop.jpg new file mode 100644 index 00000000..54d2a13e Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-secret-level-2024-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-secret-level-2024-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-secret-level-2024-poster.jpg new file mode 100644 index 00000000..1b6e67f6 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-secret-level-2024-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-severance-2022-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-severance-2022-backdrop.jpg new file mode 100644 index 00000000..a24c03bd Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-severance-2022-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-severance-2022-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-severance-2022-poster.jpg new file mode 100644 index 00000000..5a29d6f9 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-severance-2022-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-sex-and-the-city-1998-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-sex-and-the-city-1998-backdrop.jpg new file mode 100644 index 00000000..57beacc1 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-sex-and-the-city-1998-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-sex-and-the-city-1998-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-sex-and-the-city-1998-poster.jpg new file mode 100644 index 00000000..e546cc6d Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-sex-and-the-city-1998-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-the-100-2014-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-the-100-2014-backdrop.jpg new file mode 100644 index 00000000..8d41cb22 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-the-100-2014-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-the-100-2014-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-the-100-2014-poster.jpg new file mode 100644 index 00000000..4d254cb0 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-the-100-2014-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-the-abbott-and-costello-show-1952-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-the-abbott-and-costello-show-1952-backdrop.jpg new file mode 100644 index 00000000..53e1d593 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-the-abbott-and-costello-show-1952-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-the-abbott-and-costello-show-1952-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-the-abbott-and-costello-show-1952-poster.jpg new file mode 100644 index 00000000..7d6768ea Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-the-abbott-and-costello-show-1952-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-the-afterparty-2022-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-the-afterparty-2022-backdrop.jpg new file mode 100644 index 00000000..72ca19db Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-the-afterparty-2022-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-the-afterparty-2022-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-the-afterparty-2022-poster.jpg new file mode 100644 index 00000000..9beacde2 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-the-afterparty-2022-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-the-bear-2022-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-the-bear-2022-backdrop.jpg new file mode 100644 index 00000000..9c9cca57 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-the-bear-2022-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-the-bear-2022-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-the-bear-2022-poster.jpg new file mode 100644 index 00000000..bbf0ab28 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-the-bear-2022-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-the-beast-in-me-2025-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-the-beast-in-me-2025-backdrop.jpg new file mode 100644 index 00000000..e7727a79 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-the-beast-in-me-2025-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-the-beast-in-me-2025-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-the-beast-in-me-2025-poster.jpg new file mode 100644 index 00000000..c78c5cf0 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-the-beast-in-me-2025-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-the-bold-type-2017-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-the-bold-type-2017-backdrop.jpg new file mode 100644 index 00000000..dd84deab Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-the-bold-type-2017-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-the-bold-type-2017-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-the-bold-type-2017-poster.jpg new file mode 100644 index 00000000..f663eb8b Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-the-bold-type-2017-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-the-boys-2019-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-the-boys-2019-backdrop.jpg new file mode 100644 index 00000000..a834d9fb Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-the-boys-2019-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-the-boys-2019-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-the-boys-2019-poster.jpg new file mode 100644 index 00000000..f67ff16f Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-the-boys-2019-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-the-capture-2019-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-the-capture-2019-backdrop.jpg new file mode 100644 index 00000000..42256fc1 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-the-capture-2019-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-the-capture-2019-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-the-capture-2019-poster.jpg new file mode 100644 index 00000000..a4039011 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-the-capture-2019-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-the-durrells-2016-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-the-durrells-2016-backdrop.jpg new file mode 100644 index 00000000..3f8bdeec Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-the-durrells-2016-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-the-durrells-2016-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-the-durrells-2016-poster.jpg new file mode 100644 index 00000000..d29448bb Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-the-durrells-2016-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-the-final-problem-2026-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-the-final-problem-2026-backdrop.jpg new file mode 100644 index 00000000..61a310d8 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-the-final-problem-2026-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-the-final-problem-2026-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-the-final-problem-2026-poster.jpg new file mode 100644 index 00000000..f0332826 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-the-final-problem-2026-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-the-legend-of-korra-2012-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-the-legend-of-korra-2012-backdrop.jpg new file mode 100644 index 00000000..ab6086bd Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-the-legend-of-korra-2012-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-the-legend-of-korra-2012-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-the-legend-of-korra-2012-poster.jpg new file mode 100644 index 00000000..a7086d5e Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-the-legend-of-korra-2012-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-the-lord-of-the-rings-the-rings-of-power-2022-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-the-lord-of-the-rings-the-rings-of-power-2022-backdrop.jpg new file mode 100644 index 00000000..0b88fd4b Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-the-lord-of-the-rings-the-rings-of-power-2022-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-the-lord-of-the-rings-the-rings-of-power-2022-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-the-lord-of-the-rings-the-rings-of-power-2022-poster.jpg new file mode 100644 index 00000000..dc387fcd Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-the-lord-of-the-rings-the-rings-of-power-2022-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-the-night-manager-2016-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-the-night-manager-2016-backdrop.jpg new file mode 100644 index 00000000..327aa449 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-the-night-manager-2016-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-the-night-manager-2016-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-the-night-manager-2016-poster.jpg new file mode 100644 index 00000000..7ab2dbf5 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-the-night-manager-2016-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-the-tatami-galaxy-2010-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-the-tatami-galaxy-2010-backdrop.jpg new file mode 100644 index 00000000..a267b4cb Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-the-tatami-galaxy-2010-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-the-tatami-galaxy-2010-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-the-tatami-galaxy-2010-poster.jpg new file mode 100644 index 00000000..5324dc75 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-the-tatami-galaxy-2010-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-the-white-lotus-2021-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-the-white-lotus-2021-backdrop.jpg new file mode 100644 index 00000000..1f747323 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-the-white-lotus-2021-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-the-white-lotus-2021-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-the-white-lotus-2021-poster.jpg new file mode 100644 index 00000000..2f23d1fa Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-the-white-lotus-2021-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-the-witcher-2019-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-the-witcher-2019-backdrop.jpg new file mode 100644 index 00000000..acca834e Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-the-witcher-2019-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-the-witcher-2019-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-the-witcher-2019-poster.jpg new file mode 100644 index 00000000..f5eb8f59 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-the-witcher-2019-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-upload-2020-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-upload-2020-backdrop.jpg new file mode 100644 index 00000000..f350a49c Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-upload-2020-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-upload-2020-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-upload-2020-poster.jpg new file mode 100644 index 00000000..547d3b7a Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-upload-2020-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-widow-s-bay-2026-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-widow-s-bay-2026-backdrop.jpg new file mode 100644 index 00000000..03b1c335 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-widow-s-bay-2026-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-widow-s-bay-2026-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-widow-s-bay-2026-poster.jpg new file mode 100644 index 00000000..8c02a0d7 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-widow-s-bay-2026-poster.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-yellowjackets-2021-backdrop.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-yellowjackets-2021-backdrop.jpg new file mode 100644 index 00000000..960c2d23 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-yellowjackets-2021-backdrop.jpg differ diff --git a/app/src/debug/assets/wolfskin-titles/assets/tv-yellowjackets-2021-poster.jpg b/app/src/debug/assets/wolfskin-titles/assets/tv-yellowjackets-2021-poster.jpg new file mode 100644 index 00000000..c7e16a57 Binary files /dev/null and b/app/src/debug/assets/wolfskin-titles/assets/tv-yellowjackets-2021-poster.jpg differ diff --git a/app/src/debug/java/org/justinvisser/wolfskin/tv/DebugHome.kt b/app/src/debug/java/org/justinvisser/wolfskin/tv/DebugHome.kt new file mode 100644 index 00000000..691f67c4 --- /dev/null +++ b/app/src/debug/java/org/justinvisser/wolfskin/tv/DebugHome.kt @@ -0,0 +1,8 @@ +package org.justinvisser.wolfskin.tv + +import android.content.Context +import org.justinvisser.wolfskin.design.HomeFixture +import org.justinvisser.wolfskin.design.HomeSnapshot + +/** Only debug builds may read the locked prototype household projection. */ +fun debugHomeSnapshot(context: Context, person: String): HomeSnapshot? = HomeFixture(context).snapshot(person) diff --git a/app/src/default/AndroidManifest.xml b/app/src/default/AndroidManifest.xml new file mode 100644 index 00000000..c59612c7 --- /dev/null +++ b/app/src/default/AndroidManifest.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/app/src/default/res/mipmap-anydpi-v26/ic_banner.xml b/app/src/default/res/mipmap-anydpi-v26/ic_banner.xml new file mode 100644 index 00000000..ec3f55e3 --- /dev/null +++ b/app/src/default/res/mipmap-anydpi-v26/ic_banner.xml @@ -0,0 +1,4 @@ + + diff --git a/app/src/default/res/mipmap-hdpi/ic_launcher.webp b/app/src/default/res/mipmap-hdpi/ic_launcher.webp new file mode 100644 index 00000000..4ac23262 Binary files /dev/null and b/app/src/default/res/mipmap-hdpi/ic_launcher.webp differ diff --git a/app/src/default/res/mipmap-hdpi/ic_launcher_foreground.webp b/app/src/default/res/mipmap-hdpi/ic_launcher_foreground.webp new file mode 100644 index 00000000..de1628cc Binary files /dev/null and b/app/src/default/res/mipmap-hdpi/ic_launcher_foreground.webp differ diff --git a/app/src/default/res/mipmap-hdpi/ic_launcher_round.webp b/app/src/default/res/mipmap-hdpi/ic_launcher_round.webp new file mode 100644 index 00000000..df5faba9 Binary files /dev/null and b/app/src/default/res/mipmap-hdpi/ic_launcher_round.webp differ diff --git a/app/src/default/res/mipmap-mdpi/ic_launcher.webp b/app/src/default/res/mipmap-mdpi/ic_launcher.webp new file mode 100644 index 00000000..415cf194 Binary files /dev/null and b/app/src/default/res/mipmap-mdpi/ic_launcher.webp differ diff --git a/app/src/default/res/mipmap-mdpi/ic_launcher_foreground.webp b/app/src/default/res/mipmap-mdpi/ic_launcher_foreground.webp new file mode 100644 index 00000000..d9df942a Binary files /dev/null and b/app/src/default/res/mipmap-mdpi/ic_launcher_foreground.webp differ diff --git a/app/src/default/res/mipmap-mdpi/ic_launcher_round.webp b/app/src/default/res/mipmap-mdpi/ic_launcher_round.webp new file mode 100644 index 00000000..dea8ff64 Binary files /dev/null and b/app/src/default/res/mipmap-mdpi/ic_launcher_round.webp differ diff --git a/app/src/default/res/mipmap-xhdpi/ic_banner.png b/app/src/default/res/mipmap-xhdpi/ic_banner.png new file mode 100644 index 00000000..ee42b91e Binary files /dev/null and b/app/src/default/res/mipmap-xhdpi/ic_banner.png differ diff --git a/app/src/default/res/mipmap-xhdpi/ic_banner_foreground.png b/app/src/default/res/mipmap-xhdpi/ic_banner_foreground.png new file mode 100644 index 00000000..ee42b91e Binary files /dev/null and b/app/src/default/res/mipmap-xhdpi/ic_banner_foreground.png differ diff --git a/app/src/default/res/mipmap-xhdpi/ic_launcher.webp b/app/src/default/res/mipmap-xhdpi/ic_launcher.webp new file mode 100644 index 00000000..924b40eb Binary files /dev/null and b/app/src/default/res/mipmap-xhdpi/ic_launcher.webp differ diff --git a/app/src/default/res/mipmap-xhdpi/ic_launcher_foreground.webp b/app/src/default/res/mipmap-xhdpi/ic_launcher_foreground.webp new file mode 100644 index 00000000..e218f8bd Binary files /dev/null and b/app/src/default/res/mipmap-xhdpi/ic_launcher_foreground.webp differ diff --git a/app/src/default/res/mipmap-xhdpi/ic_launcher_round.webp b/app/src/default/res/mipmap-xhdpi/ic_launcher_round.webp new file mode 100644 index 00000000..40674eff Binary files /dev/null and b/app/src/default/res/mipmap-xhdpi/ic_launcher_round.webp differ diff --git a/app/src/default/res/mipmap-xxhdpi/ic_launcher.webp b/app/src/default/res/mipmap-xxhdpi/ic_launcher.webp new file mode 100644 index 00000000..6f5be441 Binary files /dev/null and b/app/src/default/res/mipmap-xxhdpi/ic_launcher.webp differ diff --git a/app/src/default/res/mipmap-xxhdpi/ic_launcher_foreground.webp b/app/src/default/res/mipmap-xxhdpi/ic_launcher_foreground.webp new file mode 100644 index 00000000..8c1935c7 Binary files /dev/null and b/app/src/default/res/mipmap-xxhdpi/ic_launcher_foreground.webp differ diff --git a/app/src/default/res/mipmap-xxhdpi/ic_launcher_round.webp b/app/src/default/res/mipmap-xxhdpi/ic_launcher_round.webp new file mode 100644 index 00000000..48a4e286 Binary files /dev/null and b/app/src/default/res/mipmap-xxhdpi/ic_launcher_round.webp differ diff --git a/app/src/default/res/mipmap-xxxhdpi/ic_launcher.webp b/app/src/default/res/mipmap-xxxhdpi/ic_launcher.webp new file mode 100644 index 00000000..1cf49fb6 Binary files /dev/null and b/app/src/default/res/mipmap-xxxhdpi/ic_launcher.webp differ diff --git a/app/src/default/res/mipmap-xxxhdpi/ic_launcher_foreground.webp b/app/src/default/res/mipmap-xxxhdpi/ic_launcher_foreground.webp new file mode 100644 index 00000000..afc41a8b Binary files /dev/null and b/app/src/default/res/mipmap-xxxhdpi/ic_launcher_foreground.webp differ diff --git a/app/src/default/res/mipmap-xxxhdpi/ic_launcher_round.webp b/app/src/default/res/mipmap-xxxhdpi/ic_launcher_round.webp new file mode 100644 index 00000000..122a33e0 Binary files /dev/null and b/app/src/default/res/mipmap-xxxhdpi/ic_launcher_round.webp differ diff --git a/app/src/default/res/values-hu/strings.xml b/app/src/default/res/values-hu/strings.xml new file mode 100644 index 00000000..fc653df6 --- /dev/null +++ b/app/src/default/res/values-hu/strings.xml @@ -0,0 +1,6 @@ + + + Wolfskin alapรฉrtelmezett beรกllรญtรกsa + Wolfskin kompakt elrendezรฉs + A Wolfskin frissรผlt a %s verziรณra + diff --git a/app/src/default/res/values-pl/strings.xml b/app/src/default/res/values-pl/strings.xml new file mode 100644 index 00000000..e334b3ba --- /dev/null +++ b/app/src/default/res/values-pl/strings.xml @@ -0,0 +1,4 @@ + + + O Wolfskin + diff --git a/app/src/default/res/values/strings.xml b/app/src/default/res/values/strings.xml new file mode 100644 index 00000000..dd5ba542 --- /dev/null +++ b/app/src/default/res/values/strings.xml @@ -0,0 +1,8 @@ + + + Wolfskin + Wolfskin + Wolfskin Default + Wolfskin Compact + Wolfskin updated to %s + diff --git a/app/src/main/java/com/github/damontecres/wholphin/MainActivity.kt b/app/src/main/java/com/github/damontecres/wholphin/MainActivity.kt index a1410d0b..ec61583d 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/MainActivity.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/MainActivity.kt @@ -66,7 +66,6 @@ import com.github.damontecres.wholphin.ui.nav.Destination import com.github.damontecres.wholphin.ui.playback.PlayExternalViewModel import com.github.damontecres.wholphin.ui.showToast import com.github.damontecres.wholphin.ui.theme.WholphinTheme -import com.github.damontecres.wholphin.ui.theme.colors.WolfskinThemeColors import com.github.damontecres.wholphin.ui.util.ProvideLocalClock import com.github.damontecres.wholphin.util.DebugLogTree import com.github.damontecres.wholphin.util.ExceptionHandler @@ -234,7 +233,7 @@ class MainActivity : AppCompatActivity() { viewModel.appStart(intent) setContent { - MaterialTheme(colorScheme = WolfskinThemeColors.darkScheme) { + MaterialTheme { Surface(Modifier.fillMaxSize()) { val userPreferences by userPreferencesService.flow.collectAsState(null) if (userPreferences == null) { diff --git a/app/src/main/java/com/github/damontecres/wholphin/MainContent.kt b/app/src/main/java/com/github/damontecres/wholphin/MainContent.kt index 26dda908..fcaa3165 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/MainContent.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/MainContent.kt @@ -34,7 +34,7 @@ import com.github.damontecres.wholphin.services.NavigationManager import com.github.damontecres.wholphin.services.ScreensaverService import com.github.damontecres.wholphin.services.SetupDestination import com.github.damontecres.wholphin.ui.components.AppScreensaver -import com.github.damontecres.wholphin.ui.nav.ApplicationContent +import org.justinvisser.wolfskin.tv.WolfskinApp import com.github.damontecres.wholphin.ui.setup.SwitchServerContent import com.github.damontecres.wholphin.ui.setup.SwitchUserContent import com.github.damontecres.wholphin.ui.util.InterfaceCustomization @@ -111,7 +111,7 @@ fun MainContent( } if (showContent) { - ApplicationContent( + WolfskinApp( user = current.user, server = current.server, navigationManager = navigationManager, diff --git a/app/src/main/java/com/github/damontecres/wholphin/preferences/AppPreference.kt b/app/src/main/java/com/github/damontecres/wholphin/preferences/AppPreference.kt index 63761d99..b6d9426c 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/preferences/AppPreference.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/preferences/AppPreference.kt @@ -557,7 +557,7 @@ sealed interface AppPreference { val ThemeColors = AppChoicePreference( title = R.string.app_theme, - defaultValue = AppThemeColors.WOLFSKIN, + defaultValue = AppThemeColors.PURPLE, getter = { it.interfacePreferences.appThemeColors }, setter = { prefs, value -> prefs.updateInterfacePreferences { appThemeColors = value } @@ -647,6 +647,19 @@ sealed interface AppPreference { destination = Destination.Settings(PreferenceScreenOption.ADVANCED), ) + val WolfskinScreens = + AppSwitchPreference( + title = R.string.wolfskin_screens, + defaultValue = true, + getter = { org.justinvisser.wolfskin.tv.WolfskinScreenPreference.enabled }, + setter = { prefs, value -> + org.justinvisser.wolfskin.tv.WolfskinScreenPreference.enabled = value + prefs + }, + summaryOn = R.string.enabled, + summaryOff = R.string.disabled, + ) + val UserProfileSettings = AppDestinationPreference( title = R.string.override_user_profile_settings, @@ -1306,6 +1319,7 @@ val advancedPreferences = title = R.string.ui_interface, preferences = listOf( + AppPreference.WolfskinScreens, AppPreference.ShowClock, AppPreference.BackdropStylePref, AppPreference.ShowLogos, diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/cards/WatchedIcon.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/cards/WatchedIcon.kt index 17649be9..ce8952a7 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/cards/WatchedIcon.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/cards/WatchedIcon.kt @@ -41,7 +41,6 @@ fun WatchedIconBackground(): Color = when (LocalTheme.current) { AppThemeColors.UNRECOGNIZED, AppThemeColors.PURPLE, - AppThemeColors.WOLFSKIN, AppThemeColors.BLUE, AppThemeColors.GREEN, AppThemeColors.ORANGE, @@ -56,8 +55,6 @@ fun WatchedIconBackground(): Color = @Composable fun WatchedIconColor(): Color = when (LocalTheme.current) { - AppThemeColors.WOLFSKIN -> MaterialTheme.colorScheme.onPrimary - AppThemeColors.UNRECOGNIZED, AppThemeColors.PURPLE, AppThemeColors.BLUE, diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/components/SliderBar.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/components/SliderBar.kt index f2addcd8..9021e213 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/components/SliderBar.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/components/SliderBar.kt @@ -143,7 +143,6 @@ fun sliderActiveColor(focused: Boolean): Color { return when (theme) { AppThemeColors.UNRECOGNIZED, AppThemeColors.PURPLE, - AppThemeColors.WOLFSKIN, AppThemeColors.BLUE, AppThemeColors.GREEN, AppThemeColors.ORANGE, @@ -180,7 +179,6 @@ fun sliderInactiveColor(focused: Boolean): Color { return when (theme) { AppThemeColors.UNRECOGNIZED, AppThemeColors.PURPLE, - AppThemeColors.WOLFSKIN, -> { MaterialTheme.colorScheme.border .copy(alpha = .25f) diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/nav/Destination.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/nav/Destination.kt index 110cb637..5bef2675 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/nav/Destination.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/nav/Destination.kt @@ -35,6 +35,9 @@ import java.util.UUID sealed class Destination( val fullScreen: Boolean = false, ) : NavKey { + @Serializable + data class Wolfskin(val route: String) : Destination(false) + @Serializable data class Home( val id: Long = 0L, diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/nav/DestinationContent.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/nav/DestinationContent.kt index 63789d6c..3e449875 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/nav/DestinationContent.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/nav/DestinationContent.kt @@ -69,6 +69,10 @@ fun DestinationContent( LaunchedEffect(Unit) { onClearBackdrop.invoke() } } when (destination) { + is Destination.Wolfskin -> { + org.justinvisser.wolfskin.tv.WolfskinDestinationContent(destination.route, modifier) + } + is Destination.Home -> { HomePage( preferences = preferences, diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/nav/NavDrawer.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/nav/NavDrawer.kt index c26cb891..100b6caf 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/nav/NavDrawer.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/nav/NavDrawer.kt @@ -771,7 +771,6 @@ fun navItemColor( when (theme) { AppThemeColors.UNRECOGNIZED, AppThemeColors.PURPLE, - AppThemeColors.WOLFSKIN, AppThemeColors.BLUE, AppThemeColors.GREEN, AppThemeColors.ORANGE, diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/preferences/SwitchPreference.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/preferences/SwitchPreference.kt index 43e213ea..daf6fa07 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/preferences/SwitchPreference.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/preferences/SwitchPreference.kt @@ -70,7 +70,6 @@ fun SwitchColors(): SwitchColors { return when (theme) { AppThemeColors.UNRECOGNIZED, AppThemeColors.PURPLE, - AppThemeColors.WOLFSKIN, AppThemeColors.BLUE, -> { SwitchDefaults.colors() diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/theme/Theme.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/theme/Theme.kt index 8cce37e5..8ae95b25 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/theme/Theme.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/theme/Theme.kt @@ -13,10 +13,9 @@ import com.github.damontecres.wholphin.ui.theme.colors.OledThemeColors import com.github.damontecres.wholphin.ui.theme.colors.OrangeThemeColors import com.github.damontecres.wholphin.ui.theme.colors.PurpleThemeColors import com.github.damontecres.wholphin.ui.theme.colors.RedThemeColors -import com.github.damontecres.wholphin.ui.theme.colors.WolfskinThemeColors val LocalTheme = - compositionLocalOf { AppThemeColors.WOLFSKIN } + compositionLocalOf { AppThemeColors.PURPLE } fun getThemeColors(appThemeColors: AppThemeColors): ThemeColors = when (appThemeColors) { @@ -28,14 +27,13 @@ fun getThemeColors(appThemeColors: AppThemeColors): ThemeColors = AppThemeColors.BOLD_BLUE -> BoldBlueThemeColors AppThemeColors.RED -> RedThemeColors AppThemeColors.BROWN -> BrownThemeColors - AppThemeColors.WOLFSKIN -> WolfskinThemeColors - AppThemeColors.UNRECOGNIZED -> WolfskinThemeColors + AppThemeColors.UNRECOGNIZED -> PurpleThemeColors } @Composable fun WholphinTheme( darkTheme: Boolean = true, - appThemeColors: AppThemeColors = AppThemeColors.WOLFSKIN, + appThemeColors: AppThemeColors = AppThemeColors.PURPLE, content: @Composable () -> Unit, ) { val themeColors = getThemeColors(appThemeColors) diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/theme/colors/WolfskinThemeColors.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/theme/colors/WolfskinThemeColors.kt deleted file mode 100644 index ee0a77b5..00000000 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/theme/colors/WolfskinThemeColors.kt +++ /dev/null @@ -1,59 +0,0 @@ -package com.github.damontecres.wholphin.ui.theme.colors - -import androidx.compose.ui.graphics.Color -import com.github.damontecres.wholphin.ui.theme.ThemeColors - -/** Lilac accents on near-black surfaces, with upstream Purple available separately. */ -val WolfskinThemeColors = - object : ThemeColors { - private val background = Color(0xFF07070A) - private val lilac = Color(0xFFD2BCFF) - private val onLilac = Color(0xFF241334) - private val container = Color(0xFF382A49) - private val onContainer = Color(0xFFEADCFF) - private val surfaceVariant = Color(0xFF24202D) - - override val lightSchemeMaterial = PurpleThemeColors.lightSchemeMaterial - override val lightScheme = PurpleThemeColors.lightScheme - - override val darkSchemeMaterial = - PurpleThemeColors.darkSchemeMaterial.copy( - primary = lilac, - onPrimary = onLilac, - primaryContainer = container, - onPrimaryContainer = onContainer, - secondary = lilac, - onSecondary = onLilac, - secondaryContainer = container, - onSecondaryContainer = onContainer, - tertiary = lilac, - onTertiary = onLilac, - tertiaryContainer = container, - onTertiaryContainer = onContainer, - background = background, - surface = background, - surfaceVariant = surfaceVariant, - inversePrimary = Color(0xFF705090), - ) - - override val darkScheme = - PurpleThemeColors.darkScheme.copy( - primary = lilac, - onPrimary = onLilac, - primaryContainer = container, - onPrimaryContainer = onContainer, - secondary = lilac, - onSecondary = onLilac, - secondaryContainer = container, - onSecondaryContainer = onContainer, - tertiary = lilac, - onTertiary = onLilac, - tertiaryContainer = container, - onTertiaryContainer = onContainer, - background = background, - surface = background, - surfaceVariant = surfaceVariant, - inversePrimary = Color(0xFF705090), - border = lilac.copy(alpha = .75f), - ) - } diff --git a/app/src/main/proto/WholphinDataStore.proto b/app/src/main/proto/WholphinDataStore.proto index 55553166..910853e9 100644 --- a/app/src/main/proto/WholphinDataStore.proto +++ b/app/src/main/proto/WholphinDataStore.proto @@ -128,7 +128,7 @@ enum AppThemeColors { OLED_BLACK = 5; RED = 6; BROWN = 7; - WOLFSKIN = 8; + reserved 8; } enum EdgeStyle{ diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_banner.xml b/app/src/main/res/mipmap-anydpi-v26/ic_banner.xml index ec3f55e3..4c5f707b 100644 --- a/app/src/main/res/mipmap-anydpi-v26/ic_banner.xml +++ b/app/src/main/res/mipmap-anydpi-v26/ic_banner.xml @@ -1,4 +1,9 @@ - + + + + + + diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/app/src/main/res/mipmap-hdpi/ic_launcher.webp index 4ac23262..5b7669dc 100644 Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher.webp and b/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp index de1628cc..8e05a03a 100644 Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp and b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp index df5faba9..e6a5972a 100644 Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/app/src/main/res/mipmap-mdpi/ic_launcher.webp index 415cf194..f44d1093 100644 Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher.webp and b/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp index d9df942a..9e9214e8 100644 Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp and b/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp index dea8ff64..3766935e 100644 Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_banner.png b/app/src/main/res/mipmap-xhdpi/ic_banner.png index ee42b91e..4fa742db 100644 Binary files a/app/src/main/res/mipmap-xhdpi/ic_banner.png and b/app/src/main/res/mipmap-xhdpi/ic_banner.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_banner_foreground.png b/app/src/main/res/mipmap-xhdpi/ic_banner_foreground.png index ee42b91e..52b72c47 100644 Binary files a/app/src/main/res/mipmap-xhdpi/ic_banner_foreground.png and b/app/src/main/res/mipmap-xhdpi/ic_banner_foreground.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp index 924b40eb..ce75a196 100644 Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp and b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp index e218f8bd..22298ad1 100644 Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp and b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp index 40674eff..3f7c7e29 100644 Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp index 6f5be441..e5cef34d 100644 Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp index 8c1935c7..fafcb4f1 100644 Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp index 48a4e286..5c1a8e36 100644 Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp index 1cf49fb6..90341396 100644 Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp index afc41a8b..dbe5821e 100644 Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp index 122a33e0..2ef5c7d0 100644 Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3783bfdf..1fadeac7 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,6 +1,6 @@ - Wolfskin - Wolfskin + Wholphin + Wholphin About Active Recordings @@ -604,8 +604,8 @@ Fill Fill width Fill height - Wolfskin Default - Wolfskin Compact + Wholphin Default + Wholphin Compact Series Thumb images Episode Thumbnail images @@ -637,7 +637,6 @@ @string/black @string/red @string/brown - @string/wolfskin_theme Ignore @@ -831,7 +830,7 @@ Select all Separate types Prefer showing logos for titles - Wolfskin updated to %s + Wholphin updated to %s Remove from continue watching Remove series from next up View series removed from next up diff --git a/app/src/main/res/values/wolfskin.xml b/app/src/main/res/values/wolfskin.xml index 2aca4d36..0308ae9e 100644 --- a/app/src/main/res/values/wolfskin.xml +++ b/app/src/main/res/values/wolfskin.xml @@ -1,6 +1,6 @@ - Wolfskin + Wolfskin screens based on Wholphin by damontecres https://github.com/damontecres/Wholphin diff --git a/app/src/release/java/org/justinvisser/wolfskin/tv/DebugHome.kt b/app/src/release/java/org/justinvisser/wolfskin/tv/DebugHome.kt new file mode 100644 index 00000000..b49e7828 --- /dev/null +++ b/app/src/release/java/org/justinvisser/wolfskin/tv/DebugHome.kt @@ -0,0 +1,8 @@ +package org.justinvisser.wolfskin.tv + +import android.content.Context +import org.justinvisser.wolfskin.design.HomeSnapshot + +/** Release Home always reads the selected Jellyfin identity, never prototype data. */ +@Suppress("UNUSED_PARAMETER") +fun debugHomeSnapshot(context: Context, person: String): HomeSnapshot? = null diff --git a/app/src/test/java/com/github/damontecres/wholphin/ui/WolfskinThemeColorsTest.kt b/app/src/test/java/com/github/damontecres/wholphin/ui/WolfskinThemeColorsTest.kt index 3ef4ad20..e262e2ad 100644 --- a/app/src/test/java/com/github/damontecres/wholphin/ui/WolfskinThemeColorsTest.kt +++ b/app/src/test/java/com/github/damontecres/wholphin/ui/WolfskinThemeColorsTest.kt @@ -2,7 +2,7 @@ package com.github.damontecres.wholphin.ui import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.luminance -import com.github.damontecres.wholphin.ui.theme.colors.WolfskinThemeColors +import org.justinvisser.wolfskin.design.WolfskinColors import org.junit.Assert.assertTrue import org.junit.Test @@ -10,8 +10,8 @@ import org.junit.Test class WolfskinThemeColorsTest { @Test fun darkPaletteHasReadableNormalAndFocusedText() { - val television = WolfskinThemeColors.darkScheme - val material = WolfskinThemeColors.darkSchemeMaterial + val television = WolfskinColors.darkScheme + val material = WolfskinColors.darkSchemeMaterial val textAndBackgrounds = listOf( television.onBackground to television.background, diff --git a/app/src/test/java/org/justinvisser/wolfskin/tv/DiscoverLoadingFocusTest.kt b/app/src/test/java/org/justinvisser/wolfskin/tv/DiscoverLoadingFocusTest.kt new file mode 100644 index 00000000..b18f6a22 --- /dev/null +++ b/app/src/test/java/org/justinvisser/wolfskin/tv/DiscoverLoadingFocusTest.kt @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: GPL-2.0-only +package org.justinvisser.wolfskin.tv + +import android.app.Application +import androidx.activity.ComponentActivity +import androidx.compose.ui.input.key.Key +import androidx.compose.ui.test.junit4.createAndroidComposeRule +import androidx.compose.ui.test.onNodeWithTag +import androidx.compose.ui.test.performKeyInput +import androidx.compose.ui.test.pressKey +import kotlinx.coroutines.CompletableDeferred +import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse +import org.junit.Assert.assertNotNull +import org.junit.Assert.assertTrue +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.justinvisser.wolfskin.design.DiscoverFixture +import org.justinvisser.wolfskin.design.DiscoverScreen +import org.justinvisser.wolfskin.design.DiscoverState +import org.justinvisser.wolfskin.design.DiscoverStatus +import org.justinvisser.wolfskin.design.ShellPerson +import org.justinvisser.wolfskin.design.ShellState +import org.justinvisser.wolfskin.design.ShellSurface +import org.justinvisser.wolfskin.design.WolfskinTheme +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config +import org.robolectric.annotation.GraphicsMode + +/** The real asynchronous host must return focus from its loading nav to the first loaded action. */ +@RunWith(RobolectricTestRunner::class) +@Config(sdk = [34], application = Application::class, qualifiers = "w960dp-h540dp-xhdpi") +@GraphicsMode(GraphicsMode.Mode.NATIVE) +class DiscoverLoadingFocusTest { + @get:Rule val rule = createAndroidComposeRule() + + @Test fun firstOkAfterLoadingOpensTheHeroInsteadOfSelectingTheNav() { + val pending = CompletableDeferred() + val shell = ShellState(listOf(ShellPerson("justin", "Justin", "J", true)), "justin").apply { + pickerVisible = false + enterDestination("discover") + } + lateinit var current: DiscoverState + rule.setContent { + val state = rememberDiscoverState(shell, shell::enterDestination, { shell.enterDestination("discover") }, loadFixture = { pending.await() }) + current = state + WolfskinTheme { ShellSurface(shell) { DiscoverScreen(state, it) } } + } + rule.runOnIdle { + assertEquals(DiscoverStatus.Loading, current.snapshot.status) + assertTrue(shell.navFocused) + val json = rule.activity.assets.open("wolfskin-discover/fixture.json").bufferedReader().use { it.readText() } + pending.complete(DiscoverFixture(json) { "file:///android_asset/wolfskin-discover/$it" }) + } + rule.waitForIdle() + rule.runOnIdle { + assertEquals(DiscoverStatus.Ready, current.snapshot.status) + assertFalse(shell.navFocused) + assertEquals(0, current.focusedRow) + } + rule.onNodeWithTag("wolfskin-shell").performKeyInput { pressKey(Key.DirectionCenter) } + rule.runOnIdle { + assertNotNull(current.title) + assertEquals("The Amazing Spider-Man", current.title!!.title) + assertEquals("discover-title/${current.title!!.key}", shell.route) + } + } + + @Test fun finishingLoadPreservesANavTargetChosenWhileLoading() { + val pending = CompletableDeferred() + val shell = ShellState(listOf(ShellPerson("justin", "Justin", "J", true)), "justin").apply { + pickerVisible = false + enterDestination("discover") + } + lateinit var current: DiscoverState + rule.setContent { + val state = rememberDiscoverState(shell, shell::enterDestination, { shell.enterDestination("discover") }, loadFixture = { pending.await() }) + current = state + WolfskinTheme { ShellSurface(shell) { DiscoverScreen(state, it) } } + } + rule.onNodeWithTag("wolfskin-shell").performKeyInput { pressKey(Key.DirectionRight) } + rule.runOnIdle { + assertEquals(DiscoverStatus.Loading, current.snapshot.status) + assertEquals(2, shell.navIndex) + val json = rule.activity.assets.open("wolfskin-discover/fixture.json").bufferedReader().use { it.readText() } + pending.complete(DiscoverFixture(json) { "file:///android_asset/wolfskin-discover/$it" }) + } + rule.waitForIdle() + rule.runOnIdle { + assertEquals(DiscoverStatus.Ready, current.snapshot.status) + assertTrue(shell.navFocused) + assertEquals(2, shell.navIndex) + } + rule.onNodeWithTag("wolfskin-shell").performKeyInput { pressKey(Key.DirectionCenter) } + rule.runOnIdle { + assertEquals("movies", shell.route) + assertEquals(null, current.title) + } + } +} diff --git a/app/src/test/java/org/justinvisser/wolfskin/tv/HomeLibraryCacheTest.kt b/app/src/test/java/org/justinvisser/wolfskin/tv/HomeLibraryCacheTest.kt new file mode 100644 index 00000000..49fc269f --- /dev/null +++ b/app/src/test/java/org/justinvisser/wolfskin/tv/HomeLibraryCacheTest.kt @@ -0,0 +1,29 @@ +package org.justinvisser.wolfskin.tv + +import android.app.Application +import androidx.test.core.app.ApplicationProvider +import org.junit.Assert.* +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config +import org.justinvisser.wolfskin.design.HomeLibrary +import org.justinvisser.wolfskin.design.HomeTitle +import org.justinvisser.wolfskin.tv.read.HomeLibraryCache + +/** A reopened Home cache preserves playable identity and episode/resume state without network reads. */ +@RunWith(RobolectricTestRunner::class) +@Config(sdk = [34], application = Application::class) +class HomeLibraryCacheTest { + @Test fun savedHomeReopensWithEpisodeMetadataAndFullShelfCount() { + val context = ApplicationProvider.getApplicationContext() + val episode = HomeTitle("episode-id", "The next episode", "episode", year = 2025, runtimeSeconds = 1800, overview = "Overview", poster = "poster", backdrop = "backdrop", seriesTitle = "A series", season = 2, episode = 3, resumeSeconds = 125.5, addedAt = "2026-11-05", genres = listOf("Drama"), held = true, tmdbId = 42) + val film = HomeTitle("film-id", "A film", "movie", year = 2024, runtimeSeconds = 5400, played = true, held = true, tmdbId = 43) + val library = HomeLibrary(listOf(episode), listOf(episode.copy(id = "next", resumeSeconds = 0.0)), listOf(film), mapOf("movies" to listOf(film)), mapOf("movies" to 84)) + HomeLibraryCache(context).write("server:person", library, 12345L) + val saved = HomeLibraryCache(context).read("server:person")!! + assertEquals(library, saved.first) + assertEquals(12345L, saved.second) + assertNull(HomeLibraryCache(context).read("server:someone-else")) + } +} diff --git a/app/src/test/java/org/justinvisser/wolfskin/tv/HomeRecoveryTest.kt b/app/src/test/java/org/justinvisser/wolfskin/tv/HomeRecoveryTest.kt new file mode 100644 index 00000000..864c1743 --- /dev/null +++ b/app/src/test/java/org/justinvisser/wolfskin/tv/HomeRecoveryTest.kt @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: GPL-2.0-only +package org.justinvisser.wolfskin.tv + +import android.app.Application +import androidx.test.core.app.ApplicationProvider +import com.github.damontecres.wholphin.data.model.JellyfinServer +import com.github.damontecres.wholphin.data.model.JellyfinUser +import com.github.damontecres.wholphin.services.NavigationManager +import io.mockk.coEvery +import io.mockk.every +import io.mockk.mockk +import java.io.IOException +import java.util.UUID +import kotlinx.coroutines.CompletableDeferred +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.async +import kotlinx.coroutines.runBlocking +import org.junit.Assert.* +import org.junit.Test +import org.junit.runner.RunWith +import org.justinvisser.wolfskin.design.* +import org.justinvisser.wolfskin.tv.read.HomeLibraryCache +import org.justinvisser.wolfskin.tv.read.HomeReadFacade +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config + +/** Saved Home projections survive outages but never survive an authenticated identity change. */ +@RunWith(RobolectricTestRunner::class) +@Config(sdk = [34], application = Application::class) +class HomeRecoveryTest { + private val context = ApplicationProvider.getApplicationContext() + private val server = JellyfinServer(UUID.fromString("00000000-0000-0000-0000-000000000001"), "Fixture", "https://example.invalid", null) + private val personA = JellyfinUser(id = UUID.fromString("00000000-0000-0000-0000-000000000002"), name = "Justin", serverId = server.id, accessToken = null) + private val personB = personA.copy(id = UUID.fromString("00000000-0000-0000-0000-000000000003"), name = "Mindel") + private val film = HomeTitle("private-film", "Person A film", "movie", held = true, runtimeSeconds = 5400) + private val library = HomeLibrary(resume = listOf(film)) + + @Test fun savedHomePaintsBeforeRefreshAndStaysAfterFailedRetry() = runBlocking { + val cache = HomeLibraryCache(context) + cache.write("${server.id}:${personA.id}", library, 1000L) + val started = CompletableDeferred() + val response = CompletableDeferred() + val facade = mockk() + coEvery { facade.read(personA.id) } coAnswers { started.complete(Unit); response.await() } + val model = WolfskinHomeViewModel(context, facade, cache, NavigationManager(), WolfskinSeeAllLists()) + val refresh = async(Dispatchers.IO) { model.loadLibrary(server, personA, "justin", retry = true) } + started.await() + assertEquals(film.id, model.snapshot.rows.first().cards.first().id) + response.completeExceptionally(IOException("fixture offline")) + refresh.await() + assertFalse(model.snapshot.jellyfinAvailable) + assertEquals(film.id, model.snapshot.rows.first().cards.first().id) + assertNotNull(model.snapshot.savedAt) + assertEquals(RecoveryMessage.StillUnreachable, model.toast) + } + + @Test fun personBSeesNeitherPersonAsSavedHomeNorTheirLateRefreshResult() = runBlocking { + val facade = mockk() + val cache = HomeLibraryCache(context) + cache.write("${server.id}:${personA.id}", library, 1000L) + val startedA = CompletableDeferred() + val responseA = CompletableDeferred() + coEvery { facade.read(personA.id) } coAnswers { startedA.complete(Unit); responseA.await() } + coEvery { facade.read(personB.id) } throws IOException("fixture offline") + val model = WolfskinHomeViewModel(context, facade, cache, NavigationManager(), WolfskinSeeAllLists()) + val requestA = async(Dispatchers.IO) { model.loadLibrary(server, personA, "justin") } + startedA.await() + assertTrue(model.snapshot.rows.any { row -> row.cards.any { it.id == film.id } }) + model.loadLibrary(server, personB, "mindel") + assertFalse(model.snapshot.rows.any { row -> row.cards.any { it.id == film.id } }) + assertNull(model.snapshot.savedAt) + assertTrue(model.snapshot.rows.any { it.kind == HomeRowKind.State && it.focusable }) + responseA.complete(library) + requestA.await() + assertFalse(model.snapshot.rows.any { row -> row.cards.any { it.id == film.id } }) + assertFalse(model.snapshot.jellyfinAvailable) + } + + @Test fun readableJellyfinDoesNotBecomeAnOutageWhenLocalCacheCannotBeWritten() = runBlocking { + val facade = mockk() + coEvery { facade.read(personA.id) } returns library + val cache = mockk() + every { cache.read(any()) } returns null + every { cache.write(any(), any(), any()) } throws IOException("fixture disk full") + val model = WolfskinHomeViewModel(context, facade, cache, NavigationManager(), WolfskinSeeAllLists()) + model.loadLibrary(server, personA, "justin") + assertTrue(model.snapshot.jellyfinAvailable) + assertEquals(film.id, model.snapshot.rows.first().cards.first().id) + assertNull(model.toast) + } +} diff --git a/app/src/test/java/org/justinvisser/wolfskin/tv/HomeSeeAllNavigationTest.kt b/app/src/test/java/org/justinvisser/wolfskin/tv/HomeSeeAllNavigationTest.kt new file mode 100644 index 00000000..47f843b2 --- /dev/null +++ b/app/src/test/java/org/justinvisser/wolfskin/tv/HomeSeeAllNavigationTest.kt @@ -0,0 +1,130 @@ +package org.justinvisser.wolfskin.tv + +import android.app.Application +import androidx.activity.ComponentActivity +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.ui.input.key.Key +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.junit4.createAndroidComposeRule +import androidx.compose.ui.test.onNodeWithTag +import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.performKeyInput +import androidx.compose.ui.test.pressKey +import com.github.damontecres.wholphin.data.model.JellyfinServer +import com.github.damontecres.wholphin.data.model.JellyfinUser +import com.github.damontecres.wholphin.services.NavigationManager +import com.github.damontecres.wholphin.ui.nav.Destination +import io.mockk.mockk +import java.util.UUID +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue +import org.junit.Assert.assertSame +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.justinvisser.wolfskin.design.* +import org.justinvisser.wolfskin.tv.read.LibraryReadFacade +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config + +/** Home opens the complete shared grid and Back restores its original continuation card. */ +@RunWith(RobolectricTestRunner::class) +@Config(sdk = [34], application = Application::class, qualifiers = "w960dp-h540dp-xhdpi") +class HomeSeeAllNavigationTest { + @get:Rule val rule = createAndroidComposeRule() + + @Test fun personalMovieContinuationReachesTheEighteenthTitleAndReturnsToHome() = continuation("pk-m", 5) { grid -> + assertEquals(18, grid.items.size) + repeat(2) { press(Key.DirectionDown) } + repeat(5) { press(Key.DirectionRight) } + rule.onNodeWithText("Bleach the Movie: Fade to Black").assertIsDisplayed() + assertEquals("movie-bleach-the-movie-fade-to-black-2008", grid.focusedTitle?.id) + } + + @Test fun horizontallyScrolledContinuationRestoresTheExactHomeViewport() = continuation("trending", 20) { grid -> + press(Key.DirectionDown) + assertEquals(6, grid.index) + rule.onNodeWithTag("library-grid").assertIsDisplayed() + } + + private fun continuation(rowId: String, expectedColumn: Int, exerciseGrid: (LibraryGridState) -> Unit) { + rule.mainClock.autoAdvance = false + val snapshot = HomeFixture(rule.activity).snapshot("justin") + val row = snapshot.rows.first { it.id == rowId } + val cardTag = "home-card:$rowId:$expectedColumn" + val navigation = NavigationManager() + val lists = WolfskinSeeAllLists() + val shell = ShellState(listOf(ShellPerson("justin", "Justin", "J", true)), "justin") { + if (it == ShellAction.Pop) navigation.goBack() + }.apply { + pickerVisible = false + view.row = snapshot.rows.indexOf(row) + view.home.focusedKey = row.id + view.cards[row.id] = row.cards.size + } + val server = JellyfinServer(UUID.fromString("00000000-0000-0000-0000-000000000001"), "Fixture", "https://example.invalid", null) + val user = JellyfinUser(id = UUID.fromString("00000000-0000-0000-0000-000000000002"), name = "Justin", serverId = server.id, accessToken = null) + val model = WolfskinHomeViewModel(rule.activity, mockk(), mockk(), navigation, lists) + val facade = mockk() + rule.setContent { + val destination = navigation.backStack.last() + val route = (destination as? Destination.Wolfskin)?.route ?: "home" + LaunchedEffect(destination) { shell.enterDestination(route) } + WolfskinTheme { ShellSurface(shell) { modifier -> + if (destination is Destination.Home) HomeScreen(shell, snapshot, modifier) { model.act(it, shell, server, user) } + else WolfskinLibraryContent(rule.activity, route, shell, user, "fixture", facade, navigation, lists, modifier) + } } + } + settle() + rule.onNodeWithTag(cardTag).assertIsDisplayed() + val home = shell.view + val track = home.home.tracks.getValue(rowId) + val verticalIndex = home.listState.firstVisibleItemIndex + val verticalOffset = home.listState.firstVisibleItemScrollOffset + val rowOffset = home.listState.layoutInfo.visibleItemsInfo.first { it.key == rowId }.offset + val horizontalIndex = track.firstVisibleItemIndex + val horizontalOffset = track.firstVisibleItemScrollOffset + press(Key.DirectionCenter) + assertEquals("seeall/justin/$rowId", (navigation.backStack.last() as Destination.Wolfskin).route) + val grid = requireNotNull(lists.get("justin/$rowId")) + try { + rule.onNodeWithTag("library-grid").assertIsDisplayed() + exerciseGrid(grid) + press(Key.Back) + rule.waitForIdle() + assertTrue(navigation.backStack.last() is Destination.Home) + assertEquals(row.id, snapshot.rows[shell.view.row].id) + assertEquals(expectedColumn, shell.view.cards[row.id]) + assertSame("Home retains its original route memory", home, shell.view) + assertSame("Home retains its original horizontal state", track, home.home.tracks.getValue(rowId)) + assertEquals("Vertical first item", verticalIndex, home.listState.firstVisibleItemIndex) + assertEquals("Vertical pixel offset", verticalOffset, home.listState.firstVisibleItemScrollOffset) + assertEquals("Selected row pixel offset", rowOffset, home.listState.layoutInfo.visibleItemsInfo.first { it.key == rowId }.offset) + assertEquals("Horizontal first item", horizontalIndex, track.firstVisibleItemIndex) + assertEquals("Horizontal pixel offset", horizontalOffset, track.firstVisibleItemScrollOffset) + rule.onNodeWithTag(cardTag).assertIsDisplayed() + } catch (failure: AssertionError) { + throw AssertionError( + "Expected $rowId:$expectedColumn vertical=$verticalIndex/$verticalOffset row-offset=$rowOffset horizontal=$horizontalIndex/$horizontalOffset; " + + "actual route=${shell.route} row=${home.row} card=${home.cards[rowId]} nav=${shell.navFocused} handler=${shell.contentFocus?.javaClass?.simpleName} grid=${grid.index} " + + "vertical=${home.listState.firstVisibleItemIndex}/${home.listState.firstVisibleItemScrollOffset} horizontal=${track.firstVisibleItemIndex}/${track.firstVisibleItemScrollOffset} " + + "visible-rows=${home.listState.layoutInfo.visibleItemsInfo.map { it.key to it.offset }}", + failure, + ) + } + } + + private fun press(key: Key) { + rule.onNodeWithTag("wolfskin-shell").performKeyInput { pressKey(key) } + settle() + } + + private fun settle() { + repeat(3) { + rule.mainClock.advanceTimeByFrame() + rule.waitForIdle() + } + rule.mainClock.advanceTimeBy(1_000) + rule.waitForIdle() + } +} diff --git a/app/src/test/java/org/justinvisser/wolfskin/tv/LibrarySnapshotStoreTest.kt b/app/src/test/java/org/justinvisser/wolfskin/tv/LibrarySnapshotStoreTest.kt new file mode 100644 index 00000000..5363848c --- /dev/null +++ b/app/src/test/java/org/justinvisser/wolfskin/tv/LibrarySnapshotStoreTest.kt @@ -0,0 +1,49 @@ +package org.justinvisser.wolfskin.tv + +import android.app.Application +import kotlinx.coroutines.flow.toList +import kotlinx.coroutines.runBlocking +import org.junit.Assert.* +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config +import org.justinvisser.wolfskin.conductarr.MemoryCacheStore +import org.justinvisser.wolfskin.design.LibraryTitle +import org.justinvisser.wolfskin.tv.read.LibrarySnapshotStore + +/** A stale library remains readable offline without crossing server/person boundaries. */ +@RunWith(RobolectricTestRunner::class) +@Config(sdk = [34], application = Application::class) +class LibrarySnapshotStoreTest { + @Test fun savedCopyArrivesBeforeFailedRefreshAndFreshCopySkipsNetwork() = runBlocking { + var now = 1000L + val store = LibrarySnapshotStore(MemoryCacheStore()) { now } + val items = listOf(LibraryTitle("a", "Film A", "movie", year = 2007, runtimeSeconds = 6000, played = true)) + store.read("server:justin", "movies") { items }.toList() + val fresh = store.read("server:justin", "movies") { error("Fresh snapshot must not read") }.toList() + assertEquals(items, fresh.single().items) + now += 11 * 60_000 + val offline = store.read("server:justin", "movies") { throw java.io.IOException("offline") }.toList() + assertEquals(2, offline.size) + assertFalse(offline.first().unreachable) + assertTrue(offline.last().unreachable) + assertEquals(1000L, offline.last().savedAtMillis) + assertEquals(items, offline.last().items) + for (scope in listOf("server:mindel", "other-server:justin")) { + val isolated = store.read(scope, "movies") { throw java.io.IOException("offline") }.toList().single() + assertNull(isolated.savedAtMillis) + assertTrue(isolated.items.isEmpty()) + } + } + + @Test fun explicitRecoveryRefreshesEvenFreshEmptyDestination() = runBlocking { + val store = LibrarySnapshotStore(MemoryCacheStore()) { 1000L } + store.read("server:justin", "movies") { emptyList() }.toList() + val current = listOf(LibraryTitle("b", "New Film", "movie")) + val reads = store.read("server:justin", "movies", force = true) { current }.toList() + assertTrue(reads.first().items.isEmpty()) + assertEquals(current, reads.last().items) + assertFalse(reads.last().unreachable) + } +} diff --git a/app/src/test/java/org/justinvisser/wolfskin/tv/PlayerHandoffTest.kt b/app/src/test/java/org/justinvisser/wolfskin/tv/PlayerHandoffTest.kt new file mode 100644 index 00000000..69fbe6ba --- /dev/null +++ b/app/src/test/java/org/justinvisser/wolfskin/tv/PlayerHandoffTest.kt @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: GPL-2.0-only +package org.justinvisser.wolfskin.tv + +import android.app.Application +import android.os.Looper +import android.view.View +import android.view.WindowManager +import androidx.activity.ComponentActivity +import androidx.compose.foundation.layout.requiredSize +import androidx.compose.ui.Modifier +import androidx.compose.ui.input.key.Key +import androidx.compose.ui.test.* +import androidx.compose.ui.test.junit4.createAndroidComposeRule +import com.github.damontecres.wholphin.data.model.JellyfinServer +import com.github.damontecres.wholphin.data.model.JellyfinUser +import com.github.damontecres.wholphin.services.NavigationManager +import com.github.damontecres.wholphin.ui.nav.Destination +import com.github.takahirom.roborazzi.captureRoboImage +import io.mockk.coEvery +import io.mockk.coVerify +import io.mockk.mockk +import java.io.File +import java.io.IOException +import java.util.UUID +import org.junit.Assert.* +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.Shadows.shadowOf +import org.justinvisser.wolfskin.design.* +import org.justinvisser.wolfskin.tv.read.HomeReadFacade +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config +import org.robolectric.annotation.GraphicsMode + +/** Actual Home actions either open upstream playback or leave focus and the saved Home intact. */ +@RunWith(RobolectricTestRunner::class) +@Config(sdk = [34], application = Application::class, qualifiers = "w960dp-h540dp-xhdpi") +@GraphicsMode(GraphicsMode.Mode.NATIVE) +class PlayerHandoffTest { + @get:Rule val rule = createAndroidComposeRule() + private val server = JellyfinServer(UUID.fromString("00000000-0000-0000-0000-000000000001"), "Fixture", "https://example.invalid", null) + private val user = JellyfinUser(id = UUID.fromString("00000000-0000-0000-0000-000000000002"), name = "Mindel", serverId = server.id, accessToken = null) + private val navigation = NavigationManager() + private val facade = mockk() + private lateinit var model: WolfskinHomeViewModel + private lateinit var shell: ShellState + + @Before fun setup() { + rule.activity.window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN) + @Suppress("DEPRECATION") + rule.activity.window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_FULLSCREEN or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY + shell = ShellState(listOf(ShellPerson("mindel", "Mindel", "M", false)), "mindel").apply { pickerVisible = false } + model = WolfskinHomeViewModel(rule.activity, facade, mockk(), navigation, WolfskinSeeAllLists()) + } + + @Test fun failedPlaybackReadLeavesSavedHomeFocusedAndDrawsTheExactOfflineToast() { + val snapshot = HomeFixture(rule.activity).snapshot("mindel", "offline") + val title = snapshot.rows.first().cards.first() + coEvery { facade.playableId(user.id, title) } throws IOException("fixture offline") + rule.setContent { WolfskinTheme { + ShellSurface(shell, Modifier.requiredSize(WolfskinTokens.Shell.stageWidth, WolfskinTokens.Shell.stageHeight)) { modifier -> + HomeScreen(shell, snapshot, modifier) { model.act(it, shell, server, user) } + model.toast?.let { RecoveryToast(it) } + } + } } + rule.mainClock.advanceTimeBy(1000) + rule.onNodeWithTag("wolfskin-shell").performKeyInput { pressKey(Key.DirectionCenter) } + awaitModel { model.toast != null } + rule.onNodeWithText(RecoveryMessage.PlaybackUnavailable).assertIsDisplayed() + assertTrue(navigation.backStack.single() is Destination.Home) + assertFalse(shell.navFocused) + assertEquals("hero", snapshot.rows[shell.view.row].id) + assertEquals(0, shell.view.cards["hero"] ?: 0) + val directory = File(System.getProperty("wolfskin.captureDirectory"), "recovery").apply { mkdirs() } + rule.onRoot().captureRoboImage(File(directory, "st-090-integrated.png").absolutePath) + } + + @Test fun successfulPlaybackUsesTheRealFullscreenDestinationAndBackKeepsTheResumeCard() { + val title = HomeFixture(rule.activity).snapshot("mindel").rows.first().cards.first() + val id = UUID.fromString("00000000-0000-0000-0000-000000000003") + coEvery { facade.playableId(user.id, title) } returns id + val view = shell.view + view.cards["hero"] = 0 + rule.runOnIdle { model.act(HomeAction.Play(title, resume = true), shell, server, user) } + awaitModel { navigation.backStack.last() is Destination.Playback } + val destination = navigation.backStack.last() as Destination.Playback + assertEquals(id, destination.itemId) + assertEquals((title.resumeSeconds * 1000).toLong(), destination.positionMs) + assertTrue(destination.fullScreen) + navigation.goBack() + assertTrue(navigation.backStack.single() is Destination.Home) + assertSame(view, shell.view) + assertEquals(0, shell.view.cards["hero"]) + assertNull(model.toast) + } + + @Test fun anotherPersonsSessionCannotResolveOrStartPlayback() { + val title = HomeFixture(rule.activity).snapshot("mindel").rows.first().cards.first() + val otherUser = user.copy(name = "Justin") + rule.runOnIdle { model.act(HomeAction.Play(title, resume = true), shell, server, otherUser) } + awaitModel { model.toast != null } + assertEquals(RecoveryMessage.PlaybackUnavailable, model.toast) + assertTrue(navigation.backStack.single() is Destination.Home) + coVerify(exactly = 0) { facade.playableId(any(), any()) } + } + private fun awaitModel(condition: () -> Boolean) { + rule.waitUntil(5000) { + shadowOf(Looper.getMainLooper()).idle() + condition() + } + } +} diff --git a/app/src/test/java/org/justinvisser/wolfskin/tv/RequestsRefreshTest.kt b/app/src/test/java/org/justinvisser/wolfskin/tv/RequestsRefreshTest.kt new file mode 100644 index 00000000..a90bb4b1 --- /dev/null +++ b/app/src/test/java/org/justinvisser/wolfskin/tv/RequestsRefreshTest.kt @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0-only +package org.justinvisser.wolfskin.tv + +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.launch +import kotlinx.coroutines.test.advanceTimeBy +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Assert.assertEquals +import org.junit.Test +import org.justinvisser.wolfskin.design.ComingInRequest +import org.justinvisser.wolfskin.design.ComingInSnapshot +import org.justinvisser.wolfskin.design.ComingInStage +import org.justinvisser.wolfskin.design.ComingInStatus +import org.justinvisser.wolfskin.design.ShellPerson +import org.justinvisser.wolfskin.design.ShellState + +/** The fake clock checks refresh boundaries and cancellation without a server or a real wait. */ +@OptIn(ExperimentalCoroutinesApi::class) +class RequestsRefreshTest { + @Test fun foregroundOpenUnsettledSettledAndStoppedTransitions() = runTest { + val state = ShellState(listOf(ShellPerson("justin", "Justin", "J", false)), "justin") + val request = ComingInRequest("one", "movie", 1, "One", "justin", "Justin", "shared", "Shared", ComingInStage.Waiting) + state.requests.update(ComingInSnapshot(status = ComingInStatus.Ready, signedIn = true)) + var reads = 0 + val active = launch { refreshRequestsWhileStarted(state) { reads++ } } + runCurrent() + assertEquals(1, reads) + advanceTimeBy(30_000); runCurrent() + assertEquals("Closed and settled does not poll", 1, reads) + state.openRequests() + advanceTimeBy(29_999); runCurrent() + assertEquals(1, reads) + advanceTimeBy(1); runCurrent() + assertEquals("An open empty sheet still refreshes at 30 seconds", 2, reads) + state.closeRequests() + state.requests.update(ComingInSnapshot(listOf(request), ComingInStatus.Ready, signedIn = true)) + advanceTimeBy(30_000); runCurrent() + assertEquals("An unsettled request refreshes after the sheet closes", 3, reads) + state.requests.update(ComingInSnapshot(listOf(request.copy(stage = ComingInStage.Ready)), ComingInStatus.Ready, signedIn = true)) + advanceTimeBy(30_000); runCurrent() + assertEquals("Ready requests stop polling", 3, reads) + active.cancel(); runCurrent() + state.openRequests() + advanceTimeBy(60_000); runCurrent() + assertEquals("A stopped lifecycle cannot poll", 3, reads) + val resumed = launch { refreshRequestsWhileStarted(state) { reads++ } } + runCurrent() + assertEquals("Returning to the foreground refreshes immediately", 4, reads) + resumed.cancel() + } +} diff --git a/app/src/test/java/org/justinvisser/wolfskin/tv/SettingsHandOffCaptureTest.kt b/app/src/test/java/org/justinvisser/wolfskin/tv/SettingsHandOffCaptureTest.kt new file mode 100644 index 00000000..dd5ee44c --- /dev/null +++ b/app/src/test/java/org/justinvisser/wolfskin/tv/SettingsHandOffCaptureTest.kt @@ -0,0 +1,76 @@ +package org.justinvisser.wolfskin.tv + +import android.app.Application +import android.view.View +import android.view.WindowManager +import androidx.activity.ComponentActivity +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.ui.Modifier +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.junit4.createAndroidComposeRule +import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.onRoot +import com.github.damontecres.wholphin.R +import com.github.damontecres.wholphin.services.ImageUrlService +import com.github.damontecres.wholphin.services.SeerrRatingsService +import com.github.damontecres.wholphin.ui.LocalImageUrlService +import com.github.damontecres.wholphin.ui.components.LocalSeerrRatingsService +import com.github.damontecres.wholphin.preferences.AppPreferences +import com.github.damontecres.wholphin.preferences.UserPreferences +import com.github.damontecres.wholphin.ui.main.settings.HomePageSettingsState +import com.github.damontecres.wholphin.ui.main.settings.HomeSettingsPage +import com.github.damontecres.wholphin.ui.main.settings.HomeSettingsViewModel +import com.github.damontecres.wholphin.util.LoadingState +import com.github.takahirom.roborazzi.captureRoboImage +import io.mockk.every +import io.mockk.mockk +import java.io.File +import kotlinx.coroutines.flow.MutableStateFlow +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.justinvisser.wolfskin.design.WolfskinTheme +import org.justinvisser.wolfskin.design.WolfskinTokens +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config +import org.robolectric.annotation.GraphicsMode + +/** The frozen st-094 state opens User profile settings, not the separate Playback press path. */ +@RunWith(RobolectricTestRunner::class) +@Config(sdk = [34], application = Application::class, qualifiers = "w960dp-h540dp-xhdpi") +@GraphicsMode(GraphicsMode.Mode.NATIVE) +class SettingsHandOffCaptureTest { + @get:Rule val rule = createAndroidComposeRule() + + @Before fun fullscreen() { + rule.activity.window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN) + @Suppress("DEPRECATION") + rule.activity.window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_FULLSCREEN or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY + } + + @Test fun st094_realUserProfileHomeSettingsHandOff() { + val model = mockk(relaxed = true) + every { model.state } returns MutableStateFlow(HomePageSettingsState.EMPTY.copy(loading = LoadingState.Success)) + every { model.serverPluginActive } returns MutableStateFlow(false) + every { model.settingsChanged } returns MutableStateFlow(false) + val preferences = UserPreferences(AppPreferences.getDefaultInstance(), null) + val ratings = SeerrRatingsService(mockk(relaxed = true), mockk(relaxed = true)) + val images = mockk(relaxed = true) + rule.setContent { + WolfskinTheme { + CompositionLocalProvider(LocalSeerrRatingsService provides ratings, LocalImageUrlService provides images) { + HomeSettingsPage(preferences, Modifier.fillMaxSize().background(WolfskinTokens.Color.bg), viewModel = model) + } + } + } + rule.mainClock.advanceTimeBy(1000) + rule.waitForIdle() + rule.onNodeWithText(rule.activity.getString(R.string.customize_home)).assertIsDisplayed() + val directory = File(requireNotNull(System.getProperty("wolfskin.captureDirectory"))) + directory.mkdirs() + rule.onRoot().captureRoboImage(File(directory, "st-094.png").absolutePath) + } +} diff --git a/app/src/test/java/org/justinvisser/wolfskin/tv/ShellRoutingTest.kt b/app/src/test/java/org/justinvisser/wolfskin/tv/ShellRoutingTest.kt new file mode 100644 index 00000000..a5b181f7 --- /dev/null +++ b/app/src/test/java/org/justinvisser/wolfskin/tv/ShellRoutingTest.kt @@ -0,0 +1,70 @@ +package org.justinvisser.wolfskin.tv + +import android.app.Application +import androidx.test.core.app.ApplicationProvider +import com.github.damontecres.wholphin.preferences.AppPreference +import com.github.damontecres.wholphin.preferences.AppPreferences +import com.github.damontecres.wholphin.ui.nav.Destination +import com.github.damontecres.wholphin.ui.preferences.PreferenceScreenOption +import java.util.UUID +import org.jellyfin.sdk.model.api.BaseItemKind +import org.jellyfin.sdk.model.api.CollectionType +import org.junit.After +import org.junit.Assert.* +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config + +/** The actual Advanced preference persists its value and changes the shell's renderer policy. */ +@RunWith(RobolectricTestRunner::class) +@Config(sdk = [34], application = Application::class) +class ShellRoutingTest { + private val context: Application get() = ApplicationProvider.getApplicationContext() + private val movies = Destination.MediaItem(UUID.fromString("00000000-0000-0000-0000-000000000001"), BaseItemKind.COLLECTION_FOLDER, CollectionType.MOVIES) + private val libraries = mapOf("movies" to movies, "shows" to movies, "anime" to movies) + + @Before fun initialize() { WolfskinScreenPreference.initialize(context); WolfskinScreenPreference.enabled = true } + @After fun restore() { WolfskinScreenPreference.enabled = true } + + @Test fun advancedSwitchRestoresUpstreamHomeAndLibrariesAndPersistsAcrossReload() { + val preference = AppPreference.WolfskinScreens + val preferences = AppPreferences.getDefaultInstance() + assertNull(resolveUpstreamDestination(Destination.Home(), true, libraries)) + assertNull(resolveUpstreamDestination(Destination.Wolfskin("movies"), true, libraries)) + preference.setter(preferences, false) + WolfskinScreenPreference.initialize(context) + assertFalse(preference.getter(preferences)) + assertTrue(resolveUpstreamDestination(Destination.Home(), WolfskinScreenPreference.enabled, libraries) is Destination.Home) + listOf("movies", "shows", "anime").forEach { route -> + assertEquals(movies, resolveUpstreamDestination(Destination.Wolfskin(route), WolfskinScreenPreference.enabled, libraries)) + } + preference.setter(preferences, true) + assertNull(resolveUpstreamDestination(Destination.Home(), WolfskinScreenPreference.enabled, libraries)) + assertNull(resolveUpstreamDestination(Destination.Wolfskin("movies"), WolfskinScreenPreference.enabled, libraries)) + } + + @Test fun settingsAndPickerNeverBecomeUpstreamScreensButUnrelatedRoutesPassThrough() { + val settings = Destination.Wolfskin("settings") + val upstream = Destination.Settings(PreferenceScreenOption.ADVANCED) + for (enabled in listOf(false, true)) { + assertNull(resolveUpstreamDestination(settings, enabled, libraries)) + assertEquals(upstream, resolveUpstreamDestination(upstream, enabled, libraries)) + assertEquals(Destination.Search("name"), resolveUpstreamDestination(Destination.Search("name"), enabled, libraries)) + } + } + + @Test fun titleRolloutOwnsOnlyFilmSeriesEpisodeAndPerson() { + val id = UUID.fromString("00000000-0000-0000-0000-000000000001") + for (kind in listOf(BaseItemKind.MOVIE, BaseItemKind.SERIES, BaseItemKind.EPISODE, BaseItemKind.PERSON)) { + val destination = Destination.MediaItem(id, kind) + assertNull(resolveUpstreamDestination(destination, true, libraries)) + assertEquals(destination, resolveUpstreamDestination(destination, false, libraries)) + } + for (kind in listOf(BaseItemKind.COLLECTION_FOLDER, BaseItemKind.AUDIO, BaseItemKind.MUSIC_ALBUM, BaseItemKind.BOX_SET)) { + val destination = Destination.MediaItem(id, kind) + assertEquals(destination, resolveUpstreamDestination(destination, true, libraries)) + } + } +} diff --git a/app/src/test/java/org/justinvisser/wolfskin/tv/TitleAsyncFocusTest.kt b/app/src/test/java/org/justinvisser/wolfskin/tv/TitleAsyncFocusTest.kt new file mode 100644 index 00000000..8316538b --- /dev/null +++ b/app/src/test/java/org/justinvisser/wolfskin/tv/TitleAsyncFocusTest.kt @@ -0,0 +1,165 @@ +package org.justinvisser.wolfskin.tv + +import android.app.Application +import androidx.activity.ComponentActivity +import androidx.compose.ui.input.key.Key +import androidx.compose.ui.test.junit4.createAndroidComposeRule +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.onNodeWithTag +import androidx.compose.ui.test.onRoot +import androidx.compose.ui.test.performKeyInput +import androidx.compose.ui.test.pressKey +import androidx.lifecycle.viewModelScope +import com.github.damontecres.wholphin.preferences.AppPreferences +import com.github.damontecres.wholphin.preferences.UserPreferences +import com.github.damontecres.wholphin.services.NavigationManager +import io.mockk.coEvery +import io.mockk.mockk +import kotlinx.coroutines.CompletableDeferred +import kotlinx.coroutines.cancel +import org.junit.After +import org.junit.Assert.* +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.justinvisser.wolfskin.design.ShellPerson +import org.justinvisser.wolfskin.design.RecoveryMessage +import org.justinvisser.wolfskin.design.TitleConnection +import org.justinvisser.wolfskin.design.ShellState +import org.justinvisser.wolfskin.design.TitleItem +import org.justinvisser.wolfskin.design.TitlePageData +import org.justinvisser.wolfskin.design.TitleReadStatus +import org.justinvisser.wolfskin.design.TitleSheet +import org.justinvisser.wolfskin.design.TitleTrack +import org.justinvisser.wolfskin.design.TitleVersion +import org.justinvisser.wolfskin.design.WolfskinTheme +import org.justinvisser.wolfskin.tv.read.TitleReadFacade +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config +import java.util.UUID + +/** A delayed service reply exercises the production destination, view-model and Android focus transfer. */ +@RunWith(RobolectricTestRunner::class) +@Config(sdk = [34], application = Application::class, qualifiers = "w960dp-h540dp-xhdpi") +class TitleAsyncFocusTest { + @get:Rule val rule = createAndroidComposeRule() + private lateinit var viewModel: WolfskinTitleViewModel + + @After fun dispose() { + if (::viewModel.isInitialized) viewModel.viewModelScope.cancel() + } + + @Test fun loadingToReadyRestoresRealKeyFocusAndSheetReturn() { + val id = UUID.fromString("00000000-0000-0000-0000-000000000012") + val ready = CompletableDeferred() + val facade = mockk() + coEvery { facade.readSaved(id, any()) } returns null + coEvery { facade.read(id, any(), any()) } coAnswers { ready.await() } + viewModel = WolfskinTitleViewModel(rule.activity, facade, mockk(), mockk(relaxed = true)) + val person = ShellPerson("justin", "Justin", "J", false) + val route = titleRoute(id.toString()) + val shell = ShellState(listOf(person), person.key).apply { + pickerVisible = false + pickerLaunch = false + enterDestination(route) + } + val preferences = UserPreferences(AppPreferences.getDefaultInstance(), null) + rule.setContent { WolfskinTheme { TitleDestination(route, shell, preferences, viewModel = viewModel) } } + rule.waitUntil { viewModel.title?.data?.status == TitleReadStatus.Loading } + rule.waitForIdle() + assertTrue(shell.navFocused) + press(Key.DirectionDown) + assertTrue("The initial skeleton cannot receive nav Down", shell.navFocused) + + val source = TitleVersion("first", "Original", "1080p", "", "", "MKV", listOf(TitleTrack(3, "English", true)), emptyList()) + rule.runOnIdle { + ready.complete(TitlePageData(TitleItem(id.toString(), "A held film", "movie", held = true), versions = listOf(source, source.copy(id = "second", name = "Alternate")))) + } + rule.waitUntil { viewModel.title?.data?.status == TitleReadStatus.Ready && !shell.navFocused } + press(Key.DirectionRight) + val state = requireNotNull(viewModel.title) + assertEquals("version", state.options[state.column].id) + press(Key.DirectionCenter) + assertEquals(TitleSheet.Version, state.sheet) + rule.runOnIdle { rule.activity.onBackPressedDispatcher.onBackPressed() } + assertNull(state.sheet) + press(Key.DirectionRight) + assertEquals("tracks", state.options[state.column].id) + assertFalse(shell.navFocused) + } + + @Test fun loadingPersonFocusesItsFirstCreditBeforeRealRemoteNavigation() { + val id = UUID.fromString("00000000-0000-0000-0000-000000000013") + val reply = CompletableDeferred() + val facade = mockk() + coEvery { facade.readPersonSaved(id) } returns null + coEvery { facade.readPerson(id, 0) } coAnswers { reply.await() } + viewModel = WolfskinTitleViewModel(rule.activity, facade, mockk(), mockk(relaxed = true)) + val viewer = ShellPerson("justin", "Justin", "J", false) + val route = personRoute(id.toString()) + val shell = ShellState(listOf(viewer), viewer.key).apply { + pickerVisible = false + pickerLaunch = false + enterDestination(route) + } + rule.setContent { WolfskinTheme { + TitleDestination(route, shell, UserPreferences(AppPreferences.getDefaultInstance(), null), viewModel = viewModel) + } } + rule.waitUntil { viewModel.title?.data?.status == TitleReadStatus.Loading } + rule.waitForIdle() + assertTrue(shell.navFocused) + press(Key.DirectionDown) + assertTrue(shell.navFocused) + rule.runOnIdle { + reply.complete(org.justinvisser.wolfskin.tv.read.PersonRead( + org.justinvisser.wolfskin.design.TitlePerson(id.toString(), "Actor"), + listOf(TitleItem("first-credit", "First credit", "movie"), TitleItem("second-credit", "Second credit", "movie")), + )) + } + rule.waitUntil(timeoutMillis = 5000) { viewModel.person != null || viewModel.title?.data?.status == TitleReadStatus.Unavailable } + assertNotNull("A real person reply must populate the performer destination", viewModel.person) + rule.waitForIdle() + assertFalse("The loaded person must transfer nav ownership to its first credit", shell.navFocused) + assertEquals(0, viewModel.person!!.index) + press(Key.DirectionRight) + assertEquals(1, viewModel.person!!.index) + assertFalse(shell.navFocused) + } + + @Test fun failedRetryKeepsThePersonsSavedTitleAndShowsSharedRecovery() { + val id = UUID.fromString("00000000-0000-0000-0000-000000000014") + val reads = java.util.concurrent.atomic.AtomicInteger() + val saved = TitlePageData(TitleItem(id.toString(), "Saved title", "movie"), + connection = TitleConnection.Offline, savedAt = "20:42") + val facade = mockk() + coEvery { facade.readSaved(id, any()) } returns saved + coEvery { facade.read(id, any(), any()) } coAnswers { + reads.incrementAndGet() + throw java.io.IOException("offline") + } + viewModel = WolfskinTitleViewModel(rule.activity, facade, mockk(), mockk(relaxed = true)) + val viewer = ShellPerson("justin", "Justin", "J", false) + val route = titleRoute(id.toString()) + val shell = ShellState(listOf(viewer), viewer.key).apply { + pickerVisible = false; pickerLaunch = false; enterDestination(route) + } + rule.setContent { WolfskinTheme { + TitleDestination(route, shell, UserPreferences(AppPreferences.getDefaultInstance(), null), viewModel = viewModel) + } } + rule.waitUntil(timeoutMillis = 5000) { reads.get() == 1 && viewModel.title?.toast != null } + rule.waitForIdle() + assertEquals("20:42", shell.navSavedAt) + assertEquals("retry", viewModel.title!!.options[viewModel.title!!.column].id) + rule.runOnIdle { viewModel.title!!.toast = null } + press(Key.DirectionCenter) + rule.waitUntil(timeoutMillis = 5000) { reads.get() == 2 && viewModel.title?.toast != null } + rule.waitForIdle() + assertEquals("Saved title", viewModel.title!!.data.item.name) + assertEquals("20:42", shell.navSavedAt) + assertEquals(RecoveryMessage.StillUnreachable, viewModel.title!!.toast) + assertFalse(shell.navFocused) + rule.onNodeWithTag("recovery-toast").assertIsDisplayed() + } + + private fun press(key: Key) { rule.onRoot().performKeyInput { pressKey(key) } } +} diff --git a/app/src/test/java/org/justinvisser/wolfskin/tv/TitleCaptureTest.kt b/app/src/test/java/org/justinvisser/wolfskin/tv/TitleCaptureTest.kt new file mode 100644 index 00000000..90d6fcc1 --- /dev/null +++ b/app/src/test/java/org/justinvisser/wolfskin/tv/TitleCaptureTest.kt @@ -0,0 +1,218 @@ +package org.justinvisser.wolfskin.tv + +import android.app.Application +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.view.View +import android.view.WindowManager +import androidx.activity.ComponentActivity +import androidx.compose.foundation.layout.requiredSize +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.asImageBitmap +import androidx.compose.ui.test.junit4.createAndroidComposeRule +import androidx.compose.ui.test.onRoot +import androidx.compose.ui.test.onAllNodesWithTag +import androidx.compose.ui.test.onNodeWithTag +import androidx.compose.ui.test.performSemanticsAction +import androidx.compose.ui.semantics.SemanticsActions +import androidx.compose.ui.text.TextLayoutResult +import androidx.compose.ui.test.SemanticsMatcher +import androidx.compose.ui.graphics.toArgb +import com.github.takahirom.roborazzi.captureRoboImage +import org.json.JSONObject +import org.junit.Before +import org.junit.After +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.justinvisser.wolfskin.design.LocalTitleBitmaps +import org.justinvisser.wolfskin.design.PersonState +import org.justinvisser.wolfskin.design.PersonSurface +import org.justinvisser.wolfskin.design.ShellKey +import org.justinvisser.wolfskin.design.ShellState +import org.justinvisser.wolfskin.design.TitleConnection +import org.justinvisser.wolfskin.design.TitlePageData +import org.justinvisser.wolfskin.design.TitleReadStatus +import org.justinvisser.wolfskin.design.TitleState +import org.justinvisser.wolfskin.design.TitleSurface +import org.justinvisser.wolfskin.design.WolfskinTheme +import org.justinvisser.wolfskin.design.WolfskinTokens +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config +import org.robolectric.annotation.GraphicsMode +import java.io.File +import java.util.Locale + +/** Frozen local art feeds the shipped Compose surface; no test can call a live server. */ +@RunWith(RobolectricTestRunner::class) +@Config(sdk = [34], application = Application::class, qualifiers = "w960dp-h540dp-xhdpi") +@GraphicsMode(GraphicsMode.Mode.NATIVE) +class TitleCaptureTest { + @get:Rule val rule = createAndroidComposeRule() + private lateinit var fixture: TitleFixture + private var previousLocale = Locale.getDefault() + + @Before fun fullscreen() { + previousLocale = Locale.getDefault() + Locale.setDefault(Locale.US) + rule.activity.window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN) + @Suppress("DEPRECATION") + rule.activity.window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_FULLSCREEN or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY + fixture = TitleFixture(rule.activity.assets.open("wolfskin-titles.json").bufferedReader().use { JSONObject(it.readText()) }) + } + @After fun restoreLocale() { Locale.setDefault(previousLocale) } + + private fun capture(number: Int, title: String = "Locke", person: String = "justin", transform: (TitlePageData) -> TitlePageData = { it }, configure: (TitleState, ShellState) -> Unit = { _, _ -> }) { + val data = transform(fixture.title(title, person)) + val shell = ShellState(fixture.people, person).apply { pickerVisible = false; pickerLaunch = false; enterDestination("title/${data.item.id}") } + val state = TitleState(data, shell.person) {} + configure(state, shell) + val bitmaps = decodeArt(data) + rule.setContent { + WolfskinTheme { CompositionLocalProvider(LocalTitleBitmaps provides bitmaps) { + TitleSurface(state, shell, Modifier.requiredSize(WolfskinTokens.Shell.stageWidth, WolfskinTokens.Shell.stageHeight)) + } } + } + if (number == 55) rule.runOnIdle { + shell.view.listState.requestScrollToItem(1, -(WolfskinTokens.Layout.pinnedLine.value * 2).toInt()) + } + save(number) + } + + private fun decodeArt(data: TitlePageData): Map { + val requests = buildList> { + data.item.backdrop?.let { add(Triple(it, 1280, 720)) } + if (data.item.backdrop == null || data.item.isPosterBackdrop) data.item.poster?.let { add(Triple(it, 420, 630)) } + data.cast.forEach { person -> person.portrait?.let { add(Triple(it, 200, 200)) } } + data.related.forEach { item -> item.poster?.let { add(Triple(it, 256, 384)) } } + data.episodes.forEach { item -> + (if (item.isPosterBackdrop) item.poster else item.backdrop)?.let { add(Triple(it, 416, 234)) } + } + } + return requests.distinctBy { it.first }.associate { (path, width, height) -> + val bitmap = rule.activity.assets.open(path.removePrefix("file:///android_asset/")).use { BitmapFactory.decodeStream(it)!! } + val scale = maxOf(width.toFloat() / bitmap.width, height.toFloat() / bitmap.height).coerceAtMost(1f) + val scaled = Bitmap.createScaledBitmap(bitmap, (bitmap.width * scale).toInt(), (bitmap.height * scale).toInt(), true) + if (scaled !== bitmap) bitmap.recycle() + path to scaled.asImageBitmap() + } + } + + private fun save(number: Int) { + rule.mainClock.advanceTimeBy(1000) + rule.waitForIdle() + val directory = File(requireNotNull(System.getProperty("wolfskin.captureDirectory"))).apply { mkdirs() } + rule.onRoot().captureRoboImage(File(directory, "st-${number.toString().padStart(3, '0')}.png").absolutePath) + val heading = rule.onAllNodesWithTag("title-heading").fetchSemanticsNodes().singleOrNull() + if (heading != null) { + val layouts = mutableListOf() + rule.onNodeWithTag("title-heading").performSemanticsAction(SemanticsActions.GetTextLayoutResult) { action -> action(layouts) } + val layout = layouts.single() + val metrics = JSONObject().put("title", layout.layoutInput.text.text).put("lineCount", layout.lineCount) + .put("lineWidthsPx", org.json.JSONArray(List(layout.lineCount) { layout.getLineRight(it) - layout.getLineLeft(it) })) + .put("ellipsized", org.json.JSONArray(List(layout.lineCount) { layout.isLineEllipsized(it) })) + .put("maxWidthPx", layout.layoutInput.constraints.maxWidth).put("fontSizeSp", layout.layoutInput.style.fontSize.value) + .put("requestedWeight", layout.layoutInput.style.fontWeight?.weight) + .put("boundsPx", org.json.JSONArray(listOf(heading.boundsInRoot.left, heading.boundsInRoot.top, heading.boundsInRoot.right, heading.boundsInRoot.bottom))) + File(directory, "st-${number.toString().padStart(3, '0')}-layout.json").writeText(metrics.toString(2)) + } + recordTextMetrics(directory, number) + recordElements(directory, number) + } + + private fun recordTextMetrics(directory: File, number: Int) { + val elements = rule.onAllNodes(SemanticsMatcher.keyIsDefined(SemanticsActions.GetTextLayoutResult), useUnmergedTree = true) + val records = org.json.JSONArray() + elements.fetchSemanticsNodes().forEachIndexed { index, node -> + if (node.boundsInRoot.width > 0 && node.boundsInRoot.height > 0) { + val layouts = mutableListOf() + elements[index].performSemanticsAction(SemanticsActions.GetTextLayoutResult) { action -> action(layouts) } + val layout = layouts.single() + records.put(JSONObject().put("text", layout.layoutInput.text.text) + .put("fontSizeSp", layout.layoutInput.style.fontSize.value) + .put("weight", layout.layoutInput.style.fontWeight?.weight) + .put("colourArgb", Integer.toUnsignedString(layout.layoutInput.style.color.toArgb(), 16)) + .put("lineHeightSp", layout.layoutInput.style.lineHeight.value.takeIf { it.isFinite() } ?: JSONObject.NULL) + .put("lineCount", layout.lineCount) + .put("boundsPx", org.json.JSONArray(listOf(node.boundsInRoot.left, node.boundsInRoot.top, node.boundsInRoot.right, node.boundsInRoot.bottom))) + .put("spans", org.json.JSONArray(layout.layoutInput.text.spanStyles.map { span -> + JSONObject().put("start", span.start).put("end", span.end).put("weight", span.item.fontWeight?.weight) + }))) + } + } + File(directory, "st-${number.toString().padStart(3, '0')}-text.json").writeText(records.toString(2)) + } + + private fun recordElements(directory: File, number: Int) { + val tag = androidx.compose.ui.semantics.SemanticsProperties.TestTag + val description = androidx.compose.ui.semantics.SemanticsProperties.ContentDescription + val matcher = SemanticsMatcher.keyIsDefined(tag) or SemanticsMatcher.keyIsDefined(description) + val records = org.json.JSONArray() + rule.onAllNodes(matcher, useUnmergedTree = true).fetchSemanticsNodes().forEach { node -> + records.put(JSONObject() + .put("tag", if (node.config.contains(tag)) node.config[tag] else JSONObject.NULL) + .put("description", if (node.config.contains(description)) org.json.JSONArray(node.config[description]) else JSONObject.NULL) + .put("boundsPx", org.json.JSONArray(listOf(node.boundsInRoot.left, node.boundsInRoot.top, node.boundsInRoot.right, node.boundsInRoot.bottom)))) + } + File(directory, "st-${number.toString().padStart(3, '0')}-elements.json").writeText(records.toString(2)) + } + + private fun option(state: TitleState, id: String) { state.focus("header", state.options.indexOfFirst { it.id == id }) } + private fun open(state: TitleState, shell: ShellState, id: String) { + option(state, id) + state.key(ShellKey.Ok, true, 0, shell) + state.key(ShellKey.Ok, false, 0, shell) + } + + @Test fun st042_heldMovie() = capture(42, "The Girl Who Leapt Through Time") + @Test fun st043_options() = capture(43) { state, _ -> option(state, "version") } + @Test fun st044_versions() = capture(44) { state, shell -> open(state, shell, "version") } + @Test fun st045_rememberedVersion() = capture(45) { state, _ -> state.versionId = "v2"; option(state, "version") } + @Test fun st046_tracks() = capture(46) { state, shell -> open(state, shell, "tracks") } + @Test fun st047_mediaInfo() = capture(47) { state, shell -> open(state, shell, "more") } + @Test fun st048_trailerNoApp() = capture(48) { state, _ -> option(state, "trailer"); state.toast = "No YouTube app is available to play this trailer." } + @Test fun st049_watched() = capture(49, transform = { it.copy(watchTarget = it.watchTarget.copy(watched = true)) }) { state, _ -> option(state, "watched") } + @Test fun st050_seriesConfirm() = capture(50, "Andor") { state, shell -> open(state, shell, "watched") } + @Test fun st051_episodeRestart() = capture(51, "episode-sex-and-the-country-2001-s4e9", "mindel") { state, _ -> option(state, "restart") } + @Test fun st052_filmCast() = capture(52) { state, shell -> + state.focus("cast", 0) + state.key(ShellKey.Right, true, 0, shell) + state.key(ShellKey.Right, false, 0, shell) + } + @Test fun st053_seriesCast() = capture(53, "Andor") { state, _ -> state.focus("cast", 0) } + @Test fun st054_initialsCast() = capture(54, "Spirited Away", "shared") { state, _ -> state.focus("cast", 0) } + @Test fun st055_castLoading() = capture(55, transform = { it.copy(cast = emptyList(), castStatus = TitleReadStatus.Loading) }) + @Test fun st056_castUnavailable() = capture(56, transform = { it.copy(cast = emptyList(), castStatus = TitleReadStatus.Unavailable) }) { state, _ -> state.focus("related", 0) } + @Test fun st057_person() { + val (person, credits) = fixture.person("Tom Holland", "justin") + val shell = ShellState(fixture.people, "justin").apply { pickerVisible = false; enterDestination("person/Tom Holland") } + val state = PersonState(person, credits, {}) + val data = TitlePageData(credits.first(), cast = listOf(person), related = credits) + val art = decodeArt(data) + rule.setContent { WolfskinTheme { CompositionLocalProvider(LocalTitleBitmaps provides art) { + PersonSurface(state, shell, Modifier.requiredSize(WolfskinTokens.Shell.stageWidth, WolfskinTokens.Shell.stageHeight)) + } } } + save(57) + } + @Test fun st058_hiddenReceipt() = capture(58, "The Amazing Spider-Man") { state, shell -> open(state, shell, "hide") } + @Test fun st059_hiddenPick() = capture(59, "The Amazing Spider-Man", transform = { it.copy(hidden = true) }) { state, _ -> option(state, "unhide") } + @Test fun st060_titleNav() = capture(60) { _, shell -> shell.focusNav(0) } + @Test fun st061_loading() = capture(61, transform = { it.copy(status = TitleReadStatus.Loading) }) { _, shell -> shell.focusNav(0) } + @Test fun st062_error() = capture(62, transform = { it.copy(status = TitleReadStatus.Unavailable) }) + @Test fun st063_signedOut() = capture(63, "The Amazing Spider-Man", transform = { it.copy(connection = TitleConnection.SignedOut) }) + @Test fun st064_seriesNext() = capture(64, "Andor") + @Test fun st065_resumeEpisode() = capture(65, "episode-sex-and-the-country-2001-s4e9", "mindel") + @Test fun st066_notHeld() = capture(66, "The Amazing Spider-Man") + @Test fun st067_trailerFallback() = capture(67, "The Amazing Spider-Man") + @Test fun st068_requested() = capture(68, "The Amazing Spider-Man", transform = { it.copy(requestedStage = "Searching", requestActor = "Justin") }) + @Test fun st069_missingArt() = capture(69, "The Amazing Spider-Man", transform = { it.copy(item = it.item.copy(poster = null, backdrop = null)) }) + @Test fun st070_offline() = capture(70, "The Amazing Spider-Man", transform = { + it.copy(connection = TitleConnection.Offline, savedAt = "20:42", item = it.item.copy(ratings = emptyList())) + }) + @Test fun st104_relatedPlate() = capture(104, "The Girl Who Leapt Through Time") { state, _ -> state.focus("related", state.data.related.indexOfFirst { it.name == "INVINCIBLE" }.coerceAtLeast(0)) } + @Test fun st106_heldRatings() = capture(106, "American Gangster", "shared") + @Test fun st107_seriesEpisodeRatings() = capture(107, "Andor") + @Test fun st108_resumingEpisodeRatings() = capture(108, "episode-sex-and-the-country-2001-s4e9", "mindel") + @Test fun st109_noRatings() = capture(109, "The Amazing Spider-Man") +} diff --git a/app/src/test/java/org/justinvisser/wolfskin/tv/TitleKeysTest.kt b/app/src/test/java/org/justinvisser/wolfskin/tv/TitleKeysTest.kt new file mode 100644 index 00000000..6df8426d --- /dev/null +++ b/app/src/test/java/org/justinvisser/wolfskin/tv/TitleKeysTest.kt @@ -0,0 +1,345 @@ +package org.justinvisser.wolfskin.tv + +import android.app.Application +import androidx.activity.ComponentActivity +import androidx.activity.compose.BackHandler +import androidx.compose.ui.input.key.Key +import androidx.compose.ui.test.junit4.createAndroidComposeRule +import androidx.compose.ui.test.onRoot +import androidx.compose.ui.test.performKeyInput +import androidx.compose.ui.test.pressKey +import androidx.compose.ui.test.onNodeWithTag +import androidx.compose.ui.test.performMouseInput +import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.performSemanticsAction +import androidx.compose.ui.semantics.SemanticsActions +import androidx.compose.ui.text.TextLayoutResult +import org.justinvisser.wolfskin.design.WolfskinTokens +import org.json.JSONArray +import org.json.JSONObject +import org.junit.Assert.* +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.justinvisser.wolfskin.design.ShellAction +import org.justinvisser.wolfskin.design.ShellState +import org.justinvisser.wolfskin.design.TitleAction +import org.justinvisser.wolfskin.design.TitleConnection +import org.justinvisser.wolfskin.design.TitleReadStatus +import org.justinvisser.wolfskin.design.TitleSheet +import org.justinvisser.wolfskin.design.TitleState +import org.justinvisser.wolfskin.design.TitleSurface +import org.justinvisser.wolfskin.design.WolfskinTheme +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config +import org.robolectric.annotation.GraphicsMode + +/** Approved title-entry suffixes replay Android keys through the rendered title and shared shell. */ +@RunWith(RobolectricTestRunner::class) +@Config(sdk = [34], application = Application::class, qualifiers = "w960dp-h540dp-xhdpi") +class TitleKeysTest { + @get:Rule val rule = createAndroidComposeRule() + private lateinit var fixture: TitleFixture + private val effects = mutableListOf() + private val shellEffects = mutableListOf() + private lateinit var state: TitleState + private lateinit var shell: ShellState + private lateinit var paths: List + + @Before fun fixtures() { + fixture = TitleFixture(rule.activity.assets.open("wolfskin-titles.json").bufferedReader().use { JSONObject(it.readText()) }) + val data = javaClass.getResourceAsStream("/title-press-paths.json")!!.bufferedReader().use { JSONArray(it.readText()) } + paths = List(data.length()) { data.getJSONObject(it) } + } + + private fun render(title: String = "Locke", transform: (org.justinvisser.wolfskin.design.TitlePageData) -> org.justinvisser.wolfskin.design.TitlePageData = { it }) { + shell = ShellState(fixture.people, "justin", shellEffects::add).apply { pickerVisible = false; pickerLaunch = false; enterDestination(titleRoute(title)) } + state = TitleState(transform(fixture.title(title, "justin")), shell.person, effects::add) + rule.setContent { WolfskinTheme { + BackHandler { state.back(shell) } + TitleSurface(state, shell) + } } + } + + private fun press(key: Key) { rule.onRoot().performKeyInput { pressKey(key) } } + private fun replay(end: String): Int { + val path = paths.single { it.getString("end") == end } + render(path.getString("title")) + val keys = path.getJSONArray("keys") + var presses = 0 + for (index in path.getInt("entryPresses") until keys.length()) { + val key = when (keys.getString(index)) { + "UP" -> Key.DirectionUp + "DOWN" -> Key.DirectionDown + "LEFT" -> Key.DirectionLeft + "RIGHT" -> Key.DirectionRight + "OK" -> Key.DirectionCenter + else -> error("Unknown replay key") + } + press(key) + presses++ + } + return presses + } + + @Test fun titleToNavOnePressFromEntry() { + assertEquals(1, replay("nav")) + assertTrue(shell.navFocused) + assertEquals(shell.currentTab, shell.navIndex) + } + + @Test fun switchPersonFivePressesFromTitleEntry() { + assertEquals(5, replay("person-mindel")) + assertEquals("mindel", shell.person.key) + assertEquals("home", shell.route) + assertFalse(shell.pickerVisible) + assertTrue(shellEffects.last() is ShellAction.Person) + } + + @Test fun lockeSecondVersionSixPressesFromTitleEntry() { + assertEquals(6, replay("play-version-2")) + assertEquals("v2", state.versionId) + assertNull(state.sheet) + assertEquals("play", state.options[state.column].id) + assertTrue(effects.last() is TitleAction.Play) + assertEquals("Locke", (effects.last() as TitleAction.Play).item.name) + } + + @Test fun lockeCastTwoPressesFromTitleEntry() { + assertEquals(2, replay("person-Tom Hardy")) + assertEquals("cast", state.row) + assertEquals("Tom Hardy", (effects.single() as TitleAction.Person).person.name) + } + + @Test fun sheetBackRestoresItsOpeningOptionAndChosenVersion() { + render() + press(Key.DirectionRight) + press(Key.DirectionCenter) + assertEquals(TitleSheet.Version, state.sheet) + press(Key.DirectionDown) + press(Key.DirectionCenter) + assertEquals("v2", state.versionId) + assertEquals("Version", state.options[state.column].label) + press(Key.DirectionCenter) + assertEquals(1, state.sheetIndex) + press(Key.Back) + assertNull(state.sheet) + assertEquals("Version", state.options[state.column].label) + assertFalse(shell.navFocused) + } + + @Test fun trackChoiceStaysInSheetAndOffRemainsAnExplicitChoice() { + render() + press(Key.DirectionRight); press(Key.DirectionRight); press(Key.DirectionCenter) + assertEquals(TitleSheet.Tracks, state.sheet) + press(Key.DirectionDown); press(Key.DirectionCenter) + assertEquals(1, state.audioIndex) + assertEquals(TitleSheet.Tracks, state.sheet) + press(Key.DirectionDown); press(Key.DirectionDown); press(Key.DirectionCenter) + assertEquals(2, state.subtitleIndex) + press(Key.DirectionUp); press(Key.DirectionCenter) + assertEquals(-1, state.subtitleIndex) + press(Key.Back) + assertNull(state.sheet) + assertEquals("tracks", state.options[state.column].id) + } + + @Test fun castLoadingAndUnavailableAreNeverFocusable() { + render(transform = { it.copy(cast = emptyList(), castStatus = TitleReadStatus.Loading) }) + press(Key.DirectionDown) + assertEquals("related", state.row) + assertFalse(state.rows.contains("cast")) + } + + @Test fun wholeSeriesRequiresConfirmationButEpisodesDoNot() { + render("Andor") + rule.runOnIdle { state.focus("header", state.options.indexOfFirst { it.id == "watched" }) } + press(Key.DirectionCenter) + assertEquals(TitleSheet.ConfirmWatched, state.sheet) + assertFalse(state.watched) + press(Key.DirectionRight); press(Key.DirectionCenter) + assertFalse(state.watched) + assertTrue(effects.none { it is TitleAction.Watched }) + press(Key.DirectionCenter); press(Key.DirectionCenter) + assertTrue(state.watched) + assertTrue(effects.last() is TitleAction.Watched) + } + + @Test fun titlesNobodyHoldsHaveNoTrailerUntilTheCatalogueFieldExists() { + render("The Amazing Spider-Man") + assertTrue(state.options.none { it.id == "trailer" }) + assertEquals("Request", state.options.first().label) + rule.runOnIdle { state.update(state.data.copy(connection = TitleConnection.SignedOut)) } + assertEquals(listOf("retry"), state.options.map { it.id }) + } + + @Test fun hiddenReceiptUndoRestoresTitleAndOptionInPlace() { + render("The Amazing Spider-Man") + press(Key.DirectionRight); press(Key.DirectionRight); press(Key.DirectionCenter) + assertTrue(state.data.hidden) + assertEquals(TitleSheet.HiddenReceipt, state.sheet) + press(Key.DirectionCenter) + assertFalse(state.data.hidden) + assertNull(state.sheet) + assertEquals("hide", state.options[state.column].id) + } + + @Test fun heldOkCannotChooseTheVersionInTheSheetItOpened() { + render() + press(Key.DirectionRight) + rule.runOnIdle { + rule.activity.dispatchKeyEvent(android.view.KeyEvent(0, 0, android.view.KeyEvent.ACTION_DOWN, android.view.KeyEvent.KEYCODE_DPAD_CENTER, 0)) + repeat(5) { index -> rule.activity.dispatchKeyEvent(android.view.KeyEvent(0, 0, android.view.KeyEvent.ACTION_DOWN, android.view.KeyEvent.KEYCODE_DPAD_CENTER, index + 1)) } + rule.activity.dispatchKeyEvent(android.view.KeyEvent(0, 0, android.view.KeyEvent.ACTION_UP, android.view.KeyEvent.KEYCODE_DPAD_CENTER, 0)) + } + assertEquals(TitleSheet.Version, state.sheet) + assertTrue(effects.none { it is TitleAction.Version }) + } + + @Test fun episodeWatchedToggleKeepsItsIdentityAndDoesNotAskAboutTheSeries() { + val episode = requireNotNull(fixture.title("Andor", "justin").playTarget) + render(episode.id) + rule.runOnIdle { state.focus("header", state.options.indexOfFirst { it.id == "watched" }) } + press(Key.DirectionCenter) + assertNull(state.sheet) + val change = effects.single() as TitleAction.Watched + assertEquals(episode.id, change.item.id) + assertEquals(!episode.watched, change.watched) + } + + @Test fun aPendingSeasonSkipsItsEpisodeSkeletons() { + render("Andor") + rule.runOnIdle { state.showSeasonLoading() } + press(Key.DirectionDown); press(Key.DirectionDown) + assertEquals("cast", state.row) + rule.runOnIdle { state.restoreSeason() } + press(Key.DirectionUp) + assertEquals("episodes", state.row) + } + + @Test fun aFailedOlderVersionWriteCannotUndoTheNewerChoice() { + render() + press(Key.DirectionRight); press(Key.DirectionCenter); press(Key.DirectionDown); press(Key.DirectionCenter) + val first = effects.last() as TitleAction.Version + press(Key.DirectionCenter); press(Key.DirectionUp); press(Key.DirectionCenter) + val second = effects.last() as TitleAction.Version + rule.runOnIdle { state.rejectPlayback(first); state.confirmPlayback(second) } + assertEquals("v1", state.versionId) + press(Key.DirectionCenter); press(Key.DirectionDown); press(Key.DirectionCenter) + val failed = effects.last() as TitleAction.Version + rule.runOnIdle { state.rejectPlayback(failed) } + assertEquals("v1", state.versionId) + } + + @Test fun aNewRowUsesTheNearestHorizontalCardBeforeItsOwnRememberedCard() { + render() + repeat(4) { press(Key.DirectionRight) } + val x = rule.onNodeWithTag("title-option-trailer").fetchSemanticsNode().boundsInRoot.center.x + val cast = state.data.cast.take(WolfskinTokens.Card.personSlots) + val nearest = cast.indices.minBy { index -> + kotlin.math.abs(rule.onNodeWithTag("title-cast-${cast[index].id}").fetchSemanticsNode().boundsInRoot.center.x - x) + } + press(Key.DirectionDown) + assertEquals(nearest, state.column) + press(Key.DirectionRight) + val remembered = state.column + press(Key.DirectionUp); press(Key.DirectionDown) + assertEquals(remembered, state.column) + } + + @Test fun wheelThenRemoteLandsOnTheFirstVisibleFocusableRow() { + render() + rule.onNodeWithTag("title-page").performMouseInput { scroll(800f) } + val expected = rule.runOnIdle { + shell.view.listState.layoutInfo.visibleItemsInfo.first { + it.key in state.rows && it.offset + it.size > WolfskinTokens.Layout.pinnedLine.value * 2 + }.key as String + } + assertNotEquals("header", expected) + press(Key.DirectionDown) + assertEquals(expected, state.row) + } + @Test fun seriesOptionsKeepTheCompleteHouseholdActionLabel() { + render("Andor") + val layouts = mutableListOf() + rule.onNodeWithText("Add for someone", useUnmergedTree = true) + .performSemanticsAction(SemanticsActions.GetTextLayoutResult) { action -> action(layouts) } + val layout = layouts.single() + assertFalse("The final pill must not shrink to its icon or a clipped label", layout.didOverflowWidth) + assertEquals(1, layout.lineCount) + } + + @Test fun anInitialLoadNeverExposesStaleCastBelowItsSkeleton() { + render(transform = { it.copy(status = TitleReadStatus.Loading) }) + rule.onNodeWithText("Cast").assertDoesNotExist() + press(Key.DirectionDown) + assertTrue(shell.navFocused) + assertEquals("header", state.row) + rule.runOnIdle { rule.activity.onBackPressedDispatcher.onBackPressed() } + assertEquals(listOf(TitleAction.Pop), effects) + } + + + @Test fun unratedFactsDoNotReserveAnEmptyRatingsSlot() { + render("The Amazing Spider-Man", transform = { + it.copy(item = it.item.copy(ratings = emptyList(), genres = listOf("Drama"), runtimeSeconds = 0), + cast = emptyList(), related = emptyList()) + }) + val year = rule.onNodeWithText("2012", useUnmergedTree = true).fetchSemanticsNode().boundsInRoot + val genre = rule.onNodeWithText("Drama", useUnmergedTree = true).fetchSemanticsNode().boundsInRoot + assertEquals(WolfskinTokens.Title.factsGap.value * 2, genre.left - year.right, 1f) + } + + @GraphicsMode(GraphicsMode.Mode.NATIVE) + @Test fun mediaInfoRowsPreserveTheirDeclaredLineBoxes() { + render() + rule.runOnIdle { state.focus("header", state.options.indexOfFirst { it.id == "more" }) } + press(Key.DirectionCenter) + val container = rule.onNodeWithText("Container", useUnmergedTree = true).fetchSemanticsNode().boundsInRoot + val size = rule.onNodeWithText("Size", useUnmergedTree = true).fetchSemanticsNode().boundsInRoot + val expectedPitch = (WolfskinTokens.Title.infoKey.lineHeight.value + WolfskinTokens.Title.infoRowGap.value) * 2 + assertEquals("Stacked facts retain the CSS line-box rhythm", expectedPitch, size.top - container.top, 1f) + val lastSubtitle = rule.onNodeWithText("Dutch", useUnmergedTree = true).fetchSemanticsNode().boundsInRoot + assertEquals("Fourteen stacked lines do not accumulate native pixel rounding", 526.2f, lastSubtitle.top - container.top, 1f) + } + + @GraphicsMode(GraphicsMode.Mode.NATIVE) + @Test fun filmHeaderKeepsItsFixedCssStack() { + render() + assertEquals(358f, rule.onNodeWithTag("title-facts").fetchSemanticsNode().boundsInRoot.top, 1f) + assertEquals(410f, rule.onNodeWithTag("title-overview").fetchSemanticsNode().boundsInRoot.top, 1f) + assertEquals(553f, rule.onNodeWithTag("title-actions").fetchSemanticsNode().boundsInRoot.top, 1f) + } + + @GraphicsMode(GraphicsMode.Mode.NATIVE) + @Test fun episodeProgressReclaimsItsNegativeMarginBeforeTheActionRow() { + render("Andor") + assertEquals(603f, rule.onNodeWithTag("title-actions").fetchSemanticsNode().boundsInRoot.top, 1f) + } + + @Test fun everyLongTrackChoiceAndDoneRemainInsideTheVisibleSheet() { + render(transform = { data -> + val source = data.versions.first().copy( + audio = List(3) { org.justinvisser.wolfskin.design.TitleTrack(it + 3, "Audio ${it + 1}") }, + subtitles = List(15) { org.justinvisser.wolfskin.design.TitleTrack(it + 20, "Subtitle ${it + 1}") }, + ) + data.copy(versions = listOf(source)) + }) + rule.runOnIdle { state.focus("header", state.options.indexOfFirst { it.id == "tracks" }) } + press(Key.DirectionCenter) + val bottom = rule.onRoot().fetchSemanticsNode().boundsInRoot.bottom + val labels = (1..3).map { "Audio $it" } + "Off" + (1..15).map { "Subtitle $it" } + "Done" + labels.forEachIndexed { index, label -> + if (index > 0) press(Key.DirectionDown) + rule.waitForIdle() + val bounds = rule.onNodeWithText(label, useUnmergedTree = true).fetchSemanticsNode().boundsInRoot + assertTrue("$label must have visible height: $bounds", bounds.height > 20) + assertTrue("$label stays above the viewport bottom: $bounds / $bottom", bounds.bottom <= bottom) + assertTrue("$label stays below the viewport top: $bounds", bounds.top >= 0) + } + press(Key.DirectionCenter) + assertNull(state.sheet) + assertFalse(shell.navFocused) + } +} diff --git a/app/src/test/java/org/justinvisser/wolfskin/tv/TitleLaunchKeysTest.kt b/app/src/test/java/org/justinvisser/wolfskin/tv/TitleLaunchKeysTest.kt new file mode 100644 index 00000000..07636e5a --- /dev/null +++ b/app/src/test/java/org/justinvisser/wolfskin/tv/TitleLaunchKeysTest.kt @@ -0,0 +1,132 @@ +package org.justinvisser.wolfskin.tv + +import android.app.Application +import androidx.activity.ComponentActivity +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.input.key.Key +import androidx.compose.ui.test.junit4.createAndroidComposeRule +import androidx.compose.ui.test.onRoot +import androidx.compose.ui.test.performKeyInput +import androidx.compose.ui.test.pressKey +import org.json.JSONArray +import org.json.JSONObject +import org.junit.Assert.* +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.justinvisser.wolfskin.design.* +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config + +/** Full launch paths render the real picker, Home hero/shelves, title and person surfaces. */ +@RunWith(RobolectricTestRunner::class) +@Config(sdk = [34], application = Application::class, qualifiers = "w960dp-h540dp-xhdpi") +class TitleLaunchKeysTest { + @get:Rule val rule = createAndroidComposeRule() + private lateinit var fixture: TitleFixture + private lateinit var home: HomeFixture + private lateinit var shell: ShellState + private var title by mutableStateOf(null) + private var person by mutableStateOf(null) + private val actions = mutableListOf() + private val shellActions = mutableListOf() + private lateinit var paths: List + + @Before fun launch() { + fixture = TitleFixture(rule.activity.assets.open("wolfskin-titles.json").bufferedReader().use { JSONObject(it.readText()) }) + home = HomeFixture(rule.activity) + val source = javaClass.getResourceAsStream("/title-press-paths.json")!!.bufferedReader().use { JSONArray(it.readText()) } + paths = List(source.length()) { source.getJSONObject(it) } + shell = ShellState(fixture.people, "justin") { action -> + shellActions.add(action) + if (action is ShellAction.Person) { title = null; person = null } + } + rule.setContent { WolfskinTheme { + val performer = person + val page = title + val snapshot = remember(shell.person.key) { home.snapshot(shell.person.key) } + when { + performer != null -> PersonSurface(performer, shell) + page != null -> TitleSurface(page, shell) + else -> ShellSurface(shell) { modifier -> + HomeScreen(shell, snapshot, modifier) { action -> + if (action is HomeAction.Details) openTitle(action.title.id) + } + } + } + } } + } + + private fun openTitle(id: String) { + val data = fixture.title(id, shell.person.key) + title = TitleState(data, shell.person, ::act) + person = null + shell.enterDestination(titleRoute(id)) + } + + private fun act(action: TitleAction) { + actions.add(action) + when (action) { + is TitleAction.Person -> { + val (actor, credits) = fixture.person(action.person.id, shell.person.key) + person = PersonState(actor, credits, ::act) + shell.enterDestination(personRoute(actor.id)) + } + is TitleAction.OpenTitle -> openTitle(action.item.id) + else -> Unit + } + } + + private fun replay(end: String, expectedPresses: Int) { + val path = paths.single { it.getString("end") == end } + val keys = path.getJSONArray("keys") + assertEquals(expectedPresses, path.getInt("presses")) + assertEquals(expectedPresses, keys.length()) + for (index in 0 until keys.length()) { + val key = when (keys.getString(index)) { + "UP" -> Key.DirectionUp; "DOWN" -> Key.DirectionDown + "LEFT" -> Key.DirectionLeft; "RIGHT" -> Key.DirectionRight + "OK" -> Key.DirectionCenter + else -> error("Unknown launch replay key") + } + rule.onRoot().performKeyInput { pressKey(key) } + } + } + + @Test fun titleToNavTakesFourPressesFromTheRealHomeHero() { + replay("nav", 4) + assertNotNull(title) + assertTrue(shell.navFocused) + assertEquals(shell.currentTab, shell.navIndex) + } + + @Test fun switchingPersonFromATitleTakesEightLaunchPresses() { + replay("person-mindel", 8) + assertEquals("mindel", shell.person.key) + assertFalse(shell.pickerVisible) + assertEquals("home", shell.route) + assertTrue(shellActions.last() is ShellAction.Person) + } + + @Test fun lockeVersionTwoAndPlayTakesFifteenLaunchPresses() { + replay("play-version-2", 15) + val page = requireNotNull(title) + assertEquals("Locke", page.data.item.name) + assertEquals("v2", page.versionId) + assertNull(page.sheet) + assertEquals("play", page.options[page.column].id) + assertEquals("Locke", (actions.last() as TitleAction.Play).item.name) + } + + @Test fun lockeToTomHardyTakesElevenLaunchPresses() { + replay("person-Tom Hardy", 11) + assertEquals("Tom Hardy", requireNotNull(person).person.name) + assertEquals(0, person!!.index) + assertFalse(shell.navFocused) + assertTrue(actions.last() is TitleAction.Person) + } +} diff --git a/app/src/test/java/org/justinvisser/wolfskin/tv/TitleLocaleTest.kt b/app/src/test/java/org/justinvisser/wolfskin/tv/TitleLocaleTest.kt new file mode 100644 index 00000000..e9462bff --- /dev/null +++ b/app/src/test/java/org/justinvisser/wolfskin/tv/TitleLocaleTest.kt @@ -0,0 +1,57 @@ +package org.justinvisser.wolfskin.tv + +import android.app.Application +import androidx.activity.ComponentActivity +import androidx.compose.ui.semantics.SemanticsActions +import androidx.compose.ui.test.junit4.createAndroidComposeRule +import androidx.compose.ui.test.onAllNodesWithText +import androidx.compose.ui.test.onLast +import androidx.compose.ui.test.performSemanticsAction +import androidx.compose.ui.text.TextLayoutResult +import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.justinvisser.wolfskin.design.ShellPerson +import org.justinvisser.wolfskin.design.ShellState +import org.justinvisser.wolfskin.design.TitleConnection +import org.justinvisser.wolfskin.design.TitleItem +import org.justinvisser.wolfskin.design.TitlePageData +import org.justinvisser.wolfskin.design.LibraryRating +import org.justinvisser.wolfskin.design.TitleState +import org.justinvisser.wolfskin.design.TitleSurface +import org.justinvisser.wolfskin.design.WolfskinTheme +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config +import org.robolectric.annotation.GraphicsMode +import java.util.Locale + +/** Native text layout proves locale formatting still fits the focused poster's one-line plate. */ +@RunWith(RobolectricTestRunner::class) +@Config(sdk = [34], application = Application::class, qualifiers = "w960dp-h540dp-xhdpi") +@GraphicsMode(GraphicsMode.Mode.NATIVE) +class TitleLocaleTest { + @get:Rule val rule = createAndroidComposeRule() + + private fun render(locale: Locale, expected: String) { + val previous = Locale.getDefault() + try { + Locale.setDefault(locale) + val person = ShellPerson("justin", "Justin", "J", false) + val item = TitleItem("movie:1", "Title", "movie", ratings = listOf(LibraryRating("tmdb", 7.8))) + val shell = ShellState(listOf(person), person.key).apply { pickerVisible = false; enterDestination("title/movie:1") } + val state = TitleState(TitlePageData(item, related = listOf(item.copy(id = "movie:2")), connection = TitleConnection.SignedIn), person) {} + state.focus("related", 0) + rule.setContent { WolfskinTheme { TitleSurface(state, shell) } } + rule.mainClock.advanceTimeBy(1000) + val layouts = mutableListOf() + rule.onAllNodesWithText(expected, useUnmergedTree = true).onLast().performSemanticsAction(SemanticsActions.GetTextLayoutResult) { get -> get(layouts) } + assertEquals(1, layouts.single().lineCount) + assertFalse(layouts.single().didOverflowWidth) + } finally { Locale.setDefault(previous) } + } + + @Test fun dutchScoreUsesCommaOnTheNativePlate() = render(Locale.forLanguageTag("nl-NL"), "7,8") + @Test fun englishScoreUsesPointOnTheNativePlate() = render(Locale.US, "7.8") +} diff --git a/app/src/test/java/org/justinvisser/wolfskin/tv/TitleReadFacadeTest.kt b/app/src/test/java/org/justinvisser/wolfskin/tv/TitleReadFacadeTest.kt new file mode 100644 index 00000000..1a672f67 --- /dev/null +++ b/app/src/test/java/org/justinvisser/wolfskin/tv/TitleReadFacadeTest.kt @@ -0,0 +1,203 @@ +package org.justinvisser.wolfskin.tv + +import android.app.Application +import android.content.Context +import com.github.damontecres.wholphin.WholphinApplication +import com.github.damontecres.wholphin.data.ItemPlaybackRepository +import com.github.damontecres.wholphin.data.ServerRepository +import com.github.damontecres.wholphin.data.model.JellyfinUser +import com.github.damontecres.wholphin.data.model.JellyfinServer +import com.github.damontecres.wholphin.preferences.AppPreferences +import com.github.damontecres.wholphin.preferences.UserPreferences +import com.github.damontecres.wholphin.services.FavoriteWatchManager +import com.github.damontecres.wholphin.services.ImageUrlService +import com.github.damontecres.wholphin.ui.successQueryResult +import com.github.damontecres.wholphin.ui.successResponse +import io.mockk.coEvery +import io.mockk.coVerify +import io.mockk.every +import io.mockk.mockk +import io.mockk.mockkObject +import io.mockk.unmockkObject +import kotlinx.coroutines.test.runTest +import org.jellyfin.sdk.api.client.ApiClient +import org.jellyfin.sdk.api.client.extensions.itemsApi +import org.jellyfin.sdk.api.client.extensions.tvShowsApi +import org.jellyfin.sdk.api.client.extensions.userLibraryApi +import org.jellyfin.sdk.api.operations.ItemsApi +import org.jellyfin.sdk.api.operations.TvShowsApi +import org.jellyfin.sdk.api.operations.UserLibraryApi +import org.jellyfin.sdk.model.api.BaseItemDto +import org.jellyfin.sdk.model.api.BaseItemKind +import com.github.damontecres.wholphin.test.TestTracks +import org.jellyfin.sdk.model.api.MediaStreamType +import org.jellyfin.sdk.model.api.request.GetEpisodesRequest +import org.jellyfin.sdk.model.api.request.GetItemsRequest +import org.junit.Assert.* +import org.junit.After +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.rules.TemporaryFolder +import org.junit.runner.RunWith +import org.justinvisser.wolfskin.design.ShellPerson +import org.justinvisser.wolfskin.design.TitleConnection +import org.justinvisser.wolfskin.design.TitleState +import org.justinvisser.wolfskin.tv.read.TitleReadFacade +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config +import org.robolectric.RuntimeEnvironment +import java.util.UUID + +/** SDK replies stay in-process; disk reload and identity isolation exercise the real facade. */ +@RunWith(RobolectricTestRunner::class) +@Config(sdk = [34], application = Application::class) +class TitleReadFacadeTest { + @get:Rule val directory = TemporaryFolder() + private val library = mockk() + private val items = mockk() + private val shows = mockk() + private val api = mockk() + private val playback = mockk() + private val repository = mockk() + private val preferences = UserPreferences(AppPreferences.getDefaultInstance(), null) + private lateinit var facade: TitleReadFacade + private val firstId = UUID.fromString("00000000-0000-0000-0000-000000000001") + private val secondId = UUID.fromString("00000000-0000-0000-0000-000000000002") + private val seriesId = UUID.fromString("00000000-0000-0000-0000-000000000003") + private val seasonId = UUID.fromString("00000000-0000-0000-0000-000000000004") + private val sourceId = UUID.fromString("00000000-0000-0000-0000-000000000005").toString().replace("-", "") + + @Before fun setup() { + // BaseItem formats runtime using application resources; no Hilt/network application is started. + val app = mockk { + every { resources } returns RuntimeEnvironment.getApplication().resources + } + mockkObject(WholphinApplication.Companion) + every { WholphinApplication.instance } returns app + every { api.userLibraryApi } returns library + every { api.itemsApi } returns items + every { api.tvShowsApi } returns shows + every { repository.currentServer } returns null + every { repository.currentUser } returns null + coEvery { playback.getSelectedTracks(any(), any(), any()) } returns null + val context = mockk { every { filesDir } returns directory.root } + facade = TitleReadFacade(api, mockk(relaxed = true), playback, repository, mockk(), context) + } + + @After fun teardown() { + unmockkObject(WholphinApplication.Companion) + } + + private fun file(id: UUID, kind: BaseItemKind = BaseItemKind.MOVIE): BaseItemDto { + val source = TestTracks.Builder().addVideo().addAudio().addSubtitle().buildMediaSourceInfo() + val streams = source.mediaStreams.orEmpty().map { stream -> + when (stream.type) { + MediaStreamType.VIDEO -> stream.copy(index = 0, displayTitle = "1080p") + MediaStreamType.AUDIO -> stream.copy(index = 3, displayTitle = "English", isDefault = true) + MediaStreamType.SUBTITLE -> stream.copy(index = 8, displayTitle = "Dutch") + else -> error("Unexpected track in the SDK fixture builder") + } + } + return BaseItemDto(id = id, name = "A real file", type = kind, runTimeTicks = 6_000_000_000, + mediaSources = listOf(source.copy(id = sourceId, name = "Original", container = "mkv", mediaStreams = streams))) + } + + @Test fun diskCopyPreservesFileAndNonContiguousStreamIndexesWithoutRatingsBeforeSignIn() = runTest { + coEvery { library.getItem(firstId) } returns successResponse(file(firstId)) + facade.read(firstId, null, preferences) + coEvery { library.getItem(any()) } throws java.io.IOException("offline") + val saved = facade.readSaved(firstId, preferences)!! + val screen = TitleState(saved, ShellPerson("justin", "Justin", "J", false)) {} + assertEquals("MKV", saved.versions.single().container) + assertEquals(3, screen.audio?.index) + assertEquals(listOf(8), saved.versions.single().subtitles.map { it.index }) + assertEquals(TitleConnection.SignedOut, saved.connection) + assertTrue(saved.item.ratings.isEmpty()) + assertEquals(firstId.toString(), saved.watchTarget.id) + } + + @Test fun diskCopiesNeverCrossViewerIdentity() = runTest { + val userA = mockk { every { id } returns firstId } + val userB = mockk { every { id } returns secondId } + every { repository.currentUser } returns userA + coEvery { library.getItem(firstId) } returns successResponse(file(firstId)) + facade.read(firstId, null, preferences) + every { repository.currentUser } returns userB + assertNull(facade.readSaved(firstId, preferences)) + every { repository.currentUser } returns userA + assertEquals("A real file", facade.readSaved(firstId, preferences)?.item?.name) + } + + @Test fun personBiographyAndContinuousCreditsRemainReadableFromDiskWithoutAService() = runTest { + val actor = BaseItemDto(id = firstId, type = BaseItemKind.PERSON, name = "Actor", overview = "Actual biography") + coEvery { library.getItem(firstId) } returns successResponse(actor) + coEvery { items.getItems(any()) } returns successQueryResult(listOf(file(secondId))) + facade.readPerson(firstId, 0) + coEvery { library.getItem(any()) } throws java.io.IOException("offline") + coEvery { items.getItems(any()) } throws java.io.IOException("offline") + val saved = facade.readPersonSaved(firstId)!! + assertEquals("Actual biography", saved.person.biography) + assertEquals(secondId.toString(), saved.credits.single().id) + assertEquals("A real file", saved.credits.single().name) + } + + @Test fun personSavedCopiesNeverCrossServerOrViewerIdentity() = runTest { + val userA = mockk { every { id } returns firstId } + val userB = mockk { every { id } returns secondId } + val serverA = mockk { every { id } returns seriesId } + val serverB = mockk { every { id } returns seasonId } + every { repository.currentUser } returns userA + every { repository.currentServer } returns serverA + coEvery { library.getItem(firstId) } returns successResponse( + BaseItemDto(id = firstId, type = BaseItemKind.PERSON, name = "Saved actor", overview = "Private biography")) + coEvery { items.getItems(any()) } returns successQueryResult(listOf(file(secondId))) + facade.readPerson(firstId, 0) + every { repository.currentUser } returns userB + assertNull(facade.readPersonSaved(firstId)) + every { repository.currentUser } returns userA + every { repository.currentServer } returns serverB + assertNull(facade.readPersonSaved(firstId)) + every { repository.currentServer } returns serverA + val saved = requireNotNull(facade.readPersonSaved(firstId)) + assertEquals("Private biography", saved.person.biography) + assertEquals(secondId.toString(), saved.credits.single().id) + } + + @Test fun explicitEpisodeStaysThePlayAndWatchTargetAcrossDifferentSeasonSelection() = runTest { + val episode = file(firstId, BaseItemKind.EPISODE).copy(seriesId = seriesId, parentIndexNumber = 4, indexNumber = 9) + val other = file(secondId, BaseItemKind.EPISODE).copy(seriesId = seriesId, parentIndexNumber = 2, indexNumber = 1) + val series = BaseItemDto(id = seriesId, name = "Series", type = BaseItemKind.SERIES) + val secondSeason = BaseItemDto(id = seasonId, type = BaseItemKind.SEASON, indexNumber = 2) + coEvery { library.getItem(firstId) } returns successResponse(episode) + coEvery { library.getItem(seriesId) } returns successResponse(series) + coEvery { items.getItems(any()) } returns successQueryResult(listOf(secondSeason)) + coEvery { shows.getEpisodes(any()) } returns successQueryResult(listOf(other)) + val data = facade.read(firstId, 2, preferences) + assertEquals(seriesId.toString(), data.item.id) + assertEquals(firstId.toString(), data.playTarget?.id) + assertEquals(firstId.toString(), data.watchTarget.id) + assertEquals(listOf(secondId.toString()), data.episodes.map { it.id }) + assertEquals(listOf(2), data.seasonNumbers) + assertEquals(2, TitleState(data, ShellPerson("justin", "Justin", "J", false)) {}.season) + } + + @Test fun compactJellyfinSourceIdUsesTheSameVersionPersistenceKey() = runTest { + coEvery { library.getItem(firstId) } returns successResponse(file(firstId)) + coEvery { playback.savePlayVersion(any(), any()) } returns null + val data = facade.read(firstId, null, preferences) + facade.apply(org.justinvisser.wolfskin.design.TitleAction.Version(data.watchTarget, data.versions.single())) + coVerify(exactly = 1) { playback.savePlayVersion(firstId, UUID.fromString("00000000-0000-0000-0000-000000000005")) } + } + @Test fun subtitleOffDisablesPlaybackRatherThanRestoringThePreferredLanguage() = runTest { + coEvery { library.getItem(firstId) } returns successResponse(file(firstId)) + coEvery { playback.saveTrackSelection(any(), any(), any(), MediaStreamType.SUBTITLE) } returns + com.github.damontecres.wholphin.data.model.ItemPlayback(userId = 1, itemId = firstId) + val data = facade.read(firstId, null, preferences) + facade.apply(org.justinvisser.wolfskin.design.TitleAction.Track(data.watchTarget, data.versions.single(), audio = null, subtitle = -1)) + coVerify(exactly = 1) { playback.saveTrackSelection(any(), any(), com.github.damontecres.wholphin.data.model.TrackIndex.DISABLED, MediaStreamType.SUBTITLE) } + coVerify(exactly = 0) { playback.saveTrackSelection(any(), any(), com.github.damontecres.wholphin.data.model.TrackIndex.UNSPECIFIED, MediaStreamType.SUBTITLE) } + facade.apply(org.justinvisser.wolfskin.design.TitleAction.Track(data.watchTarget, data.versions.single(), audio = null, subtitle = 8)) + coVerify(exactly = 1) { playback.saveTrackSelection(any(), any(), 8, MediaStreamType.SUBTITLE) } + } +} diff --git a/app/src/test/java/org/justinvisser/wolfskin/tv/TitleTrailerTest.kt b/app/src/test/java/org/justinvisser/wolfskin/tv/TitleTrailerTest.kt new file mode 100644 index 00000000..afa137ee --- /dev/null +++ b/app/src/test/java/org/justinvisser/wolfskin/tv/TitleTrailerTest.kt @@ -0,0 +1,51 @@ +package org.justinvisser.wolfskin.tv + +import android.app.Application +import android.content.Context +import android.content.Intent +import android.content.pm.ActivityInfo +import android.content.pm.ResolveInfo +import android.net.Uri +import androidx.test.core.app.ApplicationProvider +import org.junit.Assert.* +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.Shadows.shadowOf +import org.robolectric.annotation.Config + +/** Browser handlers must never become a fallback for a missing YouTube app. */ +@RunWith(RobolectricTestRunner::class) +@Config(sdk = [34], application = Application::class) +class TitleTrailerTest { + private val context = ApplicationProvider.getApplicationContext() + private val url = "https://www.youtube.com/watch?v=abcdefghijk" + + @Test fun missingYoutubeHandlerStaysOnTheTitleEvenWhenABrowserExists() { + register(Intent(Intent.ACTION_VIEW, Uri.parse(url)), "test.browser") + assertFalse(TitleTrailer(context).open(url)) + assertNull(shadowOf(context as Application).nextStartedActivity) + } + + @Test fun installedYoutubeHandlerReceivesAnExplicitPackageAndNoBrowserUrl() { + register(Intent(Intent.ACTION_VIEW, Uri.parse("vnd.youtube:abcdefghijk")), "test.youtube") + assertTrue(TitleTrailer(context).open(url)) + val launched = shadowOf(context as Application).nextStartedActivity + assertEquals("test.youtube", launched.`package`) + assertEquals("vnd.youtube", launched.data?.scheme) + assertEquals("abcdefghijk", launched.data?.schemeSpecificPart) + } + + @Test fun nonYoutubeTrailerNeverOpensAGeneralViewHandler() { + register(Intent(Intent.ACTION_VIEW, Uri.parse("https://trailers.example/video")), "test.browser") + assertFalse(TitleTrailer(context).open("https://trailers.example/video")) + assertNull(shadowOf(context as Application).nextStartedActivity) + } + + private fun register(intent: Intent, name: String) { + val info = ResolveInfo().apply { + activityInfo = ActivityInfo().apply { packageName = name; this.name = "$name.Player"; exported = true } + } + shadowOf(context.packageManager).addResolveInfoForIntent(intent, info) + } +} diff --git a/app/src/test/java/org/justinvisser/wolfskin/tv/UpstreamContentFocusTest.kt b/app/src/test/java/org/justinvisser/wolfskin/tv/UpstreamContentFocusTest.kt new file mode 100644 index 00000000..d9e88778 --- /dev/null +++ b/app/src/test/java/org/justinvisser/wolfskin/tv/UpstreamContentFocusTest.kt @@ -0,0 +1,144 @@ +package org.justinvisser.wolfskin.tv + +import android.app.Application +import android.view.View +import android.view.WindowManager +import androidx.activity.ComponentActivity +import androidx.compose.foundation.focusable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.FocusRequester +import androidx.compose.ui.focus.focusRequester +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.toPixelMap +import androidx.compose.ui.input.key.Key +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.assertIsFocused +import androidx.compose.ui.test.assertIsNotFocused +import androidx.compose.ui.test.captureToImage +import androidx.compose.ui.test.junit4.createAndroidComposeRule +import androidx.compose.ui.test.onNodeWithTag +import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.onRoot +import androidx.compose.ui.test.performKeyInput +import androidx.compose.ui.test.pressKey +import androidx.compose.ui.unit.dp +import com.github.damontecres.wholphin.data.model.JellyfinServer +import com.github.damontecres.wholphin.data.model.JellyfinUser +import com.github.damontecres.wholphin.preferences.AppPreferences +import com.github.damontecres.wholphin.preferences.BackdropStyle +import com.github.damontecres.wholphin.preferences.UserPreferences +import com.github.damontecres.wholphin.services.BackdropResult +import com.github.damontecres.wholphin.services.NavigationManager +import com.github.damontecres.wholphin.ui.nav.Destination +import com.github.takahirom.roborazzi.captureRoboImage +import io.mockk.coEvery +import io.mockk.every +import io.mockk.mockk +import java.io.File +import java.util.UUID +import kotlinx.coroutines.flow.MutableStateFlow +import org.junit.After +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.justinvisser.wolfskin.design.ShellPerson +import org.justinvisser.wolfskin.design.ShellState +import org.justinvisser.wolfskin.design.ShellSurface +import org.justinvisser.wolfskin.design.WolfskinTheme +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config +import org.robolectric.annotation.GraphicsMode + +/** The rollout-off path must preserve native content focus and its backdrop beneath the shell. */ +@RunWith(RobolectricTestRunner::class) +@Config(sdk = [34], application = Application::class, qualifiers = "w960dp-h540dp-xhdpi") +@GraphicsMode(GraphicsMode.Mode.NATIVE) +class UpstreamContentFocusTest { + @get:Rule val rule = createAndroidComposeRule() + + @Before fun prepare() { + WolfskinScreenPreference.initialize(rule.activity) + WolfskinScreenPreference.enabled = false + rule.activity.window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN) + @Suppress("DEPRECATION") + rule.activity.window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_FULLSCREEN or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY + } + + @After fun restore() { WolfskinScreenPreference.enabled = true } + + private fun shellState() = ShellState(listOf(ShellPerson("justin", "Justin", "J", true)), "justin").apply { + pickerVisible = false + navFocused = false + } + + @Test fun switchOffUpMovesBetweenContentRowsBeforeEnteringNav() { + val state = shellState() + val first = FocusRequester() + val second = FocusRequester() + rule.setContent { + val upstream = resolveUpstreamDestination(Destination.Home(), WolfskinScreenPreference.enabled, emptyMap()) + WolfskinTheme { + ShellSurface(state, handlesContentKeys = upstream == null) { contentModifier -> + Column(contentModifier.padding(start = 100.dp, top = 150.dp), verticalArrangement = Arrangement.spacedBy(32.dp)) { + Box(Modifier.size(200.dp, 60.dp).testTag("upstream-first").focusRequester(first).focusable()) + Box(Modifier.size(200.dp, 60.dp).testTag("upstream-second").focusRequester(second).focusable()) + } + } + } + } + rule.runOnIdle { second.requestFocus() } + rule.onNodeWithTag("upstream-second").assertIsFocused() + rule.onNodeWithTag("upstream-second").performKeyInput { pressKey(Key.DirectionUp) } + rule.onNodeWithTag("upstream-first").assertIsFocused() + rule.runOnIdle { assertFalse("Up from the second row must not enter nav", state.navFocused) } + rule.onNodeWithTag("upstream-first").performKeyInput { pressKey(Key.DirectionUp) } + rule.runOnIdle { assertTrue("Only the first row exits upward to nav", state.navFocused) } + rule.onNodeWithTag("upstream-first").assertIsNotFocused() + rule.onNodeWithTag("wolfskin-shell").performKeyInput { pressKey(Key.DirectionDown) } + rule.onNodeWithTag("upstream-first").assertIsFocused() + } + + @Test fun switchOffShowsRealUpstreamBackdropAndSwitchOnRestoresOwnedBackground() { + val state = shellState() + val model = mockk(relaxed = true) + every { model.session } returns WolfskinSession().also { it.state = state } + every { model.libraryDestinations } returns emptyMap() + // An unavailable saved identity uses the real sign-in placeholder, avoiding any server reads. + every { model.signedInPerson } returns "unavailable" + every { model.backdropFlow } returns MutableStateFlow(BackdropResult("fixture", null, Color.Red, Color.Red, Color.Red)) + coEvery { model.load(any(), any()) } returns Unit + val server = JellyfinServer(UUID.fromString("00000000-0000-0000-0000-000000000001"), "Fixture", "https://example.invalid", null) + val user = JellyfinUser(id = UUID.fromString("00000000-0000-0000-0000-000000000002"), name = "Justin", serverId = server.id, accessToken = null) + val defaults = AppPreferences.getDefaultInstance() + val preferences = UserPreferences(defaults.toBuilder().setInterfacePreferences(defaults.interfacePreferences.toBuilder().setBackdropStyle(BackdropStyle.BACKDROP_DYNAMIC_COLOR)).build(), null) + val navigation = NavigationManager() + rule.setContent { WolfskinApp(server, user, navigation, preferences, Modifier.fillMaxSize(), model) } + rule.mainClock.advanceTimeBy(1500) + rule.waitForIdle() + val off = rule.onRoot().captureToImage().toPixelMap()[1700, 900] + assertTrue("The real dynamic backdrop must remain visible through native content", off.red > .4f && off.green < .1f && off.blue < .1f) + val directory = File(requireNotNull(System.getProperty("wolfskin.captureDirectory"))) + directory.mkdirs() + rule.onRoot().captureRoboImage(File(directory, "review-upstream-off.png").absolutePath) + rule.runOnIdle { WolfskinScreenPreference.enabled = true } + rule.mainClock.advanceTimeBy(1500) + rule.waitForIdle() + rule.onNodeWithText("Sign in as Justin to open their Jellyfin library").assertIsDisplayed() + val on = rule.onRoot().captureToImage().toPixelMap()[1700, 900] + val background = org.justinvisser.wolfskin.design.WolfskinTokens.Color.bg + org.junit.Assert.assertEquals("Owned background red", background.red, on.red, 1f / 255f) + org.junit.Assert.assertEquals("Owned background green", background.green, on.green, 1f / 255f) + org.junit.Assert.assertEquals("Owned background blue", background.blue, on.blue, 1f / 255f) + rule.onRoot().captureRoboImage(File(directory, "review-upstream-on.png").absolutePath) + } +} diff --git a/app/src/test/resources/title-press-paths.json b/app/src/test/resources/title-press-paths.json new file mode 100644 index 00000000..14b28147 --- /dev/null +++ b/app/src/test/resources/title-press-paths.json @@ -0,0 +1,92 @@ +[ + { + "goal": "Round 3 ยท title page โ†’ nav", + "keys": [ + "OK", + "RIGHT", + "OK", + "UP" + ], + "presses": 4, + "note": "1 from the title page", + "start": "app launch: Who's watching with Justin focused (index.html:357)", + "replayed": "PASS", + "source": "index.html:2152-2174 PRESSES, replayed 2026-11-05", + "entryPresses": 3, + "title": "The Girl Who Leapt Through Time", + "end": "nav" + }, + { + "goal": "Round 3 ยท play Locke with version 2 (sample files)", + "keys": [ + "OK", + "DOWN", + "DOWN", + "DOWN", + "RIGHT", + "RIGHT", + "RIGHT", + "RIGHT", + "OK", + "RIGHT", + "OK", + "DOWN", + "OK", + "LEFT", + "OK" + ], + "presses": 15, + "note": "6 on the title page", + "start": "app launch: Who's watching with Justin focused (index.html:357)", + "replayed": "PASS", + "source": "index.html:2152-2174 PRESSES, replayed 2026-11-05", + "entryPresses": 9, + "title": "Locke", + "end": "play-version-2" + }, + { + "goal": "Round 3 ยท Locke โ†’ its first cast memberโ€™s page", + "keys": [ + "OK", + "DOWN", + "DOWN", + "DOWN", + "RIGHT", + "RIGHT", + "RIGHT", + "RIGHT", + "OK", + "DOWN", + "OK" + ], + "presses": 11, + "note": "2 on the title page: โ†“ to Cast, OK", + "start": "app launch: Who's watching with Justin focused (index.html:357)", + "replayed": "PASS", + "source": "index.html:2152-2174 PRESSES, replayed 2026-11-05", + "entryPresses": 9, + "title": "Locke", + "end": "person-Tom Hardy" + }, + { + "goal": "Round 3 ยท switch person from a title page", + "keys": [ + "OK", + "RIGHT", + "OK", + "UP", + "LEFT", + "OK", + "RIGHT", + "OK" + ], + "presses": 8, + "note": "5 from the title page", + "start": "app launch: Who's watching with Justin focused (index.html:357)", + "replayed": "PASS", + "source": "index.html:2152-2174 PRESSES, replayed 2026-11-05", + "entryPresses": 3, + "title": "The Girl Who Leapt Through Time", + "end": "person-mindel" + } +] diff --git a/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/ConductarrDiscoverOperations.kt b/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/ConductarrDiscoverOperations.kt new file mode 100644 index 00000000..0c8a7067 --- /dev/null +++ b/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/ConductarrDiscoverOperations.kt @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: GPL-2.0-only +package org.justinvisser.wolfskin.tv + +import kotlinx.coroutines.flow.last +import org.justinvisser.wolfskin.conductarr.ClientError +import org.justinvisser.wolfskin.conductarr.ConductarrClient +import org.justinvisser.wolfskin.conductarr.MediaType +import org.justinvisser.wolfskin.conductarr.MutationResult +import org.justinvisser.wolfskin.conductarr.ReadResult +import org.justinvisser.wolfskin.conductarr.TvRoutes +import org.justinvisser.wolfskin.conductarr.model.RecommendationHideInputBody +import org.justinvisser.wolfskin.conductarr.model.RequestIntentBody +import org.justinvisser.wolfskin.conductarr.model.RequestReceipt +import org.justinvisser.wolfskin.design.DiscoverOperations +import org.justinvisser.wolfskin.design.DiscoverRequest +import org.justinvisser.wolfskin.design.DiscoverRequestResult +import org.justinvisser.wolfskin.design.DiscoverSnapshot +import org.justinvisser.wolfskin.design.DiscoverTitle +import org.justinvisser.wolfskin.design.RequestPhase + +/** An injected signed-in client is the only real mutation path; the fixture host never constructs one. */ +class ConductarrDiscoverOperations( + private val client: ConductarrClient, + private val refreshSnapshot: suspend () -> DiscoverSnapshot, +) : DiscoverOperations { + override suspend fun request(intent: DiscoverRequest): DiscoverRequestResult { + val title = intent.title + require(title.type != "tv" || !title.seasons.isNullOrEmpty()) { "Whole-series season metadata is required" } + val body = RequestIntentBody( + mediaType = if (title.type == "movie") RequestIntentBody.MediaType.MOVIE else RequestIntentBody.MediaType.TV, + recommendationProfile = intent.profile.takeIf { intent.fromRecommendation }, requester = intent.requester, + seasons = title.seasons?.map(Int::toLong), + source = if (intent.fromRecommendation) RequestIntentBody.Source.RECOMMENDATION else RequestIntentBody.Source.TITLE, + tmdbId = title.tmdb, + ) + return when (val result = client.mutate(TvRoutes.request(body))) { + is MutationResult.Success -> result.value.outcome() + is MutationResult.Failure -> DiscoverRequestResult(if (result.error == ClientError.Http(403)) RequestPhase.Refused else RequestPhase.NotConfirmed) + } + } + + override suspend fun check(intent: DiscoverRequest): DiscoverRequestResult { + return when (val result = client.read(TvRoutes.requests(intent.title.tmdb, intent.title.mediaType()), org.justinvisser.wolfskin.conductarr.ReadTrigger.FORCE).last()) { + is ReadResult.Value -> result.saved.value?.requests?.firstOrNull { it.requester == intent.requester }?.outcome() ?: DiscoverRequestResult(RequestPhase.NotConfirmed) + is ReadResult.Failure -> DiscoverRequestResult(RequestPhase.NotConfirmed) + } + } + + override suspend fun hide(profile: String, title: DiscoverTitle): Boolean { + val result = client.mutate(TvRoutes.hide(profile, + RecommendationHideInputBody(if (title.type == "movie") RecommendationHideInputBody.MediaType.MOVIE else RecommendationHideInputBody.MediaType.TV, + title = title.title, tmdbId = title.tmdb, year = title.year?.toLong()))) + return result is MutationResult.Success || observedHidden(profile, title) == true + } + + override suspend fun restore(profile: String, title: DiscoverTitle): Boolean { + val result = client.mutate(TvRoutes.restore(profile, title.tmdb, title.mediaType())) + return result is MutationResult.Success || observedHidden(profile, title) == false + } + + private suspend fun observedHidden(profile: String, title: DiscoverTitle): Boolean? { + return when (val result = client.read(TvRoutes.dismissals(profile), org.justinvisser.wolfskin.conductarr.ReadTrigger.FORCE).last()) { + is ReadResult.Value -> result.saved.value?.dismissals?.any { + it.tmdbId == title.tmdb && it.mediaType.name == title.mediaType().name + } + is ReadResult.Failure -> null + } + } + override suspend fun refresh(): DiscoverSnapshot = refreshSnapshot() +} + +private fun DiscoverTitle.mediaType(): MediaType = if (type == "movie") MediaType.MOVIE else MediaType.TV +private fun RequestReceipt.outcome(): DiscoverRequestResult = DiscoverRequestResult( + phase = if (state == RequestReceipt.State.PENDING) RequestPhase.Pending else if (state == RequestReceipt.State.RETIRED) RequestPhase.Refused else RequestPhase.Receipt, + actor = actor.name, + requester = requester, +) diff --git a/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/DiscoverHost.kt b/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/DiscoverHost.kt new file mode 100644 index 00000000..b107bd97 --- /dev/null +++ b/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/DiscoverHost.kt @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: GPL-2.0-only +package org.justinvisser.wolfskin.tv + +import android.content.Context +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.compositionLocalOf +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue +import androidx.compose.ui.platform.LocalContext +import com.github.damontecres.wholphin.BuildConfig +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import org.justinvisser.wolfskin.design.DiscoverFixture +import org.justinvisser.wolfskin.design.DiscoverOperations +import org.justinvisser.wolfskin.design.DiscoverRequest +import org.justinvisser.wolfskin.design.DiscoverRequestResult +import org.justinvisser.wolfskin.design.DiscoverSnapshot +import org.justinvisser.wolfskin.design.DiscoverState +import org.justinvisser.wolfskin.design.DiscoverTitle +import org.justinvisser.wolfskin.design.DiscoverStatus +import org.justinvisser.wolfskin.design.RequestPhase +import org.justinvisser.wolfskin.design.ShellState + +internal val LocalDiscoverState = compositionLocalOf { error("Discover requires the Wolfskin shell") } + +/** No client or endpoint is constructed before TV sign-in exists; release stays explicitly signed out. */ +@Composable +internal fun rememberDiscoverState( + shell: ShellState, + push: (String) -> Unit, + pop: () -> Unit, + loadFixture: suspend (Context) -> DiscoverFixture = { context -> withContext(Dispatchers.IO) { readDiscoverFixture(context) } }, +): DiscoverState { + val context = LocalContext.current + val scope = rememberCoroutineScope() + var state by remember(shell, shell.person.key) { mutableStateOf(DiscoverState(shell, DiscoverSnapshot(status = if (BuildConfig.DEBUG) DiscoverStatus.Loading else DiscoverStatus.NeedsSignIn), SignedOutDiscoverOperations, scope, push, pop)) } + LaunchedEffect(shell, shell.person.key) { + if (BuildConfig.DEBUG) { + val fixture = loadFixture(context) + val snapshot = fixture.snapshot(shell.person.key) + val resumeContent = shell.route == "discover" && (!shell.navFocused || shell.navIndex == shell.currentTab) + val loaded = DiscoverState(shell, snapshot, DebugDiscoverOperations(snapshot, shell.person.name), scope, push, pop, fixture::service) + state = loaded + if (resumeContent) loaded.focus(if (loaded.hasHero || !loaded.canRequest) 0 else 1) + } + } + LaunchedEffect(shell.route, state) { state.enterRoute(shell.route) } + return state +} + +private fun readDiscoverFixture(context: Context): DiscoverFixture { + val json = context.assets.open("wolfskin-discover/fixture.json").bufferedReader().use { it.readText() } + return DiscoverFixture(json) { "file:///android_asset/wolfskin-discover/$it" } +} + +/** Fixture writes are in-memory only and cannot reach a Conductarr client. */ +private class DebugDiscoverOperations(private val snapshot: DiscoverSnapshot, private val actor: String) : DiscoverOperations { + override suspend fun request(intent: DiscoverRequest) = DiscoverRequestResult(RequestPhase.Receipt, actor) + override suspend fun check(intent: DiscoverRequest) = DiscoverRequestResult(RequestPhase.NotConfirmed) + override suspend fun hide(profile: String, title: DiscoverTitle) = true + override suspend fun restore(profile: String, title: DiscoverTitle) = true + override suspend fun refresh() = snapshot +} + +private object SignedOutDiscoverOperations : DiscoverOperations { + override suspend fun request(intent: DiscoverRequest) = DiscoverRequestResult(RequestPhase.Refused) + override suspend fun check(intent: DiscoverRequest) = DiscoverRequestResult(RequestPhase.NotConfirmed) + override suspend fun hide(profile: String, title: DiscoverTitle) = false + override suspend fun restore(profile: String, title: DiscoverTitle) = false + override suspend fun refresh() = DiscoverSnapshot() +} diff --git a/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/HomeDestination.kt b/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/HomeDestination.kt new file mode 100644 index 00000000..e2ac7a91 --- /dev/null +++ b/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/HomeDestination.kt @@ -0,0 +1,144 @@ +package org.justinvisser.wolfskin.tv + +import android.content.Context +import androidx.compose.foundation.layout.* +import androidx.compose.runtime.* +import androidx.compose.ui.Modifier +import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.github.damontecres.wholphin.data.model.JellyfinServer +import com.github.damontecres.wholphin.data.model.JellyfinUser +import com.github.damontecres.wholphin.services.NavigationManager +import com.github.damontecres.wholphin.ui.nav.Destination +import dagger.hilt.android.lifecycle.HiltViewModel +import dagger.hilt.android.qualifiers.ApplicationContext +import java.text.SimpleDateFormat +import java.util.Date +import java.util.Locale +import javax.inject.Inject +import kotlinx.coroutines.CancellationException +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import org.justinvisser.wolfskin.design.* +import org.justinvisser.wolfskin.tv.read.HomeLibraryCache +import org.justinvisser.wolfskin.tv.read.HomeReadFacade + +/** The Home entry owns its source reads and upstream navigation, never the design module. */ +@HiltViewModel +class WolfskinHomeViewModel @Inject constructor( + @param:ApplicationContext private val context: Context, + private val home: HomeReadFacade, + private val cache: HomeLibraryCache, + private val navigation: NavigationManager, + private val seeAll: WolfskinSeeAllLists, +) : ViewModel() { + var snapshot by mutableStateOf(HomeSnapshot(buildHomeRows(HomeLibrary(), emptyList(), loading = true), HomeAvailability.Loading)) + private set + var toast by mutableStateOf(null) + private set + private var sourceScope: String? = null + private var loadRevision = 0L + + suspend fun load(server: JellyfinServer, user: JellyfinUser, person: String, retry: Boolean = false) { + withContext(Dispatchers.IO) { debugHomeSnapshot(context, person) }?.let { snapshot = it; return } + loadLibrary(server, user, person, retry) + } + + /** The authenticated read path is shared by release and offline fixture-driven tests. */ + internal suspend fun loadLibrary(server: JellyfinServer, user: JellyfinUser, person: String, retry: Boolean = false) { + val revision = ++loadRevision + val continuation = listOf(homeDiscoverState(HomeAvailability.SignedOut)) + if (person != user.name.orEmpty().lowercase()) { + snapshot = HomeSnapshot(buildHomeRows(HomeLibrary(), continuation, libraryAvailable = false), jellyfinAvailable = false) + return + } + val scope = "${server.id}:${user.id}" + if (sourceScope != scope) { + sourceScope = scope + toast = null + snapshot = HomeSnapshot(buildHomeRows(HomeLibrary(), emptyList(), loading = true), HomeAvailability.Loading) + } + val saved = withContext(Dispatchers.IO) { try { cache.read(scope) } catch (_: java.io.IOException) { null } } + if (revision != loadRevision) return + if (saved != null) snapshot = HomeSnapshot(buildHomeRows(saved.first, continuation)) + try { + val library = withContext(Dispatchers.IO) { home.read(user.id) } + val savedAt = System.currentTimeMillis() + withContext(Dispatchers.IO) { try { cache.write(scope, library, savedAt) } catch (_: java.io.IOException) { /* Local storage failure must not turn a reachable library into an outage. */ } } + if (revision != loadRevision) return + snapshot = HomeSnapshot(buildHomeRows(library, continuation)) + } catch (exception: Exception) { + if (exception is CancellationException) throw exception + if (revision != loadRevision) return + snapshot = if (saved != null) HomeSnapshot(buildHomeRows(saved.first, continuation), jellyfinAvailable = false, savedAt = SimpleDateFormat("HH:mm", Locale.getDefault()).format(Date(saved.second))) + else HomeSnapshot(buildHomeRows(HomeLibrary(), continuation, libraryAvailable = false), jellyfinAvailable = false) + if (retry) showToast(RecoveryMessage.StillUnreachable) + } + } + + fun act(action: HomeAction, shell: ShellState, server: JellyfinServer, user: JellyfinUser) { + when (action) { + HomeAction.Discover -> openRoot(shell, "discover") + HomeAction.Retry -> viewModelScope.launch { load(server, user, shell.person.key, retry = true) } + is HomeAction.SeeAll -> if (action.row.target in shell.tabs) openRoot(shell, action.row.target!!) else seeAll.open(shell.person.key, action.row.id, action.row.title, action.row.allCards.map { it.libraryTitle() }, navigation) + is HomeAction.Details -> navigation.navigateTo(Destination.Wolfskin(titleRoute(action.title.id))) + is HomeAction.Play -> viewModelScope.launch { + if (!snapshot.jellyfinAvailable || shell.person.key != user.name.orEmpty().lowercase()) { + showToast(RecoveryMessage.PlaybackUnavailable) + return@launch + } + try { + val id = withContext(Dispatchers.IO) { home.playableId(user.id, action.title) } + if (id == null) showToast(RecoveryMessage.PlaybackUnavailable) + else navigation.navigateTo(Destination.Playback(id, if (action.resume) (action.title.resumeSeconds * 1000).toLong() else 0L)) + } catch (exception: Exception) { + if (exception is CancellationException) throw exception + showToast(RecoveryMessage.PlaybackUnavailable) + } + } + } + } + + private fun openRoot(shell: ShellState, route: String) { + shell.enterDestination(route) + shell.focusNav(shell.tabs.indexOf(route)) + shell.key(ShellKey.Ok) + } + + private fun showToast(message: String) { + toast = message + viewModelScope.launch { delay(WolfskinTokens.Motion.toast.toLong()); if (toast == message) toast = null } + } +} + +/** Complete catalogue projections feed the shared See all grid without another source read. */ +internal fun HomeTitle.libraryTitle(): LibraryTitle = LibraryTitle( + id = id, title = title, type = type, year = year, runtimeSeconds = runtimeSeconds?.toLong(), seasons = seasons, + poster = poster, played = played, progress = runtimeSeconds?.let { if (it > 0) (resumeSeconds / it).toFloat() else 0f } ?: 0f, + addedAt = addedAt, tmdbId = tmdbId?.toString(), + availability = if (held) "In your library" else otherOwner?.let { "In $itโ€™s library" }.orEmpty(), + badge = if (held) "held" else null, + ratings = ratings.map { rating -> + when (rating.mark) { + "fresh" -> LibraryRating("rtCritics", rating.score, "Fresh") + "rotten" -> LibraryRating("rtCritics", rating.score, "Rotten") + "tomato" -> LibraryRating("rtCritics", rating.score) + "upright" -> LibraryRating("rtAudience", rating.score, "Upright") + "spilled" -> LibraryRating("rtAudience", rating.score, "Spilled") + else -> LibraryRating(rating.mark, rating.score) + } + }, +) + +/** The shell keeps its focus memory while playback or later-slice screens are pushed above Home. */ +@Composable +fun HomeDestination(shell: ShellState, server: JellyfinServer, user: JellyfinUser, modifier: Modifier = Modifier, model: WolfskinHomeViewModel = hiltViewModel()) { + LaunchedEffect(shell.person.key, server.id, user.id) { model.load(server, user, shell.person.key) } + Box(modifier) { + HomeScreen(shell, model.snapshot, Modifier.fillMaxSize()) { model.act(it, shell, server, user) } + model.toast?.let { RecoveryToast(it) } + } +} diff --git a/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/RequestsRefresh.kt b/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/RequestsRefresh.kt new file mode 100644 index 00000000..2c88cc9b --- /dev/null +++ b/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/RequestsRefresh.kt @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-2.0-only +package org.justinvisser.wolfskin.tv + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.compose.LocalLifecycleOwner +import androidx.lifecycle.repeatOnLifecycle +import kotlinx.coroutines.currentCoroutineContext +import kotlinx.coroutines.delay +import kotlinx.coroutines.isActive +import org.justinvisser.wolfskin.design.ShellState +import org.justinvisser.wolfskin.design.WolfskinTokens + +/** Foreground refreshes once; only an open sheet or an unsettled request keeps polling. */ +@Composable +internal fun RequestsRefresh(state: ShellState, refresh: () -> Unit) { + val owner = LocalLifecycleOwner.current + LaunchedEffect(state, state.person.key, owner) { + owner.lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) { + refreshRequestsWhileStarted(state, refresh) + } + } +} + +/** Cancellation on leaving STARTED stops polling; reentry performs a fresh foreground read. */ +internal suspend fun refreshRequestsWhileStarted(state: ShellState, refresh: () -> Unit) { + refresh() + while (currentCoroutineContext().isActive) { + delay(WolfskinTokens.Behaviour.requestsPollSeconds.toLong() * 1000L) + if (state.requestsVisible || state.requests.snapshot.openCount > 0) refresh() + } +} diff --git a/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/ShellPeople.kt b/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/ShellPeople.kt new file mode 100644 index 00000000..2b7562df --- /dev/null +++ b/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/ShellPeople.kt @@ -0,0 +1,23 @@ +package org.justinvisser.wolfskin.tv + +import android.content.Context +import com.github.damontecres.wholphin.BuildConfig +import com.github.damontecres.wholphin.data.model.JellyfinUser +import org.json.JSONObject +import org.justinvisser.wolfskin.design.ShellPerson + +/** Prototype identities are packaged exclusively in debug assets, never release resources. */ +fun readShellPeople(context: Context, saved: List): List { + if (BuildConfig.DEBUG) { + val json = context.assets.open("wolfskin-shell.json").bufferedReader().use { JSONObject(it.readText()) } + val profiles = json.getJSONArray("profiles") + return List(profiles.length()) { index -> + val person = profiles.getJSONObject(index) + ShellPerson(person.getString("key"), person.getString("name"), person.getString("initial"), person.getJSONObject("destinations").has("Anime")) + } + } + return saved.map { user -> + val name = user.name.orEmpty() + ShellPerson(name.lowercase(), name, name.take(1).uppercase(), false) + } +} diff --git a/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/ShellRequests.kt b/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/ShellRequests.kt new file mode 100644 index 00000000..a5b32953 --- /dev/null +++ b/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/ShellRequests.kt @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0-only +package org.justinvisser.wolfskin.tv + +import android.content.Context +import com.github.damontecres.wholphin.BuildConfig +import org.justinvisser.wolfskin.design.ComingInSnapshot +import org.justinvisser.wolfskin.design.ComingInStatus +import org.justinvisser.wolfskin.design.readComingInFixture + +/** Release stays unavailable until Conductarr sign-in supplies an authenticated generated client. */ +fun readShellRequests(context: Context): ComingInSnapshot { + if (!BuildConfig.DEBUG) return ComingInSnapshot() + val json = context.assets.open("wolfskin-requests.json").bufferedReader().use { it.readText() } + val items = readComingInFixture(json) { name -> + context.assets.open("wolfskin-requests/$name").use { it.readBytes() } + } + return ComingInSnapshot(items.take(6), ComingInStatus.Ready, signedIn = true) +} diff --git a/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/ShellRouting.kt b/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/ShellRouting.kt new file mode 100644 index 00000000..dffa611b --- /dev/null +++ b/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/ShellRouting.kt @@ -0,0 +1,16 @@ +package org.justinvisser.wolfskin.tv + +import com.github.damontecres.wholphin.ui.nav.Destination +import org.jellyfin.sdk.model.api.BaseItemKind + +/** The rollout switch changes only intercepted screens; unrelated destinations always pass through. */ +fun resolveUpstreamDestination(destination: Destination, wolfskinEnabled: Boolean, libraries: Map): Destination? = + when (destination) { + is Destination.Home -> if (wolfskinEnabled) null else destination + is Destination.MediaItem -> if (wolfskinEnabled && destination.type in TITLE_KINDS) null else destination + is Destination.Wolfskin -> if (!wolfskinEnabled && destination.route in LIBRARY_ROUTES) libraries[destination.route] else null + else -> destination + } + +private val LIBRARY_ROUTES = setOf("movies", "shows", "anime") +private val TITLE_KINDS = setOf(BaseItemKind.MOVIE, BaseItemKind.SERIES, BaseItemKind.EPISODE, BaseItemKind.PERSON) diff --git a/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/TitleDestination.kt b/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/TitleDestination.kt new file mode 100644 index 00000000..913f51e7 --- /dev/null +++ b/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/TitleDestination.kt @@ -0,0 +1,250 @@ +package org.justinvisser.wolfskin.tv + +import android.content.Context +import android.net.Uri +import androidx.activity.compose.BackHandler +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.github.damontecres.wholphin.BuildConfig +import com.github.damontecres.wholphin.preferences.UserPreferences +import com.github.damontecres.wholphin.services.NavigationManager +import com.github.damontecres.wholphin.ui.nav.Destination +import dagger.hilt.android.lifecycle.HiltViewModel +import dagger.hilt.android.qualifiers.ApplicationContext +import kotlinx.coroutines.CancellationException +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import org.justinvisser.wolfskin.design.PersonState +import org.justinvisser.wolfskin.design.PersonSurface +import org.justinvisser.wolfskin.design.RecoveryMessage +import org.justinvisser.wolfskin.design.ShellPerson +import org.justinvisser.wolfskin.design.ShellState +import org.justinvisser.wolfskin.design.TitleAction +import org.justinvisser.wolfskin.design.TitleConnection +import org.justinvisser.wolfskin.design.TitleItem +import org.justinvisser.wolfskin.design.TitlePageData +import org.justinvisser.wolfskin.design.TitleReadStatus +import org.justinvisser.wolfskin.design.TitleState +import org.justinvisser.wolfskin.design.TitleSurface +import org.justinvisser.wolfskin.tv.read.TitleReadFacade +import java.util.UUID +import javax.inject.Inject + +/** Title and performer routes remain within the single existing Wolfskin destination subtype. */ +fun titleRoute(id: String): String = "title/${Uri.encode(id)}" +fun personRoute(id: String): String = "person/${Uri.encode(id)}" + +/** Each navigation entry owns its title focus and selections across nested person/title pages. */ +@HiltViewModel +class WolfskinTitleViewModel @Inject constructor( + @param:ApplicationContext private val context: Context, + private val facade: TitleReadFacade, + private val fixtureProvider: TitleFixtureProvider, + private val navigation: NavigationManager, +) : ViewModel() { + var title by mutableStateOf(null) + private set + var person by mutableStateOf(null) + private set + private var route = "" + private lateinit var viewer: ShellPerson + private lateinit var preferences: UserPreferences + private var fixture: TitleFixture? = null + private var personReadPending = false + private var personReadFinished = false + private var loadJob: Job? = null + private val saveMutex = Mutex() + private val fixtureSelections by lazy { context.getSharedPreferences("wolfskin-title-fixture", Context.MODE_PRIVATE) } + + /** Fixture reads are exclusively debug assets; real ids always use the authenticated Jellyfin facade. */ + fun load(destination: String, selected: ShellPerson, userPreferences: UserPreferences) { + if (route == destination && ::viewer.isInitialized && viewer.key == selected.key) return + route = destination + loadJob?.cancel() + person = null + fixture = null + personReadPending = false + personReadFinished = false + viewer = selected + preferences = userPreferences + val id = Uri.decode(destination.substringAfter('/')) + title = TitleState(TitlePageData(TitleItem(id, "", if (destination.startsWith("person/")) "person" else "movie"), status = TitleReadStatus.Loading), viewer, ::handle) + loadJob = viewModelScope.launch { + if (BuildConfig.DEBUG && id.toUuidOrNull() == null) { + val source = fixtureProvider.read() + fixture = source + if (destination.startsWith("person/")) { + val (actor, credits) = withContext(Dispatchers.IO) { source.person(id, selected.key) } + person = PersonState(actor, credits, ::handle) + } else { + val data = withContext(Dispatchers.IO) { source.title(id, selected.key) } + val key = "${viewer.key}:${data.item.id}" + val watchKey = "${viewer.key}:${data.watchTarget.id}" + title = TitleState(data.copy( + selectedVersion = fixtureSelections.getString("$key:version", null), + selectedAudio = if (fixtureSelections.contains("$key:audio")) fixtureSelections.getInt("$key:audio", -1) else null, + selectedSubtitle = fixtureSelections.getInt("$key:subtitle", -1), + watchTarget = data.watchTarget.copy(watched = fixtureSelections.getBoolean("$watchKey:watched", data.watchTarget.watched)), + hidden = fixtureSelections.getBoolean("$key:hidden", data.hidden), + ), viewer, ::handle) + } + } else if (destination.startsWith("person/")) readPerson(id) else readTitle(id) + } + } + + private suspend fun readTitle(id: String, retry: Boolean = false) { + val uuid = id.toUuidOrNull() ?: return + val current = title ?: return + try { + if (current.data.status != TitleReadStatus.Ready) facade.readSaved(uuid, preferences)?.let { current.update(it) } + val data = facade.read(uuid, current.takeIf { it.data.status == TitleReadStatus.Ready }?.season, preferences) + current.update(data) + } catch (exception: Exception) { + if (exception is CancellationException) throw exception + if (current.data.status == TitleReadStatus.Ready) { + if (current.data.episodesStatus == TitleReadStatus.Loading) current.restoreSeason() + } else current.update(current.data.copy(status = TitleReadStatus.Unavailable)) + if (current.data.status == TitleReadStatus.Ready || retry) current.toast = RecoveryMessage.StillUnreachable + } + } + + private suspend fun readPerson(id: String, retry: Boolean = false) { + if (personReadPending || personReadFinished) return + val uuid = id.toUuidOrNull() ?: return + val owner = viewer.key + personReadPending = true + try { + if (person == null) facade.readPersonSaved(uuid)?.let { saved -> + if (owner == viewer.key) person = newPerson(saved.person, saved.credits).apply { savedAt = saved.savedAt } + } + val start = if (person?.savedAt != null) 0 else person?.credits?.size ?: 0 + val result = facade.readPerson(uuid, start) + if (owner != viewer.key) return + val current = person + val credits = if (start == 0) result.credits else (current?.credits.orEmpty() + result.credits).distinctBy { it.id } + if (current == null) person = newPerson(result.person, credits) else current.update(result.person, credits) + personReadFinished = result.credits.size < 200 + } catch (exception: Exception) { + if (exception is CancellationException) throw exception + if (owner == viewer.key) { + person?.toast = RecoveryMessage.StillUnreachable + if (person == null) { + title?.update(title!!.data.copy(status = TitleReadStatus.Unavailable)) + if (retry) title?.toast = RecoveryMessage.StillUnreachable + } + } + } finally { if (owner == viewer.key) personReadPending = false } + } + + private fun newPerson(actor: org.justinvisser.wolfskin.design.TitlePerson, credits: List) = + PersonState(actor, credits, ::handle) { viewModelScope.launch { readPerson(actor.id) } } + + private fun handle(action: TitleAction) { + when (action) { + TitleAction.Pop -> navigation.goBack() + is TitleAction.Person -> navigation.navigateTo(action.person.id.toUuidOrNull()?.let { Destination.MediaItem(it, org.jellyfin.sdk.model.api.BaseItemKind.PERSON) } ?: Destination.Wolfskin(personRoute(action.person.id))) + is TitleAction.OpenTitle -> navigation.navigateTo(action.item.id.toUuidOrNull()?.let { Destination.MediaItem(it, when (action.item.kind) { + "movie" -> org.jellyfin.sdk.model.api.BaseItemKind.MOVIE + "episode" -> org.jellyfin.sdk.model.api.BaseItemKind.EPISODE + else -> org.jellyfin.sdk.model.api.BaseItemKind.SERIES + }) } ?: Destination.Wolfskin(titleRoute(action.item.id))) + is TitleAction.Play -> play(action.item.id.toUuidOrNull(), if (action.restart) 0 else action.item.resumeSeconds * 1000) + is TitleAction.Trailer -> if (action.url.startsWith("jellyfin:")) play(action.url.removePrefix("jellyfin:").toUuidOrNull(), 0) + else if (!TitleTrailer(context).open(action.url)) title?.toast = "No YouTube app is available to play this trailer." + is TitleAction.Version, is TitleAction.Track, is TitleAction.Watched -> savePlayback(action) + is TitleAction.Season -> { + loadJob?.cancel() + loadJob = viewModelScope.launch { + val current = title ?: return@launch + current.showSeasonLoading() + val source = fixture + if (source == null) readTitle(Uri.decode(route.substringAfter('/'))) + else { + val data = withContext(Dispatchers.IO) { source.title(Uri.decode(route.substringAfter('/')), viewer.key, action.number) } + current.update(data.copy(selectedVersion = current.versionId, selectedAudio = current.audioIndex, + selectedSubtitle = current.subtitleIndex, watchTarget = current.data.watchTarget.copy(watched = current.watched), hidden = current.data.hidden)) + } + } + } + TitleAction.Retry -> viewModelScope.launch { + if (fixture == null) { + if (route.startsWith("person/")) readPerson(Uri.decode(route.substringAfter('/')), retry = true) else readTitle(Uri.decode(route.substringAfter('/')), retry = true) + } + else title?.toast = RecoveryMessage.StillUnreachable + } + is TitleAction.Request, is TitleAction.Requests -> title?.toast = "Requests need this TV to be signed in to Conductarr." + is TitleAction.Hide -> if (fixture != null) fixtureSelections.edit().putBoolean("${viewer.key}:${action.item.id}:hidden", action.hidden).apply() + } + } + + private fun play(id: UUID?, position: Long) { + viewModelScope.launch { + try { + if (id == null) throw IllegalArgumentException("No Jellyfin playback identity") + facade.preparePlayback(id) + navigation.navigateTo(Destination.Playback(id, position)) + } catch (exception: Exception) { + if (exception is CancellationException) throw exception + title?.toast = RecoveryMessage.PlaybackUnavailable + } + } + } + + private fun savePlayback(action: TitleAction) { + val current = title ?: return + if (fixture != null) { + val edits = fixtureSelections.edit() + when (action) { + is TitleAction.Version -> edits.putString("${viewer.key}:${action.item.id}:version", action.version.id) + is TitleAction.Track -> { + action.audio?.let { edits.putInt("${viewer.key}:${action.item.id}:audio", it) } + edits.putInt("${viewer.key}:${action.item.id}:subtitle", action.subtitle) + } + is TitleAction.Watched -> edits.putBoolean("${viewer.key}:${action.item.id}:watched", action.watched) + else -> Unit + } + edits.apply() + current.confirmPlayback(action) + return + } + viewModelScope.launch { + saveMutex.withLock { + try { facade.apply(action); current.confirmPlayback(action) } + catch (exception: Exception) { + if (exception is CancellationException) throw exception + current.rejectPlayback(action) + current.toast = "Couldnโ€™t save that change. Try again." + } + } + } + } +} + +/** The screen's own Back handler closes its sheet before delegating a navigation pop. */ +@Composable +fun TitleDestination(route: String, shell: ShellState, preferences: UserPreferences, modifier: Modifier = Modifier, viewModel: WolfskinTitleViewModel = hiltViewModel()) { + LaunchedEffect(route, shell.person.key) { viewModel.load(route, shell.person, preferences) } + val title = viewModel.title?.takeIf { it.person.key == shell.person.key } + LaunchedEffect(title?.data?.status) { + if (title?.data?.status == TitleReadStatus.Ready) shell.navFocused = false + } + val person = viewModel.person.takeIf { title != null } + BackHandler(enabled = title != null) { + title?.back(shell) + } + if (person != null && route.startsWith("person/")) PersonSurface(person, shell, modifier) + else if (title != null) TitleSurface(title, shell, modifier) +} + +private fun String.toUuidOrNull(): UUID? = try { UUID.fromString(this) } catch (_: IllegalArgumentException) { null } diff --git a/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/TitleFixture.kt b/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/TitleFixture.kt new file mode 100644 index 00000000..3e9709aa --- /dev/null +++ b/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/TitleFixture.kt @@ -0,0 +1,144 @@ +package org.justinvisser.wolfskin.tv + +import android.content.Context +import com.github.damontecres.wholphin.BuildConfig +import dagger.hilt.android.qualifiers.ApplicationContext +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import javax.inject.Inject +import javax.inject.Singleton +import org.json.JSONArray +import org.json.JSONObject +import org.justinvisser.wolfskin.design.ShellPerson +import org.justinvisser.wolfskin.design.TitleConnection +import org.justinvisser.wolfskin.design.TitleItem +import org.justinvisser.wolfskin.design.TitlePageData +import org.justinvisser.wolfskin.design.TitlePerson +import org.justinvisser.wolfskin.design.LibraryRating +import org.justinvisser.wolfskin.design.TitleTrack +import org.justinvisser.wolfskin.design.TitleVersion +import java.util.Locale + +/** The locked prototype is projected only by debug callers and offline JVM captures. */ +class TitleFixture(private val fixture: JSONObject) { + private val profiles = fixture.getJSONArray("profiles").objects() + private val cast = fixture.getJSONObject("cast") + private val availableArt = fixture.getJSONArray("availableArt").let { array -> (0 until array.length()).map { array.getString(it) }.toSet() } + val people: List = profiles.map { ShellPerson(it.getString("key"), it.getString("name"), it.getString("initial"), it.getJSONObject("destinations").has("Anime")) } + private val all = profiles.flatMap { profile -> listOf("movies", "shows", "anime", "discover").flatMap { profile.getJSONArray(it).objects() } }.distinctBy { key(it) } + private val pool = profiles.flatMap { it.getJSONArray("discover").objects() }.distinctBy { key(it) } + + /** Each viewer gets their own ownership, resume target and episode watch identity. */ + fun title(id: String, person: String, season: Int? = null): TitlePageData { + val profile = profiles.first { it.getString("key") == person } + val library = listOf("movies", "shows", "anime").flatMap { profile.getJSONArray(it).objects() } + val episodes = listOf("resume", "nextUp").flatMap { profile.getJSONArray(it).objects() } + val source = (all + episodes).first { it.getString("id") == id || key(it) == id || it.getString("title") == id } + val selectedEpisode = source.takeIf { it.getString("type") == "episode" } + val container = if (selectedEpisode != null) library.first { it.getString("title") == selectedEpisode.getString("seriesTitle") } else source + val own = library.firstOrNull { key(it) == key(container) } + val item = item(own ?: container, person) + val play = selectedEpisode ?: episodes.firstOrNull { it.optString("seriesTitle") == container.getString("title") } + ?: own?.takeIf { it.optDouble("progress") > 0 } + val target = play?.let { item(it, person) } ?: item.takeIf { it.held && it.kind == "movie" } + val selectedSeason = season ?: play?.optInt("seasonNumber")?.takeIf { it > 0 } ?: 1 + val related = (pool + library).filter { key(it) != key(container) && overlap(it, container) > 0 } + .sortedByDescending { overlap(it, container) }.distinctBy { key(it) }.take(16).map { item(it, person) } + val castMembers = cast.optJSONArray(key(container))?.objects().orEmpty().map { member -> + TitlePerson(member.getString("name"), member.getString("name"), member.optString("character"), art(member.optString("img").takeIf { it.isNotEmpty() }?.let { "assets/cast/$it" })) + } + return TitlePageData(item, play?.let { item(it, person) }, selectedEpisode?.let { item(it, person) } ?: item, + versions = target?.let { versions(it) }.orEmpty(), + trailerUrl = if (item.held && key(container) in TRAILERS) "fixture:trailer" else null, + cast = castMembers, related = related, episodes = episodes.filter { it.optString("seriesTitle") == container.getString("title") && it.optInt("seasonNumber") == selectedSeason }.map { item(it, person) }, + connection = TitleConnection.SignedIn, pick = container.optString("source") == "materialized_personal_recommendation", selectedSeason = selectedSeason) + } + + /** Only real household credits are retained; prototype filler is never promoted to filmography. */ + fun person(name: String, viewer: String): Pair> { + val credits = all.mapNotNull { title -> + val actor = cast.optJSONArray(key(title))?.objects()?.firstOrNull { it.getString("name") == name } ?: return@mapNotNull null + item(title, viewer).copy(character = actor.optString("character")) + }.sortedWith(compareByDescending { it.year ?: 0 }.thenBy { it.name.replace(Regex("^(The|A|An) "), "") }) + val actor = cast.keys().asSequence().flatMap { cast.getJSONArray(it).objects() }.first { it.getString("name") == name } + return TitlePerson(name, name, portrait = art(actor.optString("img").takeIf { it.isNotEmpty() }?.let { "assets/cast/$it" })) to credits + } + + private fun item(source: JSONObject, person: String): TitleItem { + val owners = profiles.filter { profile -> listOf("movies", "shows", "anime").any { bucket -> profile.getJSONArray(bucket).objects().any { key(it) == key(source) } } } + val held = source.optString("type") == "episode" || owners.any { it.getString("key") == person } + return TitleItem( + source.getString("id"), source.getString("title"), source.getString("type"), source.optInt("year").takeIf { it > 0 }, + source.optLong("runtimeSeconds"), source.optInt("seasonCount"), source.optString("overview"), + source.optJSONArray("genres")?.let { values -> (0 until values.length()).map { values.getString(it) } }.orEmpty(), + art(source.optString("poster")), art(source.optString("backdrop")), held, source.optBoolean("played"), source.optDouble("resumeSeconds").toLong(), + seriesName = source.optString("seriesTitle").takeIf { it.isNotEmpty() }, season = source.optInt("seasonNumber"), episode = source.optInt("episodeNumber"), + ratings = ratings(source), otherOwners = owners.filter { it.getString("key") != person }.map { it.getString("name") }, + isPosterBackdrop = source.optJSONObject("artwork")?.optString("backdropKind") == "poster_crop", + ) + } + + private fun art(path: String?): String? = path?.takeIf { it in availableArt }?.let { "file:///android_asset/wolfskin-titles/$it" } + + private fun ratings(item: JSONObject): List { + val episode = item.optString("type") == "episode" + if (episode) { + val series = all.firstOrNull { it.optString("title") == item.optString("seriesTitle") } + val base = series?.let { ratings(it) }.orEmpty() + val score = item.optDouble("communityRating", Double.NaN) + return if (score in 0.0..10.0) base.filter { it.source != "tmdb" } + LibraryRating("tmdb", score, episode = true) else base + } + val ratings = item.optJSONObject("ratings") ?: JSONObject().apply { + if (!item.isNull("criticRating")) put("rtCritics", item.getDouble("criticRating")) + if (!item.isNull("communityRating")) put("tmdb", item.getDouble("communityRating")) + } + return buildList { + if (!ratings.isNull("rtCritics")) add(LibraryRating("rtCritics", ratings.getDouble("rtCritics"), ratings.optString("rtCriticsLabel").takeIf { it.isNotEmpty() })) + if (!ratings.isNull("rtAudience")) add(LibraryRating("rtAudience", ratings.getDouble("rtAudience"), ratings.optString("rtAudienceLabel").takeIf { it.isNotEmpty() })) + if (item.optString("type") == "movie" && (!ratings.has("imdbVotes") || ratings.optInt("imdbVotes") > 0) && !ratings.isNull("imdb")) add(LibraryRating("imdb", ratings.getDouble("imdb"))) + if (isEmpty() && (!ratings.has("tmdbVotes") || ratings.optInt("tmdbVotes") > 0) && !ratings.isNull("tmdb")) add(LibraryRating("tmdb", ratings.getDouble("tmdb"))) + }.filter { it.score in 0.0..if (it.source.startsWith("rt")) 100.0 else 10.0 } + } + + private fun versions(item: TitleItem): List { + val subtitles = listOf(TitleTrack(2, "English"), TitleTrack(3, "English SDH"), TitleTrack(4, "Dutch")) + fun version(id: String, name: String, video: String, bitrate: Double, container: String, audio: List) = + TitleVersion(id, name, video, "$bitrate Mbps", String.format(Locale.US, "%.1f GB", bitrate * item.runtimeSeconds / 8000), container, audio, subtitles) + val standardAudio = listOf(TitleTrack(0, "English ยท AC3 5.1", true), TitleTrack(1, "English ยท AAC 2.0")) + return if (item.name == "Locke") listOf( + version("v1", "2160p ยท HDR10 ยท Remux", "2160p HEVC Main 10 ยท HDR10", 58.4, "MKV", listOf(TitleTrack(0, "English ยท TrueHD 7.1", true), TitleTrack(1, "English ยท AC3 5.1"))), + version("v2", "1080p ยท SDR", "1080p H.264 High ยท SDR", 9.8, "MP4", standardAudio), + ) else listOf(version("v1", "1080p ยท SDR", "1080p H.264 High ยท SDR", 8.2, "MKV", standardAudio)) + } + + private fun key(item: JSONObject): String = "${item.getString("type")}:${item.optLong("tmdbId")}" + private fun overlap(first: JSONObject, second: JSONObject): Int { + fun genres(item: JSONObject): Set = item.optJSONArray("genres")?.let { array -> (0 until array.length()).flatMap { + when (val genre = array.getString(it)) { + "Sci-Fi & Fantasy" -> listOf("Science Fiction", "Fantasy") + "Action & Adventure" -> listOf("Action", "Adventure") + "Sci-Fi" -> listOf("Science Fiction") + else -> listOf(genre) + } + }.toSet() }.orEmpty() + return genres(first).intersect(genres(second)).size + } + + companion object { + private val TRAILERS = setOf("movie:14069", "movie:210479", "movie:318917", "movie:42994", "movie:123431", "tv:83867", "tv:76479", "tv:1215", "tv:1437", "tv:67070", "movie:1930", "movie:21469", "movie:76203", "tv:60948") + } +} + +/** Every title entry shares one parsed, read-only debug fixture; release callers cannot load it. */ +@Singleton +class TitleFixtureProvider @Inject constructor(@param:ApplicationContext private val context: Context) { + private val fixture by lazy { + TitleFixture(context.assets.open("wolfskin-titles.json").bufferedReader().use { JSONObject(it.readText()) }) + } + suspend fun read(): TitleFixture = withContext(Dispatchers.IO) { + check(BuildConfig.DEBUG) { "Title fixtures are debug-only" } + fixture + } +} + +private fun JSONArray.objects(): List = List(length()) { getJSONObject(it) } diff --git a/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/TitleTrailer.kt b/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/TitleTrailer.kt new file mode 100644 index 00000000..0dce1f9f --- /dev/null +++ b/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/TitleTrailer.kt @@ -0,0 +1,33 @@ +package org.justinvisser.wolfskin.tv + +import android.content.ActivityNotFoundException +import android.content.Context +import android.content.Intent +import android.content.pm.PackageManager +import android.net.Uri + +/** Only an installed app that handles the YouTube scheme may receive a remote trailer. */ +class TitleTrailer(private val context: Context) { + /** A missing handler leaves the title in place rather than falling back to a browser. */ + fun open(url: String): Boolean { + val source = Uri.parse(url) + val video = when (source.host?.lowercase()) { + "youtu.be" -> source.pathSegments.firstOrNull() + "youtube.com", "www.youtube.com", "m.youtube.com" -> source.getQueryParameter("v") + ?: source.pathSegments.takeIf { it.firstOrNull() in setOf("shorts", "embed") }?.getOrNull(1) + else -> null + } ?: return false + val intent = Intent(Intent.ACTION_VIEW, Uri.parse("vnd.youtube:$video")).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + val handler = context.packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY) + .firstOrNull { it.activityInfo.exported } ?: return false + intent.setPackage(handler.activityInfo.packageName) + return try { + context.startActivity(intent) + true + } catch (_: ActivityNotFoundException) { + false + } catch (_: SecurityException) { + false + } + } +} diff --git a/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/WolfskinApp.kt b/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/WolfskinApp.kt new file mode 100644 index 00000000..63e29f9b --- /dev/null +++ b/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/WolfskinApp.kt @@ -0,0 +1,251 @@ +package org.justinvisser.wolfskin.tv + +import android.content.Context +import androidx.activity.compose.BackHandler +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.compositionLocalOf +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.lifecycle.viewmodel.navigation3.rememberViewModelStoreNavEntryDecorator +import androidx.navigation3.runtime.NavEntry +import androidx.navigation3.runtime.rememberSaveableStateHolderNavEntryDecorator +import androidx.navigation3.ui.NavDisplay +import com.github.damontecres.wholphin.data.ServerRepository +import com.github.damontecres.wholphin.data.model.JellyfinServer +import com.github.damontecres.wholphin.data.model.JellyfinUser +import com.github.damontecres.wholphin.preferences.UserPreferences +import com.github.damontecres.wholphin.services.BackdropResult +import com.github.damontecres.wholphin.services.BackdropService +import com.github.damontecres.wholphin.services.NavigationManager +import com.github.damontecres.wholphin.services.SetupDestination +import com.github.damontecres.wholphin.services.SetupNavigationManager +import com.github.damontecres.wholphin.ui.nav.Backdrop +import com.github.damontecres.wholphin.ui.nav.Destination +import com.github.damontecres.wholphin.ui.nav.DestinationContent +import com.github.damontecres.wholphin.ui.preferences.PreferenceScreenOption +import dagger.hilt.android.lifecycle.HiltViewModel +import dagger.hilt.android.qualifiers.ApplicationContext +import javax.inject.Inject +import javax.inject.Singleton +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.launch +import org.jellyfin.sdk.model.serializer.toUUIDOrNull +import kotlinx.coroutines.withContext +import org.justinvisser.wolfskin.design.PeopleStatus +import org.justinvisser.wolfskin.design.SettingsList +import org.justinvisser.wolfskin.design.ShellAction +import org.justinvisser.wolfskin.design.ShellPerson +import org.justinvisser.wolfskin.design.ShellPlaceholder +import org.justinvisser.wolfskin.design.ShellState +import org.justinvisser.wolfskin.design.ShellSurface +import org.justinvisser.wolfskin.design.WolfskinTheme +import org.justinvisser.wolfskin.tv.read.LibraryReadFacade +import org.justinvisser.wolfskin.design.DiscoverOverlay +import org.justinvisser.wolfskin.design.DiscoverScreen + +/** View memory must outlive the upstream setup entry replaced by a user switch. */ +@Singleton +class WolfskinSession @Inject constructor() { + var state by mutableStateOf(null) + var serverId: String? = null + var onAction: (ShellAction) -> Unit = {} +} + +/** The shell routes only through the existing NavigationManager and real settings pages. */ +@HiltViewModel +class WolfskinShellViewModel @Inject constructor( + @param:ApplicationContext private val context: Context, + val session: WolfskinSession, + private val repository: ServerRepository, + private val navigation: NavigationManager, + private val setupNavigation: SetupNavigationManager, + private val backdrop: BackdropService, + val libraries: LibraryReadFacade, + val seeAll: WolfskinSeeAllLists, +) : ViewModel() { + val backdropFlow: StateFlow = backdrop.backdropFlow + private val requestsSnapshot by lazy { readShellRequests(context) } + var libraryDestinations by mutableStateOf>(emptyMap()) + private set + var signedInPerson by mutableStateOf("") + private set + + suspend fun load(server: JellyfinServer, user: JellyfinUser) { + WolfskinScreenPreference.initialize(context) + signedInPerson = user.name.orEmpty().lowercase() + if (session.state == null || session.serverId != server.id.toString()) { + val saved = withContext(Dispatchers.IO) { repository.serverDao.getServer(server.id)?.users.orEmpty() } + val people = readShellPeople(context, saved.ifEmpty { listOf(user) }) + session.serverId = server.id.toString() + session.state = ShellState(people, signedInPerson) { session.onAction(it) } + } + session.onAction = { action -> handleAction(action, server, user) } + try { + libraryDestinations = libraries.readDestinations(user.id) + } catch (exception: Exception) { + if (exception is kotlinx.coroutines.CancellationException) throw exception + libraryDestinations = emptyMap() + } + } + + fun clearBackdrop() { viewModelScope.launch { backdrop.clearBackdrop() } } + + /** The debug fixture is the only Requests supplier until TV sign-in is enabled. */ + fun refreshRequests() = refreshRequests(retry = false) + + private fun refreshRequests(retry: Boolean) { + val shell = session.state ?: return + val target = shell.requests + viewModelScope.launch { + val snapshot = withContext(Dispatchers.IO) { requestsSnapshot } + target.update(snapshot) + if (retry && snapshot.status == org.justinvisser.wolfskin.design.ComingInStatus.Unavailable && shell.requests === target) { + shell.toast = org.justinvisser.wolfskin.design.RecoveryMessage.StillUnreachable + } + } + } + + private fun handleAction(action: ShellAction, server: JellyfinServer, user: JellyfinUser) { + when (action) { + is ShellAction.Destination -> if (action.route == "settings") navigation.navigateTo(Destination.Wolfskin("settings")) else navigation.replace(if (action.route == "home") Destination.Home() else Destination.Wolfskin(action.route)) + ShellAction.Pop -> navigation.goBack() + is ShellAction.HandOff -> navigation.navigateTo(handOffDestination(action.group)) + is ShellAction.Person -> selectPerson(action.person, server, user) + ShellAction.RetryPeople -> viewModelScope.launch { load(server, user) } + ShellAction.RetryRequests -> refreshRequests(retry = true) + is ShellAction.RequestTitle -> navigation.navigateTo(Destination.Wolfskin(titleRoute("${action.request.mediaType}:${action.request.tmdbId}"))) + } + } + + private fun selectPerson(person: ShellPerson, server: JellyfinServer, user: JellyfinUser) { + navigation.replace(Destination.Home()) + if (person.key == user.name.orEmpty().lowercase()) return + viewModelScope.launch { + val saved = withContext(Dispatchers.IO) { + repository.serverDao.getServer(server.id)?.users?.firstOrNull { it.name.equals(person.name, ignoreCase = true) } + } + if (saved == null || saved.isProtected) { + signedInPerson = "" + return@launch + } + try { + val current = repository.changeUser(server, saved) + setupNavigation.navigateTo(SetupDestination.AppContent(current)) + } catch (exception: Exception) { + if (exception is kotlinx.coroutines.CancellationException) throw exception + signedInPerson = "" + session.state?.apply { peopleStatus = PeopleStatus.Unavailable; pickerVisible = true } + } + } + } +} + +/** Settings groups open the fork's own pages; the prototype hand-off panel is never shipped. */ +fun handOffDestination(group: String): Destination = when (group) { + "advanced" -> Destination.Settings(PreferenceScreenOption.ADVANCED) + "profile" -> Destination.HomeSettings + else -> Destination.Settings(PreferenceScreenOption.BASIC) +} + +private val LocalShellState = compositionLocalOf { error("Wolfskin destination requires the shell") } + +/** The one upstream hook preserves destination decorators and full-screen hand-offs. */ +@Composable +fun WolfskinApp( + server: JellyfinServer, + user: JellyfinUser, + navigationManager: NavigationManager, + preferences: UserPreferences, + modifier: Modifier = Modifier, + viewModel: WolfskinShellViewModel = hiltViewModel(), +) { + LaunchedEffect(server.id, user.id) { viewModel.load(server, user) } + val loading = remember(user.id) { + ShellState(listOf(ShellPerson(user.name.orEmpty().lowercase(), user.name.orEmpty(), user.name.orEmpty().take(1), false)), user.name.orEmpty().lowercase()).apply { peopleStatus = PeopleStatus.Loading } + } + val state = viewModel.session.state ?: loading + val discover = rememberDiscoverState( + state, + { route -> navigationManager.navigateTo(Destination.Wolfskin(route)) }, + navigationManager::goBack, + ) + RequestsRefresh(state, viewModel::refreshRequests) + WolfskinTheme { + CompositionLocalProvider(LocalShellState provides state, LocalDiscoverState provides discover) { + Box(modifier) { + val current = navigationManager.backStack.last() + if (!state.pickerVisible && resolveUpstreamDestination(current, WolfskinScreenPreference.enabled, viewModel.libraryDestinations) != null) { + val backdrop by viewModel.backdropFlow.collectAsStateWithLifecycle() + Backdrop( + backdrop = backdrop, + drawerIsOpen = false, + backdropStyle = preferences.appPreferences.interfacePreferences.backdropStyle, + ) + } + NavDisplay( + backStack = navigationManager.backStack, + onBack = { if (navigationManager.backStack.last().fullScreen) navigationManager.goBack() else state.key(org.justinvisser.wolfskin.design.ShellKey.Back) }, + entryDecorators = listOf(rememberSaveableStateHolderNavEntryDecorator(), rememberViewModelStoreNavEntryDecorator()), + entryProvider = { destination -> + NavEntry(destination, contentKey = "${destination}_${server.id}_${user.id}") { + val route = when (destination) { + is Destination.Home -> "home" + is Destination.Wolfskin -> destination.route + is Destination.MediaItem -> if (destination.type == org.jellyfin.sdk.model.api.BaseItemKind.PERSON) personRoute(destination.itemId.toString()) else titleRoute(destination.itemId.toString()) + else -> "pushed" + } + LaunchedEffect(destination) { if (!destination.fullScreen) state.enterDestination(route) } + if (destination.fullScreen) { + DestinationContent(destination, preferences, viewModel::clearBackdrop, Modifier.fillMaxSize()) + } else { + BackHandler { state.key(org.justinvisser.wolfskin.design.ShellKey.Back) } + val upstream = resolveUpstreamDestination(destination, WolfskinScreenPreference.enabled, viewModel.libraryDestinations) + if (upstream == null && (route.startsWith("title/") || route.startsWith("person/"))) { + val jellyfinIdentity = destination is Destination.MediaItem || android.net.Uri.decode(route.substringAfter('/')).toUUIDOrNull() != null + if (jellyfinIdentity && state.person.key != viewModel.signedInPerson) { + ShellSurface(state, handlesContentKeys = false) { ShellPlaceholder("Sign in as ${state.person.name} to open their Jellyfin library", it) } + } else TitleDestination(route, state, preferences) + } else { + ShellSurface(state, handlesContentKeys = upstream == null, + overlay = { if (route == "discover" || route.startsWith("discover-")) DiscoverOverlay(discover) }) { contentModifier -> + when { + (upstream != null || destination is Destination.Home || route in LIBRARY_DESTINATIONS) && state.person.key != viewModel.signedInPerson -> ShellPlaceholder("Sign in as ${state.person.name} to open their Jellyfin library", contentModifier) + upstream != null -> DestinationContent(upstream, preferences, viewModel::clearBackdrop, contentModifier) + destination is Destination.Home -> HomeDestination(state, server, user, contentModifier) + route in LIBRARY_DESTINATIONS || route.startsWith("seeall/") -> + WolfskinLibraryContent(androidx.compose.ui.platform.LocalContext.current, route, state, user, "${server.id}:${user.id}", viewModel.libraries, navigationManager, viewModel.seeAll, contentModifier) + destination is Destination.Wolfskin -> DestinationContent(destination, preferences, viewModel::clearBackdrop, contentModifier) + else -> ShellPlaceholder(route, contentModifier) + } + } + } + } + } + }, + ) + } + } + } +} + +/** The single registered destination branch delegates Wolfskin-only screens back to the shell. */ +@Composable +fun WolfskinDestinationContent(route: String, modifier: Modifier = Modifier) { + when { + route == "settings" -> SettingsList(LocalShellState.current, modifier) + route == "discover" || route.startsWith("discover-") -> DiscoverScreen(LocalDiscoverState.current, modifier) + else -> ShellPlaceholder(route, modifier) + } +} diff --git a/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/WolfskinLibrary.kt b/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/WolfskinLibrary.kt new file mode 100644 index 00000000..0a9a56e5 --- /dev/null +++ b/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/WolfskinLibrary.kt @@ -0,0 +1,99 @@ +package org.justinvisser.wolfskin.tv + +import android.content.Context +import androidx.compose.runtime.* +import androidx.compose.ui.Modifier +import com.github.damontecres.wholphin.BuildConfig +import com.github.damontecres.wholphin.data.model.JellyfinUser +import com.github.damontecres.wholphin.services.NavigationManager +import com.github.damontecres.wholphin.ui.nav.Destination +import java.io.File +import java.time.Instant +import java.time.ZoneId +import java.time.format.DateTimeFormatter +import javax.inject.Inject +import javax.inject.Singleton +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import org.justinvisser.wolfskin.design.* +import org.justinvisser.wolfskin.tv.read.LibraryReadFacade +import org.justinvisser.wolfskin.tv.read.LibrarySnapshotStore +import org.justinvisser.wolfskin.conductarr.FileCacheStore +import org.jellyfin.sdk.model.api.BaseItemKind +import org.jellyfin.sdk.model.serializer.toUUIDOrNull + +/** Other shelves register the complete per-type list, not the visible twenty-card window. */ +@Singleton +class WolfskinSeeAllLists @Inject constructor() { + private val lists = mutableMapOf() + + fun open(person: String, key: String, title: String, items: List, navigation: NavigationManager, loadNextPage: (suspend (Int) -> LibraryPage)? = null) { + val identity = "$person/$key" + val grid = LibraryGridState(title, items, catalogue = true, + onTitle = { navigation.navigateTo(libraryTitleDestination(it)) }) + if (loadNextPage != null) grid.pagination = LibraryPagination(grid, loadNextPage) + lists[identity] = grid + navigation.navigateTo(Destination.Wolfskin("seeall/$identity")) + } + + fun get(key: String): LibraryGridState? = lists[key] +} + +/** Debug fixture reads never become a fallback for an unavailable authenticated library. */ +@Composable +fun WolfskinLibraryContent( + context: Context, + route: String, + shell: ShellState, + user: JellyfinUser, + cacheScope: String, + facade: LibraryReadFacade, + navigation: NavigationManager, + seeAll: WolfskinSeeAllLists, + modifier: Modifier = Modifier, +) { + val view = shell.rememberedView(route) + val fixture by produceState(null, context) { + if (BuildConfig.DEBUG) value = withContext(Dispatchers.IO) { + context.assets.open("wolfskin-library.json").bufferedReader().use { LibraryFixture(it.readText(), "file:///android_asset/library/") } + } + } + val snapshots = remember(context) { LibrarySnapshotStore(FileCacheStore(File(context.filesDir, "wolfskin-library-cache"))) } + val grid = remember(shell.person.key, route, view) { + view.library ?: if (route.startsWith("seeall/")) seeAll.get(route.substringAfter("seeall/")) else LibraryGridState( + title = route.replaceFirstChar { it.uppercase() }, items = emptyList(), + onTitle = { navigation.navigateTo(libraryTitleDestination(it)) }, + onDiscover = { shell.enterDestination("discover"); navigation.replace(Destination.Wolfskin("discover")) }, + onRecover = { view.library?.let { it.refreshRevision++ } }, + ).also { it.status = LibraryStatus.Loading; view.library = it } + } + if (grid == null) { + ShellPlaceholder("See all list unavailable", modifier) + return + } + LaunchedEffect(grid, grid.refreshRevision, fixture) { + if (route in LIBRARY_DESTINATIONS && (!BuildConfig.DEBUG || fixture != null)) { + val wasLoading = grid.status == LibraryStatus.Loading + if (fixture != null) { + grid.source = withContext(Dispatchers.IO) { fixture!!.library(shell.person.key, route) } + grid.status = LibraryStatus.Ready + } else { + snapshots.read(cacheScope, route, force = grid.refreshRevision > 0) { facade.readLibrary(user.id, route) }.collect { snapshot -> + grid.source = snapshot.items + grid.status = if (snapshot.unreachable && snapshot.savedAtMillis == null) LibraryStatus.Unavailable else LibraryStatus.Ready + grid.savedAt = if (snapshot.unreachable) snapshot.savedAtMillis?.let { DateTimeFormatter.ofPattern("HH:mm").format(Instant.ofEpochMilli(it).atZone(ZoneId.systemDefault())) } else null + grid.tail = if (snapshot.unreachable && snapshot.items.isNotEmpty()) GridTail.Retry else GridTail.None + if (snapshot.unreachable && grid.refreshRevision > 0) shell.toast = RecoveryMessage.StillUnreachable + } + } + if (wasLoading && shell.navFocused && shell.navIndex == shell.currentTab) shell.navFocused = false + } + } + LibraryScreen(shell, grid, modifier, ratingsSignedIn = fixture != null, view = view) +} + +val LIBRARY_DESTINATIONS = setOf("movies", "shows", "anime") + +private fun libraryTitleDestination(title: LibraryTitle): Destination = + title.id.toUUIDOrNull()?.let { Destination.MediaItem(it, if (title.type == "movie") BaseItemKind.MOVIE else BaseItemKind.SERIES) } + ?: Destination.Wolfskin(titleRoute(title.id)) diff --git a/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/WolfskinScreenPreference.kt b/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/WolfskinScreenPreference.kt new file mode 100644 index 00000000..b85b702f --- /dev/null +++ b/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/WolfskinScreenPreference.kt @@ -0,0 +1,27 @@ +package org.justinvisser.wolfskin.tv + +import android.content.Context +import android.content.SharedPreferences +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import androidx.core.content.edit +import androidx.preference.PreferenceManager + +/** The single rollout preference is exposed only in upstream Advanced settings. */ +object WolfskinScreenPreference { + private const val KEY = "wolfskin.screens.enabled" + private lateinit var preferences: SharedPreferences + private var current by mutableStateOf(true) + + fun initialize(context: Context) { + preferences = PreferenceManager.getDefaultSharedPreferences(context.applicationContext) + current = preferences.getBoolean(KEY, true) + } + var enabled: Boolean + get() = current + set(value) { + current = value + preferences.edit { putBoolean(KEY, value) } + } +} diff --git a/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/read/HomeLibraryCache.kt b/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/read/HomeLibraryCache.kt new file mode 100644 index 00000000..6e69ac54 --- /dev/null +++ b/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/read/HomeLibraryCache.kt @@ -0,0 +1,66 @@ +package org.justinvisser.wolfskin.tv.read + +import android.content.Context +import dagger.hilt.android.qualifiers.ApplicationContext +import java.io.File +import javax.inject.Inject +import javax.inject.Singleton +import org.json.JSONArray +import org.json.JSONException +import org.json.JSONObject +import org.justinvisser.wolfskin.conductarr.CacheEntry +import org.justinvisser.wolfskin.conductarr.FileCacheStore +import org.justinvisser.wolfskin.design.HomeLibrary +import org.justinvisser.wolfskin.design.HomeTitle + +/** Saved Jellyfin projections reuse the app-private atomic cache and are partitioned by server/user. */ +@Singleton +class HomeLibraryCache @Inject constructor(@param:ApplicationContext context: Context) { + private val store = FileCacheStore(File(context.filesDir, "wolfskin-home")) + + fun read(scope: String): Pair? { + val entry = store.read(scope, KEY) ?: return null + return try { + val json = JSONObject(entry.body) + val destinations = json.getJSONObject("destinations") + val totals = json.getJSONObject("totals") + HomeLibrary( + decode(json.getJSONArray("resume")), decode(json.getJSONArray("nextUp")), decode(json.getJSONArray("newest")), + destinations.keys().asSequence().associateWith { decode(destinations.getJSONArray(it)) }, + totals.keys().asSequence().associateWith { totals.getInt(it) }, + ) to entry.savedAtMillis + } catch (_: JSONException) { store.remove(scope, KEY); null } + } + + fun write(scope: String, library: HomeLibrary, savedAtMillis: Long) { + val json = JSONObject().put("resume", encode(library.resume)).put("nextUp", encode(library.nextUp)).put("newest", encode(library.newest)) + .put("destinations", JSONObject().apply { library.destinations.forEach { (key, titles) -> put(key, encode(titles)) } }) + .put("totals", JSONObject(library.destinationTotals)) + store.write(scope, KEY, CacheEntry(json.toString(), null, savedAtMillis, savedAtMillis, group = "home")) + } + + private fun encode(titles: List): JSONArray = JSONArray().apply { + titles.forEach { title -> put(JSONObject().apply { + put("id", title.id); put("title", title.title); put("type", title.type); put("year", title.year) + put("runtime", title.runtimeSeconds); put("seasons", title.seasons); put("overview", title.overview) + put("poster", title.poster); put("backdrop", title.backdrop); put("posterOnly", title.posterOnly) + put("seriesTitle", title.seriesTitle); put("season", title.season); put("episode", title.episode) + put("resume", title.resumeSeconds); put("played", title.played); put("addedAt", title.addedAt) + put("genres", JSONArray(title.genres)); put("tmdb", title.tmdbId) + }) } + } + + private fun decode(items: JSONArray): List = List(items.length()) { index -> + val item = items.getJSONObject(index) + fun string(key: String): String? = if (item.isNull(key)) null else item.getString(key) + fun number(key: String): Int? = if (item.isNull(key)) null else item.getInt(key) + val genres = item.getJSONArray("genres") + HomeTitle( + item.getString("id"), item.getString("title"), item.getString("type"), number("year"), number("runtime"), number("seasons"), item.getString("overview"), + string("poster"), string("backdrop"), item.getBoolean("posterOnly"), string("seriesTitle"), number("season"), number("episode"), item.getDouble("resume"), item.getBoolean("played"), item.getString("addedAt"), + List(genres.length()) { genres.getString(it) }, held = true, tmdbId = number("tmdb"), + ) + } + + companion object { private const val KEY = "home:jellyfin" } +} diff --git a/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/read/HomeReadFacade.kt b/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/read/HomeReadFacade.kt new file mode 100644 index 00000000..1696930a --- /dev/null +++ b/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/read/HomeReadFacade.kt @@ -0,0 +1,80 @@ +package org.justinvisser.wolfskin.tv.read + +import com.github.damontecres.wholphin.data.model.BaseItem +import com.github.damontecres.wholphin.services.ImageUrlService +import java.util.UUID +import javax.inject.Inject +import org.jellyfin.sdk.api.client.ApiClient +import org.jellyfin.sdk.api.client.extensions.itemsApi +import org.jellyfin.sdk.api.client.extensions.tvShowsApi +import org.jellyfin.sdk.api.client.extensions.userViewsApi +import org.jellyfin.sdk.api.client.extensions.userLibraryApi +import org.jellyfin.sdk.model.api.BaseItemDto +import org.jellyfin.sdk.model.api.BaseItemKind +import org.jellyfin.sdk.model.api.CollectionType +import org.jellyfin.sdk.model.api.ImageType +import org.jellyfin.sdk.model.api.ItemFields +import org.jellyfin.sdk.model.api.ItemSortBy +import org.jellyfin.sdk.model.api.MediaType +import org.jellyfin.sdk.model.api.SortOrder +import org.justinvisser.wolfskin.design.HomeLibrary +import org.justinvisser.wolfskin.design.HomeTitle + +/** All Home SDK calls and image URLs stay behind this facade, with their own required field list. */ +class HomeReadFacade @Inject constructor(private val api: ApiClient, private val images: ImageUrlService) { + suspend fun read(userId: UUID): HomeLibrary { + val resume = api.itemsApi.getResumeItems(userId = userId, fields = FIELDS, mediaTypes = listOf(MediaType.VIDEO), limit = 20).content.items.map(::title) + val next = api.tvShowsApi.getNextUp(userId = userId, fields = FIELDS, limit = 20, enableUserData = true).content.items.map(::title) + val libraries = api.userViewsApi.getUserViews(userId = userId).content.items + val destinations = linkedMapOf>() + val newest = mutableListOf() + val totals = linkedMapOf() + for (library in libraries) { + val key = when { + "anime" in library.name.orEmpty().lowercase() -> "anime" + library.collectionType == CollectionType.MOVIES -> "movies" + library.collectionType == CollectionType.TVSHOWS -> "shows" + else -> continue + } + val response = api.itemsApi.getItems(userId = userId, parentId = library.id, recursive = true, includeItemTypes = listOf(BaseItemKind.MOVIE, BaseItemKind.SERIES), fields = FIELDS, sortBy = listOf(ItemSortBy.IS_PLAYED, ItemSortBy.DATE_CREATED), sortOrder = listOf(SortOrder.ASCENDING, SortOrder.DESCENDING), limit = 20).content + destinations.getOrPut(key) { mutableListOf() }.addAll(response.items.map(::title)) + totals[key] = (totals[key] ?: 0) + response.totalRecordCount + newest.addAll(api.itemsApi.getItems(userId = userId, parentId = library.id, recursive = true, includeItemTypes = listOf(BaseItemKind.MOVIE, BaseItemKind.SERIES), fields = FIELDS, sortBy = listOf(ItemSortBy.DATE_CREATED), sortOrder = listOf(SortOrder.DESCENDING), limit = 12).content.items.map(::title)) + } + return HomeLibrary(resume, next, newest.sortedByDescending { it.addedAt }.take(12), destinations, totals) + } + + suspend fun playableId(userId: UUID, title: HomeTitle): UUID? { + title.id.let { runCatching { UUID.fromString(it) }.getOrNull() }?.let { id -> + val item = api.userLibraryApi.getItem(userId = userId, itemId = id).content + if (item.type == BaseItemKind.SERIES) { + return (api.tvShowsApi.getNextUp(userId = userId, seriesId = id, limit = 1).content.items.firstOrNull() + ?: api.tvShowsApi.getEpisodes(seriesId = id, userId = userId, limit = 1).content.items.firstOrNull()) + ?.takeIf { it.type == BaseItemKind.EPISODE }?.id + } + return item.id.takeIf { item.type == BaseItemKind.MOVIE || item.type == BaseItemKind.EPISODE } + } + val kinds = if (title.isEpisode) listOf(BaseItemKind.EPISODE) else listOf(BaseItemKind.MOVIE) + return api.itemsApi.getItems(userId = userId, recursive = true, searchTerm = title.title, includeItemTypes = kinds, fields = FIELDS, limit = 20).content.items.firstOrNull { + it.name == title.title && (!title.isEpisode || (it.seriesName == title.seriesTitle && it.parentIndexNumber == title.season && it.indexNumber == title.episode)) + }?.id + } + + private fun title(item: BaseItemDto): HomeTitle { + val wrapped = BaseItem(item) + return HomeTitle( + id = item.id.toString(), title = item.name.orEmpty(), type = when (item.type) { BaseItemKind.EPISODE -> "episode"; BaseItemKind.SERIES -> "tv"; else -> "movie" }, + year = item.productionYear, runtimeSeconds = item.runTimeTicks?.div(TICKS_PER_SECOND)?.toInt(), seasons = item.childCount, + overview = item.overview.orEmpty(), poster = images.getItemImageUrl(wrapped, ImageType.PRIMARY, fillWidth = 256, fillHeight = 384), + backdrop = images.getItemImageUrl(wrapped, ImageType.BACKDROP, fillWidth = 1280, fillHeight = 720), + seriesTitle = item.seriesName, season = item.parentIndexNumber, episode = item.indexNumber, + resumeSeconds = (item.userData?.playbackPositionTicks ?: 0) / TICKS_PER_SECOND.toDouble(), played = item.userData?.played == true, + addedAt = item.dateCreated?.toString().orEmpty(), genres = item.genres.orEmpty(), held = true, tmdbId = item.providerIds?.get("Tmdb")?.toIntOrNull(), + ) + } + + companion object { + private const val TICKS_PER_SECOND = 10_000_000L + private val FIELDS = listOf(ItemFields.PROVIDER_IDS, ItemFields.OVERVIEW, ItemFields.DATE_CREATED, ItemFields.GENRES, ItemFields.CHILD_COUNT) + } +} diff --git a/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/read/LibraryReadFacade.kt b/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/read/LibraryReadFacade.kt new file mode 100644 index 00000000..fbb037b9 --- /dev/null +++ b/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/read/LibraryReadFacade.kt @@ -0,0 +1,76 @@ +package org.justinvisser.wolfskin.tv.read + +import com.github.damontecres.wholphin.ui.nav.Destination +import org.jellyfin.sdk.api.client.ApiClient +import org.jellyfin.sdk.api.client.extensions.userViewsApi +import org.jellyfin.sdk.api.client.extensions.itemsApi +import org.jellyfin.sdk.api.client.extensions.imageApi +import org.jellyfin.sdk.model.api.ItemFields +import org.jellyfin.sdk.model.api.ItemSortBy +import org.jellyfin.sdk.model.api.ImageType +import org.justinvisser.wolfskin.design.LibraryTitle +import org.justinvisser.wolfskin.design.WolfskinTokens +import org.jellyfin.sdk.model.api.BaseItemKind +import org.jellyfin.sdk.model.api.CollectionType +import java.util.UUID +import javax.inject.Inject + +/** SDK reads are confined here so shell and screen state never depend on SDK responses. */ +class LibraryReadFacade @Inject constructor(private val api: ApiClient) { + suspend fun readDestinations(userId: UUID): Map { + val libraries = api.userViewsApi.getUserViews(userId = userId).content.items.orEmpty() + return buildMap { + libraries.forEach { library -> + val name = library.name.orEmpty().lowercase() + val key = when { + "anime" in name -> "anime" + library.collectionType == CollectionType.MOVIES -> "movies" + library.collectionType == CollectionType.TVSHOWS -> "shows" + else -> null + } + if (key != null) put(key, Destination.MediaItem(library.id, BaseItemKind.COLLECTION_FOLDER, library.collectionType)) + } + } + } + + /** A destination spans every matching accessible library; containers never become titles. */ + suspend fun readLibrary(userId: UUID, destination: String): List { + val libraries = api.userViewsApi.getUserViews(userId = userId).content.items.orEmpty().filter { library -> + val anime = library.name.orEmpty().contains("anime", ignoreCase = true) + when (destination) { + "anime" -> anime + "movies" -> !anime && library.collectionType == CollectionType.MOVIES + "shows" -> !anime && library.collectionType == CollectionType.TVSHOWS + else -> false + } + } + val titles = linkedMapOf() + for (library in libraries) { + var offset = 0 + do { + val response = api.itemsApi.getItems( + userId = userId, parentId = library.id, recursive = true, + includeItemTypes = listOf(if (destination == "movies") BaseItemKind.MOVIE else BaseItemKind.SERIES), + fields = listOf(ItemFields.PROVIDER_IDS, ItemFields.SORT_NAME, ItemFields.DATE_CREATED), + sortBy = listOf(ItemSortBy.SORT_NAME), startIndex = offset, + limit = WolfskinTokens.Behaviour.libraryChunk.toInt(), + ).content + val chunk = response.items.orEmpty() + for (item in chunk) { + val runtime = item.runTimeTicks?.div(10_000_000) + val position = item.userData?.playbackPositionTicks ?: 0 + titles[item.id] = LibraryTitle( + id = item.id.toString(), title = item.name.orEmpty(), type = if (item.type == BaseItemKind.MOVIE) "movie" else "tv", + year = item.productionYear, runtimeSeconds = runtime, seasons = item.childCount, + poster = item.imageTags?.get(ImageType.PRIMARY)?.let { api.imageApi.getItemImageUrl(item.id, ImageType.PRIMARY, tag = it) }, + played = item.userData?.played == true, + progress = if ((item.runTimeTicks ?: 0) > 0) (position.toDouble() / item.runTimeTicks!!).toFloat() else 0f, + addedAt = item.dateCreated?.toString().orEmpty(), tmdbId = item.providerIds?.get("Tmdb"), + ) + } + offset += chunk.size + } while (chunk.isNotEmpty() && offset < response.totalRecordCount) + } + return titles.values.toList() + } +} diff --git a/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/read/LibrarySnapshotStore.kt b/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/read/LibrarySnapshotStore.kt new file mode 100644 index 00000000..263922eb --- /dev/null +++ b/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/read/LibrarySnapshotStore.kt @@ -0,0 +1,59 @@ +package org.justinvisser.wolfskin.tv.read + +import java.io.IOException +import kotlinx.coroutines.CancellationException +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.flowOn +import org.json.JSONArray +import org.json.JSONException +import org.json.JSONObject +import org.justinvisser.wolfskin.conductarr.CacheEntry +import org.justinvisser.wolfskin.conductarr.CacheStore +import org.justinvisser.wolfskin.design.LibraryTitle +import org.justinvisser.wolfskin.design.WolfskinTokens + +/** Saved data is published before refresh; an unreachable server never replaces it with an error. */ +data class LibrarySnapshot(val items: List, val savedAtMillis: Long?, val unreachable: Boolean) + +/** Library snapshots share the existing atomic disk store, partitioned by server and person. */ +class LibrarySnapshotStore(private val cache: CacheStore, private val now: () -> Long = System::currentTimeMillis) { + fun read(scope: String, destination: String, force: Boolean = false, load: suspend () -> List): Flow = flow { + val key = "library:$destination" + val saved = try { cache.read(scope, key) } catch (_: IOException) { null } + val titles = saved?.let { try { decode(it.body) } catch (_: JSONException) { null } } + if (saved != null && titles != null) emit(LibrarySnapshot(titles, saved.savedAtMillis, false)) + val lifetime = (WolfskinTokens.Behaviour.libraryRefreshMinutes * 60_000).toLong() + if (!force && saved != null && titles != null && now() - saved.validatedAtMillis < lifetime) return@flow + try { + val current = load() + val time = now() + try { cache.write(scope, key, CacheEntry(encode(current), null, time, time, group = "library")) } catch (_: IOException) { /* A readable server remains usable without writable local storage. */ } + emit(LibrarySnapshot(current, time, false)) + } catch (exception: Exception) { + if (exception is CancellationException) throw exception + emit(LibrarySnapshot(titles.orEmpty(), saved?.savedAtMillis.takeIf { titles != null }, true)) + } + }.flowOn(Dispatchers.IO) + + private fun encode(items: List): String = JSONArray().apply { + items.forEach { title -> put(JSONObject().apply { + put("id", title.id); put("title", title.title); put("type", title.type) + put("year", title.year); put("runtime", title.runtimeSeconds); put("seasons", title.seasons) + put("poster", title.poster); put("played", title.played); put("progress", title.progress) + put("added", title.addedAt); put("tmdb", title.tmdbId) + }) } + }.toString() + + private fun decode(body: String): List { + val array = JSONArray(body) + return List(array.length()) { index -> array.getJSONObject(index).let { item -> + LibraryTitle(id = item.getString("id"), title = item.getString("title"), type = item.getString("type"), + year = item.optInt("year").takeIf { it > 0 }, runtimeSeconds = item.optLong("runtime").takeIf { it > 0 }, + seasons = item.optInt("seasons").takeIf { it > 0 }, poster = item.optString("poster").takeIf { it.isNotEmpty() }, + played = item.optBoolean("played"), progress = item.optDouble("progress", 0.0).toFloat(), addedAt = item.optString("added"), + tmdbId = item.optString("tmdb").takeIf { it.isNotEmpty() }) + } } + } +} diff --git a/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/read/TitleReadFacade.kt b/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/read/TitleReadFacade.kt new file mode 100644 index 00000000..bdad22a5 --- /dev/null +++ b/app/src/wolfskin/java/org/justinvisser/wolfskin/tv/read/TitleReadFacade.kt @@ -0,0 +1,186 @@ +package org.justinvisser.wolfskin.tv.read + +import android.content.Context +import com.github.damontecres.wholphin.data.ItemPlaybackRepository +import com.github.damontecres.wholphin.data.ServerRepository +import com.github.damontecres.wholphin.data.model.BaseItem +import com.github.damontecres.wholphin.data.model.TrackIndex +import com.github.damontecres.wholphin.preferences.UserPreferences +import com.github.damontecres.wholphin.services.FavoriteWatchManager +import com.github.damontecres.wholphin.services.ImageUrlService +import dagger.hilt.android.qualifiers.ApplicationContext +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import kotlinx.serialization.builtins.ListSerializer +import kotlinx.serialization.json.Json +import org.jellyfin.sdk.api.client.ApiClient +import org.jellyfin.sdk.api.client.extensions.itemsApi +import org.jellyfin.sdk.api.client.extensions.tvShowsApi +import org.jellyfin.sdk.api.client.extensions.userLibraryApi +import org.jellyfin.sdk.model.api.BaseItemDto +import org.jellyfin.sdk.model.api.BaseItemKind +import org.jellyfin.sdk.model.api.ImageType +import org.jellyfin.sdk.model.api.ItemFields +import org.jellyfin.sdk.model.api.ItemSortBy +import org.jellyfin.sdk.model.api.MediaStreamType +import org.jellyfin.sdk.model.api.request.GetEpisodesRequest +import org.jellyfin.sdk.model.api.request.GetItemsRequest +import org.jellyfin.sdk.model.api.request.GetNextUpRequest +import org.jellyfin.sdk.model.serializer.toUUIDOrNull +import org.json.JSONObject +import org.justinvisser.wolfskin.design.TitleAction +import org.justinvisser.wolfskin.design.TitleConnection +import org.justinvisser.wolfskin.design.TitleItem +import org.justinvisser.wolfskin.design.TitlePageData +import org.justinvisser.wolfskin.design.TitlePerson +import org.justinvisser.wolfskin.design.TitleTrack +import org.justinvisser.wolfskin.design.TitleVersion +import java.io.File +import java.util.Locale +import java.util.UUID +import javax.inject.Inject + +data class PersonRead(val person: TitlePerson, val credits: List, val savedAt: String? = null) + +/** Jellyfin SDK changes are confined to this boundary; title UI sees immutable screen data only. */ +class TitleReadFacade @Inject constructor( + private val api: ApiClient, + private val images: ImageUrlService, + private val playback: ItemPlaybackRepository, + private val repository: ServerRepository, + private val watched: FavoriteWatchManager, + @param:ApplicationContext private val context: Context, +) { + private val json = Json { ignoreUnknownKeys = true } + private val fields = listOf(ItemFields.PROVIDER_IDS, ItemFields.MEDIA_SOURCES, ItemFields.MEDIA_STREAMS, ItemFields.OVERVIEW, ItemFields.PEOPLE, ItemFields.PARENT_ID) + + /** A disk copy is decoded before any network read; ownership is isolated by server and user. */ + suspend fun readSaved(id: UUID, preferences: UserPreferences): TitlePageData? = withContext(Dispatchers.IO) { + val file = cacheFile(id) + if (!file.exists()) return@withContext null + try { + val saved = JSONObject(file.readText()) + val rows = json.decodeFromString(ListSerializer(BaseItemDto.serializer()), saved.getString("items")) + val numbers = saved.getJSONArray("seasonNumbers").let { array -> List(array.length()) { array.getInt(it) } } + build(rows, numbers, saved.optInt("selectedSeason"), saved.getString("watch"), saved.optString("target").takeIf { it.isNotEmpty() }, preferences) + .copy(savedAt = savedTime(file), trailerUrl = saved.optString("trailer").takeIf { it.isNotEmpty() }) + } catch (_: java.io.IOException) { null } catch (_: IllegalArgumentException) { null } catch (_: org.json.JSONException) { null } + } + + /** An episode opens its series with that exact episode as both play and watched target. */ + suspend fun read(id: UUID, season: Int?, preferences: UserPreferences): TitlePageData = withContext(Dispatchers.IO) { + val file = cacheFile(id) + val opened = api.userLibraryApi.getItem(id).content + val series = if (opened.type == BaseItemKind.EPISODE && opened.seriesId != null) api.userLibraryApi.getItem(opened.seriesId!!).content else opened + val seasons = if (series.type == BaseItemKind.SERIES) api.itemsApi.getItems(GetItemsRequest(parentId = series.id, includeItemTypes = listOf(BaseItemKind.SEASON), recursive = false, sortBy = listOf(ItemSortBy.INDEX_NUMBER))).content.items.orEmpty() else emptyList() + val next = if (opened.type == BaseItemKind.EPISODE || opened.type == BaseItemKind.MOVIE) opened else { + api.tvShowsApi.getNextUp(GetNextUpRequest(seriesId = series.id, userId = repository.currentUser?.id, limit = 1, fields = fields, enableResumable = true)).content.items.firstOrNull()?.let { api.userLibraryApi.getItem(it.id).content } + } + val selectedNumber = season ?: next?.parentIndexNumber ?: seasons.firstOrNull()?.indexNumber + val selected = seasons.firstOrNull { it.indexNumber == selectedNumber } ?: seasons.firstOrNull() + val episodes = selected?.let { api.tvShowsApi.getEpisodes(GetEpisodesRequest(seriesId = series.id, seasonId = it.id, fields = fields)).content.items.orEmpty() }.orEmpty() + val target = next ?: episodes.firstOrNull { it.type == BaseItemKind.EPISODE } + val rows = (listOf(series, opened) + listOfNotNull(target) + episodes).distinctBy { it.id } + val numbers = seasons.mapNotNull { it.indexNumber } + val result = build(rows, numbers, selected?.indexNumber, opened.id.toString(), target?.id?.toString(), preferences) + val localTrailer = if (result.trailerUrl == null && (series.localTrailerCount ?: 0) > 0) api.userLibraryApi.getLocalTrailers(series.id).content.firstOrNull()?.id?.toString() else null + val trailer = result.trailerUrl ?: localTrailer?.let { "jellyfin:$it" } + val saved = JSONObject().put("items", json.encodeToString(ListSerializer(BaseItemDto.serializer()), rows)) + .put("seasonNumbers", org.json.JSONArray(numbers)).put("selectedSeason", selected?.indexNumber).put("watch", opened.id.toString()) + .put("target", target?.id?.toString().orEmpty()).put("trailer", trailer.orEmpty()) + file.parentFile?.mkdirs() + try { file.writeText(saved.toString()) } catch (_: java.io.IOException) { /* Playback remains available when the disk cannot save a copy. */ } + result.copy(trailerUrl = trailer) + } + + /** A failed reachability read leaves navigation on the title instead of opening a dead player. */ + suspend fun preparePlayback(id: UUID) { api.userLibraryApi.getItem(id) } + + /** Track selection uses the same repository consumed by the upstream player. */ + suspend fun apply(action: TitleAction) = withContext(Dispatchers.IO) { + when (action) { + is TitleAction.Version -> playback.savePlayVersion( + UUID.fromString(action.item.id), + requireNotNull(action.version.id.toUUIDOrNull()) { "Invalid Jellyfin media source identifier" }, + ) + is TitleAction.Track -> { + val id = UUID.fromString(action.item.id) + val item = BaseItem(api.userLibraryApi.getItem(id).content) + var choice = repository.currentUser?.let { playback.itemPlaybackDao.getItem(it, id) } + action.audio?.let { choice = playback.saveTrackSelection(item, choice, it, MediaStreamType.AUDIO) } + playback.saveTrackSelection(item, choice, if (action.subtitle == -1) TrackIndex.DISABLED else action.subtitle, MediaStreamType.SUBTITLE) + } + is TitleAction.Watched -> watched.setWatched(UUID.fromString(action.item.id), action.watched) + else -> Unit + } + Unit + } + + /** A person keeps the same server/user-scoped last good copy as a title. */ + suspend fun readPersonSaved(id: UUID): PersonRead? = withContext(Dispatchers.IO) { + val file = personCacheFile(id) + if (!file.exists()) return@withContext null + try { + val rows = json.decodeFromString(ListSerializer(BaseItemDto.serializer()), file.readText()) + personData(id, rows.first(), rows.drop(1)).copy(savedAt = savedTime(file)) + } catch (_: java.io.IOException) { null } catch (_: IllegalArgumentException) { null } + } + + /** Held performer credits are read continuously; a signed-out TV never falls back to Seerr. */ + suspend fun readPerson(id: UUID, start: Int): PersonRead = withContext(Dispatchers.IO) { + val file = personCacheFile(id) + val previous = if (start > 0 && file.exists()) { + try { json.decodeFromString(ListSerializer(BaseItemDto.serializer()), file.readText()) } + catch (_: java.io.IOException) { emptyList() } catch (_: IllegalArgumentException) { emptyList() } + } else emptyList() + val person = previous.firstOrNull() ?: api.userLibraryApi.getItem(id).content + val credits = api.itemsApi.getItems(GetItemsRequest(personIds = listOf(id), recursive = true, + includeItemTypes = listOf(BaseItemKind.MOVIE, BaseItemKind.SERIES), fields = fields, startIndex = start, limit = 200, + sortBy = listOf(ItemSortBy.PRODUCTION_YEAR, ItemSortBy.SORT_NAME))).content.items.orEmpty() + val rows = listOf(person) + (previous.drop(1) + credits).distinctBy { it.id } + file.parentFile?.mkdirs() + try { file.writeText(json.encodeToString(ListSerializer(BaseItemDto.serializer()), rows)) } + catch (_: java.io.IOException) { /* The readable grid does not disappear when saving fails. */ } + personData(id, person, credits) + } + + private fun personData(id: UUID, person: BaseItemDto, credits: List): PersonRead = + PersonRead(TitlePerson(id.toString(), person.name.orEmpty(), portrait = images.getItemImageUrl(id, ImageType.PRIMARY, maxWidth = 240, maxHeight = 240), biography = person.overview.orEmpty()), + credits.map { credit -> mapItem(credit).copy(character = credit.people.orEmpty().firstOrNull { it.id == id }?.role) }) + + private suspend fun build(rows: List, seasonNumbers: List, selectedSeason: Int?, watchId: String, targetId: String?, preferences: UserPreferences): TitlePageData { + val item = rows.first() + val target = rows.firstOrNull { it.id.toString() == targetId } + val chosen = target?.let { playback.getSelectedTracks(it.id, BaseItem(it), preferences) } + val versions = target?.mediaSources.orEmpty().map { source -> + val streams = source.mediaStreams.orEmpty() + TitleVersion(source.id.orEmpty(), source.name ?: source.path ?: source.id.orEmpty(), streams.firstOrNull { it.type == MediaStreamType.VIDEO }?.displayTitle.orEmpty(), + source.bitrate?.let { String.format(Locale.getDefault(), "%.1f Mbps", it / 1_000_000.0) }.orEmpty(), + source.size?.let { String.format(Locale.getDefault(), "%.1f GB", it / 1_000_000_000.0) }.orEmpty(), source.container.orEmpty().uppercase(), + streams.filter { it.type == MediaStreamType.AUDIO }.map { TitleTrack(it.index, it.displayTitle ?: it.language ?: it.codec.orEmpty(), it.isDefault) }, + streams.filter { it.type == MediaStreamType.SUBTITLE }.map { TitleTrack(it.index, it.displayTitle ?: it.language ?: it.codec.orEmpty(), it.isDefault) }) + } + return TitlePageData(mapItem(item).copy(seasons = seasonNumbers.size), target?.takeIf { it.type == BaseItemKind.EPISODE || (it.userData?.playbackPositionTicks ?: 0) > 0 }?.let { mapItem(it) }, + rows.first { it.id.toString() == watchId }.let { mapItem(it) }, versions, chosen?.source?.id, chosen?.audioStream?.stream?.index, + if (chosen?.subtitlesDisabled == true) -1 else chosen?.subtitleStream?.stream?.index ?: -1, + item.remoteTrailers.orEmpty().firstNotNullOfOrNull { it.url }, + cast = item.people.orEmpty().filter { it.type.toString().equals("Actor", true) }.map { person -> + TitlePerson(person.id.toString(), person.name.orEmpty(), person.role.orEmpty(), person.primaryImageTag?.let { images.getItemImageUrl(person.id, ImageType.PRIMARY, maxWidth = 200, maxHeight = 200, tag = it) }) + }, + episodes = rows.filter { it.type == BaseItemKind.EPISODE && it.parentIndexNumber == selectedSeason }.map { mapItem(it) }, + connection = TitleConnection.SignedOut, seasonNumbers = seasonNumbers, selectedSeason = selectedSeason) + } + + private fun mapItem(item: BaseItemDto): TitleItem = TitleItem( + item.id.toString(), item.name.orEmpty(), when (item.type) { BaseItemKind.MOVIE -> "movie"; BaseItemKind.EPISODE -> "episode"; else -> "tv" }, + item.productionYear, (item.runTimeTicks ?: 0) / 10_000_000, overview = item.overview.orEmpty(), genres = item.genres.orEmpty(), + poster = item.imageTags?.get(ImageType.PRIMARY)?.let { images.getItemImageUrl(item.id, ImageType.PRIMARY, maxWidth = 256, maxHeight = 384, tag = it) }, + backdrop = item.backdropImageTags?.firstOrNull()?.let { images.getItemImageUrl(item.id, ImageType.BACKDROP, maxWidth = 1280, maxHeight = 720, tag = it) }, + held = true, watched = item.userData?.played == true, resumeSeconds = (item.userData?.playbackPositionTicks ?: 0) / 10_000_000, + seriesId = item.seriesId?.toString(), seriesName = item.seriesName, season = item.parentIndexNumber ?: 0, episode = item.indexNumber ?: 0, + ) + + private fun cacheFile(id: UUID): File = File(context.filesDir, "wolfskin-title/${repository.currentServer?.id}/${repository.currentUser?.id}/$id.json") + private fun personCacheFile(id: UUID): File = File(cacheFile(id).parentFile, "person-$id.json") + private fun savedTime(file: File): String = java.text.SimpleDateFormat("HH:mm", Locale.getDefault()).format(java.util.Date(file.lastModified())) +} diff --git a/docker/README.md b/docker/README.md index 394aa9cd..cc822873 100644 --- a/docker/README.md +++ b/docker/README.md @@ -7,7 +7,7 @@ Android SDK. ```sh git fetch origin --tags make apk # clean, signed default release: three ABI splits + universal -make test # upstream testDefaultDebugUnitTest in the same image, no secrets +make test # app default/debug suite plus wolfskin-design JVM/capture suite make apk-debug # default debug, no secrets; MPV stub and no extra codec decoders ``` @@ -48,6 +48,410 @@ not the working tree. An uncommitted merge still builds with the old version nam Neither an upstream merge nor its validation build authorizes a release or TV installation. +## Wolfskin shell + +Wolfskin UI lives in `app/src/wolfskin/java`, beside upstream source. The signed-in +entry in `MainContent.kt` calls `WolfskinApp`; Wolfskin-only routes use the single +`Destination.Wolfskin` subtype in the existing navigation stack. Other destinations +continue through upstream `DestinationContent`. Full-screen player/settings pages +cover the Wolfskin nav. + +The independent `:wolfskin-design` module owns the shell components, fixed person +colours, focus policy, per-person root-view memory, palette and motion. Its +`tokens.json` is the copied approved TV-spec source, retaining the locked prototype +SHA and provenance. `shell-tokens.json` adds shared shell/grid/sheet measurements; +`title-tokens.json`, `home-tokens.json` and `discover-tokens.json` add their screen +measurements from the same locked prototype. Generate Kotlin, CSS and the checksum manifest together: + +```sh +python3 wolfskin-design/generate_tokens.py +python3 wolfskin-design/generate_tokens.py --check +``` + +`preBuild` checks the manifest against the source JSON, generator and generated +outputs. Editing any of them without regenerating fails the build. The shell uses +the generated palette rather than the retired `WOLFSKIN` theme-enum value; the old +numeric value is reserved. + +Compose output maps source weights 600/650 to the platform Bold (700) face, which +resolves consistently in native captures; the approved JSON weights stay unchanged. +Nav, picker names, labels and pill weights use that same mapping. Nav label colour +fades for 200 ms ease-out; the blob retains its critically damped spring. + +Settings pills have a separate 1 dp stroke (2 px on the stage), not a focus ring. +The stroke is inset within the fixed 20 dp / 40 px height; horizontal border-box +padding includes it. The 6 px dash / 4 px gap follows the browser's 3:2 stroke-width +ratios. Resting borders are white at 22% opacity; focused borders use ink at 40%. + +The small gear under the final person opens Settings with Requests focused. +Settings groups hand off to existing upstream pages; Requests opens the household +Coming-in sheet described below. **Advanced settings โ†’ Wolfskin screens** is the persistent +rollout switch: turning it off renders upstream Home and library destinations with +the upstream Backdrop and top scrim, while retaining Wolfskin's nav, picker and +Settings list. Native Up traversal stays in content until the first focusable row, +then enters the nav. Turning the switch on renders Wolfskin Home and Libraries. +Discover and Requests are integrated Wolfskin surfaces; title hand-offs remain labelled. + +Debug people, tabs and initials come from the shell-only projection of the locked +prototype fixture in `app/src/debug/assets/wolfskin-shell.json`; release resources +do not package it. Saved Jellyfin identities use existing upstream services. The +shell makes no Conductarr calls and does not add Conductarr sign-in. + +Discover adds the picks hero, type chips, catalogue shelves, service pages, continuous +See all grids, Hidden picks, request chooser and receipts. Its `discover-title/...` +destination is an explicit title-family integration stub exposing only Discover's +request and pick actions. Unheld titles have no trailer control until the pinned +Conductarr title contract supplies a trailer. + +The debug-only fixture and local art live in +`app/src/debug/assets/wolfskin-discover/`. Release builds remain on the explicit +Conductarr sign-in state. The fixture host cannot construct a network client: +debug request outcomes and dismissals stay in memory. The real mutation adapter +accepts an injected `ConductarrClient` and uses only its typed routes; it is not +wired to a live server. Unknown request outcomes force a fresh title-requests read +instead of blindly submitting again, including after closing a sheet or choosing +the same uncertain recipient from another chooser. Whole-series requests require every season. + +Discover hero and Restore text use explicit per-line CSS allocations so native +paragraph overflow cannot enlarge the bottom-anchored stack. Restore subtitles +retain the sheet's negative top margin and bottom gap. Recovery panels may +overflow their fixed-height scroll row so sign-in copy never shrinks the retry +button. Native regressions cover those three layout boundaries. + +Discover's native capture suite covers its 28 named acceptance states and emits +text-layout metrics beside the PNGs. Data-driven Android key replays cover opening +Discover in 4 presses, requesting for yourself in 7, requesting for Mindel in 9 and +Not interested in 8. Additional regressions exercise held-OK safety, uncertain +receipts, per-recipient outcomes, collection recovery and Undo, unknown seasons, +Dutch decimal formatting and short-row/tail clamping. Discover reuses the Libraries +grid, poster, ratings plate, See all and recovery cards, bounded image loader, caption +separator token and the shell's single hold guard. Both frames share the 180 ms scroll tween. + +The TV keeps platform Roboto with the approved type sizes and weights. Browser +system-font wrapping is not a per-title contract: no bundled font, forced title +breaks or width compensation is applied. Discover's own stacked text preserves +untrimmed CSS line boxes without changing merged shell/library typography. Hero, +sheet and shared focused-content shadows use tokenized drop shadows, not Material +elevation; their alpha animates in the draw phase. Native text-layout measurements +accompany each acceptance capture; remaining font-driven wrapping and text-block +positions must be listed explicitly in its comparison report. + +The asynchronous debug fixture seam hands loading focus back to the first loaded +action when Discover is still the selected destination. A JVM regression releases +the actual host's suspended fixture load and presses Android OK: it must open the +hero rather than activate the nav. Fixture completion does not steal a different +destination or nav selection. + +Native Roborazzi captures use Robolectric SDK 34 and +`w960dp-h540dp-xhdpi` (1920ร—1080 at density 2.0). `make test` writes capture PNGs and +the sampled Compose nav-spring curve to `build/wolfskin-captures/`. +Home, Library and Discover captures use `home/`, `library/` and `discover/` +subdirectories so shared spec state numbers cannot overwrite another renderer's image. +Key replays exercise the Android event adapter, including the 6/8/10/11-press shell paths. +The profile hand-off capture targets the real `HomeSettingsPage`; Playback is a +separate press-count path. + +Robolectric SDK 28/30/34 runtimes resolve through Gradle's existing persistent +dependency cache, then copy to `wolfskin-design/build/robolectric-sdk/`. Test workers +use that local directory in offline mode instead of downloading Android JARs into +the container's ephemeral home. A cache miss still needs Maven Central; rate-limited +hosts can seed the existing cache from SHA512-verified local Maven artifacts without +changing the wrapper or adding volumes. + +Default-flavour launcher artwork and English, Hungarian and Polish string overrides +live in `app/src/default/res/`. Legacy Wolfskin strings in 25 translated +`main` resource folders have not yet been moved; non-default `appstore`/`firetv` +flavours therefore combine upstream icons with some legacy Wolfskin text. Those +flavours and a full locale migration are not certified by this slice. Debug +assembly runs `checkWolfskinBranding` against every packaged APK through AGP's public +artifact provider and AAPT2. It checks all string, plural and array configurations, +rejecting user-visible upstream branding while preserving the upstream legal +attribution and project URL. The check does not depend on incremental merge files. + +## Wolfskin Home + +Home is one lazy frame: a non-rotating resume โ†’ Next up โ†’ newest โ†’ pick hero, +Jellyfin shelves, per-destination "Your โ€ฆ" shelves and the Discover continuation. +The final action opens the real merged Discover screen at its top through the +shell's root re-selection transition. Home's See all cards open `WolfskinSeeAllLists`, carrying +the complete underlying list rather than the visible shelf window. Title content +remains the later-slice target. + +All Home components and immutable screen models live in `:wolfskin-design`. +The shell's remembered view owns vertical position, each row's selected card and +actual horizontal `LazyListState`, and the bounded six-hour ratings session cache. +Composing destinations bind `rememberedView(route)` before navigation effects run, so a +new See all grid cannot borrow or clamp Home's scroller. Re-entry restores the +remembered track before the page with `scrollToItem`, preserving exact indices and +pixel offsets rather than animating back. Android focus stays with the shell; +cards use its logical focus, without requests against uncomposed lazy items. +Back preserves the viewport; returning to Home does not re-run focus-follow over +a manually scrolled saved view. The next arrow re-enters visible content when +scrolling moved focus off-screen. +Pointing changes focus without activation, cards activate on key-up, and held +OK events cannot activate twice. +Between shelves, an unvisited row selects the nearest visible card center even +when card widths differ. A visited row restores its column. Horizontal movement +keeps the track still while focus remains in its visible middle. +The initial skeleton parks focus on the nav. When the first content arrives, +an untouched fresh entry focuses hero button zero; intervening nav input prevents +that automatic transfer. Home, Libraries and Discover use the same `ShellContentFocus` +release/repeat guard and Back ladder. + +`HomeReadFacade` is the only Home code importing Jellyfin API clients. Release +variants read the selected user's Resume, Next up, newest titles and destination +shelves, with app-private last-known-good projections through the shared atomic +disk cache. A missing saved library becomes a recovery panel; a saved library +stays visible when Jellyfin is unreachable. Playback resolves an actual film or +episode and checks Jellyfin before opening upstream's player. No season, +recommendation stub or different person's session is promoted to playback. +An unresolved person switch guards Home and both owned/upstream library content +before mounting any source read with the prior person's Jellyfin session. + +Debug variants additionally package the locked fixture and local artwork under +`wolfskin-design/src/debug/assets/wolfskin-home/`; release variants exclude them. +The fixture provider supplies the approved household data and Home states without +network reads in tests. Conductarr sign-in is not implemented here: real signed-out +Home hides every rating and shows "Discover needs sign-in". No Seerr fallback is +used. Catalogue data and ratings in debug captures are fixture-backed. + +Home, Libraries and Discover reuse `TitleCard`, `Caption` and `LibrarySeeAllCard`; +those screens and Requests share one `WolfskinImages` loader. Exact-slot requests use RGB565 for posters, +disable crossfades, share a 64 MiB memory/128 MiB disk cache, limit image work to +four reads and prefetch the next shelf. Rating plates start at 14 sp, shrink to 12 sp +and drop trailing entries rather than wrap. Their uncached read gate is 350 ms; +cached focus returns without that delay. + +Focus rings and native lift draw outside fixed slots. The Saved nav chip uses its +own geometry; the Discover section uses a warning pill. Caption separators multiply +the existing muted colour alpha by the shared 40% token. Home-only untrimmed styles +and `exactLineBox` honor the declared CSS line boxes despite Android's intrinsic +paragraph minimums; shell and library typography retain their existing defaults. +The shared See all component uses its canonical locked 8px gap, not the generic +10px tail spacing. Focus lifts use the merged draw-only `FocusLift` implementation; +the obsolete Home shadow helper and duplicate gap/lift measurements are removed. +Vertical moves clamp to short target rows, including a final See all card. + +`make test` includes `HomeCaptureTest` (23 native acceptance states) and the +data-driven paths in `wolfskin-home-presses.json`: play next 2, resume 3, Discover +4, deep-row Back/Down 9, Trending 13 and Trending's See all card 33 presses. +Home captures are written to `build/wolfskin-captures/home/`. Compare those images +side by side with the frozen spec captures; Compose Roboto/JPEG rasterisation, +the approved button-scale consolidation and removal of prototype sample pills +are recorded differences, not a claim of browser pixel equality. + +## Requests under Settings + +The Requests row and Coming-in sheet share one immutable household snapshot. +Ready requests do not count as open. Rows sort Failed, Downloading/Almost ready, +Checking/Searching, Waiting, Ready. The bounded window shows five rows, or four +with readiness expanded. Right expands Request/Download/Library/Playback; Left +collapses; Up/Down collapse while moving. Opening a title preserves the request +for Back, and closing the sheet restores its opener. Selecting a root or changing +person clears the title-return link. Shared's authenticated actor always reads +โ€œby Sharedโ€, never โ€œby youโ€. + +The debug-only provider loads `app/src/debug/assets/wolfskin-requests.json` and +its eight local posters, projected from the locked prototype fixture. Six stage +rows feed the running debug shell; the Shared and focused-rating records feed +native acceptance states. The identical projection is in design-test resources. +No โ€œsampleโ€ or โ€œexample stagesโ€ pill is drawn. Release builds package none of +these assets and show Requests unavailable until Conductarr sign-in supplies +the generated-client data path. There is no Seerr fallback or handwritten HTTP. +Foreground refreshes once; an open sheet or unsettled requests refresh every +30 seconds while started. The immutable debug projection is loaded once, not +decoded again on every poll. +Thumbnails reuse `WolfskinImages` with a 96ร—144-pixel request, RGB565, no crossfade, +the shared 64 MB memory/128 MB disk cache and four-read limit. Actor separator +dots use the surrounding text colour; the 40% rule applies only to poster captions. + +Uncached focused ratings wait 350 ms; moving away cancels the read. Read ratings +show immediately on return; sign-out clears visibility. This follows the frozen +page and spec 6.12, resolving the contradictory no-dwell sentence in spec 7.8. +Deterministic coroutine-clock tests cover cancellation, reentry, cached return, +sign-out and refreshed locale scores; a thin Compose test verifies actual Dutch +rendering and sign-out suppression. The approved nine-key Requests path is JSON +data replayed through the real shell. The Requests-only harness starts at the +Home-to-nav boundary; Home's actual hero and asynchronous entry have separate key replays. + +Sheet dimensions, padding, glyphs, scales, colours and durations are generated +tokens. Scoped sheet line boxes retain CSS heights and baselines independently +of native leading rounding; shared shell/library typography is unchanged. Platform +Roboto remains required: the host browser used DejaVu Sans, so its width, +wrapping, ellipsis and text-block positions are not a wrapping-parity target. +For example, the 44-pixel โ€œComing inโ€ ink is 239 pixels wide in the reference +and 194 pixels in native captures. No per-title compensation or font bundle is +used. Native comparisons must report those structural differences explicitly. +Readiness glyphs sit inline on the text baseline with no flex gap, matching the +frozen block-span cascade. Items wrap intrinsically: Roboto fits the expanded +readiness into two lines where the reference uses three; no grouping is forced. + +The six rating marks retain the exact locked SVG source in +`wolfskin-design/request-marks/`; native-size PNGs and their hashes are generated +from the JSON dimensions with the locked contain fit (`.rr .rb` outranks `.crow img`). +Inside Coming-in rows they retain the prototype's dark `surface3` chips with 12-pixel rounded corners. +Loaded poster thumbnails have no placeholder fill beneath their clipped edge. + +```sh +uv run --with cairosvg==2.9.1 python wolfskin-design/generate_request_marks.py +``` + +`RequestsCaptureTest` writes `st-081`โ€ฆ`st-086`, `st-088` and `st-111` at 1920ร—1080, +density 2.0. Title selection opens the shared native title destination by media +type and TMDB identity. Back restores the exact Coming-in row and expansion; +the temporary `request-title/...` placeholder is removed. TV sign-in, release +and device deployment remain separate. + +## Libraries and See all + +Movies, Shows and Anime use the shell's retained view and a continuous six-column +lazy grid. Up from its first row reaches Sort/Filter, then the nav; Back preserves +the card and scroll. Sort cycles Aโ€“Z, Recently added and Rating. The letter rail +exists only at 200 titles with Aโ€“Z selected. Card OK activates on key-up through +the same shell hold guard, without a long-press menu. +Down clamps a short final title row before entering the separate Try again / Show +more row; an empty slot cannot activate recovery. An unavailable library hides +its unknown item count. + +Caption separators use 40% of the existing muted colour's alpha. The rail follows +the locked prototype CSS: bold 24 px letters, with the focused letter bold 28 px, +overriding the spec table's generic caption style for this component. +Library and Settings header initials use the muted colour over the person's fill; +navigation and picker avatars retain their dark initials. + +The debug-only `wolfskin-library.json` and `library/assets/` contain the locked +prototype's titles and local poster art. Release libraries read through +`LibraryReadFacade`, with 200-item Jellyfin chunks and ten-minute per-server/person +snapshots using the existing atomic disk cache. Saved data is painted before a +quiet refresh; a failed refresh keeps it. Production ratings remain hidden until +Conductarr sign-in exists. + +Home/Discover shelves open a full list through +`WolfskinSeeAllLists.open(person, key, title, fullList, navigation, loadNextPage)`. +The optional suspend page provider returns `LibraryPage(items, hasMore)` using the +generated Conductarr client. The grid reads within ten cards of its end, deduplicates +title identities, and pauses on Try again or Show more rather than looping. +Title activation opens `title/{id}` through `Destination.Wolfskin` for prototype +identities, or the existing typed media destination for real Jellyfin identities. +Movies, series, episodes and people use the native title family; collections and +music keep their upstream destinations. + +`LibraryCaptureTest` renders the sixteen approved library/See all states offline. +`LibraryKeysTest` reads the approved JSON path and reaches Spirited Away in exactly +20 Android key presses. Paging and snapshot tests cover duplicate-only reads, +failure/retry, stale copies, and person/server isolation. Library captures are written +to `build/wolfskin-captures/library/`; Discover's independent captures use `discover/`. + +## Title pages and people + +`TitleSurface` owns the film/series/episode header, season chips, episode tiles, +cast and related shelves. `PersonSurface` owns the real biography and continuous +six-column filmography. Both reuse the shell/nav/back ladder, `LibraryPoster`, +the adaptive `LibraryRatingPlate`, shared captions and the single bounded +`WolfskinImages` loader. Image requests use exact slot sizes, RGB565 for opaque +posters, no crossfade, four concurrent reads and next-row prefetch. The fixed +title backdrop remains visible behind deep rows; only off-screen row images +leave composition. + +The options row preserves complete labels beyond the copy-column measure. +Version choices close after selection; Audio and subtitles stays open, including +an explicit Off choice. Real source IDs use the Jellyfin SDK UUID parser, and +stream indexes remain the server's indexes rather than positions in a list. +Selections persist through the same playback repository as the upstream player. +Marking a whole series asks first; an explicit episode remains the exact play and +watched target even while another season is selected. Nested person/title visits +retain their entry's focus and selection state. +Hardware and remote Back share the sheet/picker/request-overlay precedence, then +pop a pushed title/person from content **or** nav. Initial loading has no content +target: Down stays in nav, while Back can still leave the title. A missing rating +set emits no layout node, so it cannot reserve an invisible extra facts gap. + +`TitleReadFacade` confines SDK reads, server/user-scoped last-good disk copies, +person credits and playback mutations to one boundary. Cached content appears +before refresh. Production ratings stay hidden until Conductarr sign-in exists. +Debug-only `wolfskin-titles.json` and local `wolfskin-titles/assets/` project the +locked household fixture, including portraits; release never packages them. +Those synthetic IDs are not invented Jellyfin playback IDs. Real held-title +playback uses the existing player; debug catalogue identities cannot play a file. + +Held trailers use Jellyfin remote/local trailer data. YouTube URLs target an +installed YouTube handler such as SmartTube, never a browser. No handler leaves +the title visible with a calm message. Titles nobody holds have no Trailer +button until Conductarr's trailer field exists. Conductarr sign-in and request +submission/receipt workflows belong to their separate slices; title pages do not +pretend those operations succeeded or fall back to Seerr. + +`TitleCaptureTest` writes the 34 approved title/person/options frames plus native +text weights, colours, line boxes and bounds at 1920ร—1080, density 2.0. The approved +typeface ruling keeps platform Roboto, not the browser's DejaVu Sans: no per-title +compensation and no wrapping-parity claim. Explicit CSS line boxes constrain title +headers, sheets, cast and poster captions without changing shared type tokens. +Fractional stack placement rounds only the accumulated position, preventing a +one-pixel-per-row drift. Focused controls share the canonical lift shadow. +`TitleKeysTest` replays real Android keys, including modal Back/hold, nearest-row +entry, remembered columns, long-sheet visibility and full media-table geometry. +`TitleAsyncFocusTest` delays title and person replies through the real destination +and view-model, then exercises content focus and hardware Back. Subtitles Off +maps to the player's explicit disabled sentinel, not its unspecified default. + +`TitleLaunchKeysTest` starts at Who's watching and replays the full 4/8/15/11 +sequences through the real Home hero/shelves and title/person surfaces. +`title-press-paths.json` supplies every event; no prefix is skipped or padded. +The shorter 1/5/6/2 title-entry replays remain as focused regressions. SDK cache, +exact-episode, track-index, identity, locale-layout and trailer-handler tests +run offline with in-process service replies and local art. + +## Offline states and recovery + +Owned screens share `RecoveryToast`: the warning glyph, 760 px maximum width, +22/28 px padding, 14 px icon gap, 22 px corners and CSS-sized body line boxes. +Network failures never expose transport exception text. Playback failure reads +โ€œCanโ€™t reach Jellyfin to play. Check the network and try again.โ€ and leaves the +originating card focused; no simulated player hand-off panel is shipped. Retry +failure reads โ€œStill canโ€™t reach it. The last saved view stays on screen.โ€ + +Library headers and the nav publish the same saved-copy timestamp. Failed library +refreshes retain cards and expose a reachable Try again tail. Discover retains its +current catalogue after a failed refresh, adds a recovery tail and disables request +and dismissal writes until recovery; a revoked sign-in discards that saved projection. +Previously observed plates can remain visible offline, but moving to an uncached +card cannot start a ratings read. `SavedPill` shares the compact cached-header +treatment across Home, Libraries and Requests; the nav retains its larger wifi chip. + +Requests focus, observed ratings and retained rows are partitioned by selected person. +A failed authenticated read preserves the last rows and their timestamp; Down from +the final row reaches Try again and Up returns to the row. Signed-out data is not +retained as an authenticated copy. Returning to a foreground person triggers that +person's refresh rather than waiting for the prior person's polling timer. + +Home disk snapshots remain server/user scoped. A new identity starts with its own +skeleton or saved copy, never the previous person's projection; late responses from +an older read cannot overwrite the current identity. A disk-write failure does not +turn a successful Jellyfin read into an outage. Skeleton-only Home, Library and +Discover screens keep focus in the nav even when Down is pressed repeatedly. + +Library/Discover posters use the same title/glyph/160-degree gradient fallback as +Home, including an actual Coil read failure. Discover hero image failures use the +shared ambient background; missing artwork is not a successful data refresh. + +`RecoveryStateTest`, `RecoveryCaptureTest`, `HomeRecoveryTest` and `PlayerHandoffTest` +exercise state transitions, person isolation, native recovery focus/geometry and the +real upstream playback destination with offline fixtures. New native captures and +rendered text/font metrics go to `build/wolfskin-captures/recovery/`; Dutch score +captures configure the Android resource locale as well as the JVM locale. + +Production Conductarr TV sign-in/provider wiring remains outside these state +components: release Discover is signed out and release Requests is unavailable. +The generated client's identity-scoped disk cache is the Conductarr cache boundary; +no Seerr fallback, live-test server, handwritten HTTP or offline request queue is added. +Title and person surfaces publish saved timestamps through the same per-person +`RememberedView` partition and nav Saved indicator. Their timed notices render +the shared `RecoveryToast`; failed Try again and playback use `RecoveryMessage` +without transport details. A selected-person mismatch never renders the former +person's title/person projection. Title and performer disk copies remain isolated +by both server and authenticated user; native retry and cache-isolation regressions +exercise these boundaries without a live service. + ## Toolchain and disk use `Dockerfile` pins Temurin JDK `21.0.11+10` by image digest, command-line tools diff --git a/settings.gradle.kts b/settings.gradle.kts index f2687b17..76b787aa 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -30,4 +30,5 @@ dependencyResolutionManagement { rootProject.name = "Wholphin" include(":app") include(":wholphin-mpv-stub") +include(":wolfskin-design") include(":conductarr-client") diff --git a/wolfskin-design/build.gradle.kts b/wolfskin-design/build.gradle.kts new file mode 100644 index 00000000..d1275edb --- /dev/null +++ b/wolfskin-design/build.gradle.kts @@ -0,0 +1,68 @@ +import java.security.MessageDigest +import org.jetbrains.kotlin.gradle.dsl.JvmTarget + +plugins { + alias(libs.plugins.android.library) + alias(libs.plugins.kotlin.compose) +} + +android { + namespace = "org.justinvisser.wolfskin.design" + compileSdk = libs.versions.compileSdk.get().toInt() + defaultConfig { minSdk = libs.versions.minSdk.get().toInt() } + buildFeatures { compose = true } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + testOptions.unitTests.isIncludeAndroidResources = true +} +kotlin.compilerOptions.jvmTarget = JvmTarget.JVM_11 + +val robolectricSdk by configurations.creating { + isCanBeResolved = true + isCanBeConsumed = false + isTransitive = false +} +val cacheRobolectricSdk by tasks.registering(Copy::class) { + from(robolectricSdk) + into(layout.buildDirectory.dir("robolectric-sdk")) +} + +val checkTokenDrift by tasks.registering { + inputs.files(fileTree(projectDir) { include("tokens.json", "shell-tokens.json", "title-tokens.json", "home-tokens.json", "discover-tokens.json", "generate_tokens.py", "tokens.css", "tokens.sha256", "src/main/java/**/WolfskinTokens.kt") }) + doLast { + file("tokens.sha256").readLines().forEach { line -> + val (expected, name) = line.split(" ", limit = 2) + val actual = MessageDigest.getInstance("SHA-256").digest(file(name).readBytes()).joinToString("") { "%02x".format(it) } + check(actual == expected) { "Token drift in $name: run python3 wolfskin-design/generate_tokens.py" } + } + } +} +tasks.named("preBuild") { dependsOn(checkTokenDrift) } +tasks.withType().configureEach { + dependsOn(cacheRobolectricSdk) + systemProperty("robolectric.dependency.dir", layout.buildDirectory.dir("robolectric-sdk").get().asFile.absolutePath) + systemProperty("robolectric.offline", "true") + systemProperty("robolectric.graphicsMode", "NATIVE") + systemProperty("roborazzi.test.record", "true") + systemProperty("wolfskin.captureDirectory", rootProject.layout.buildDirectory.dir("wolfskin-captures").get().asFile.absolutePath) +} + +dependencies { + robolectricSdk("org.robolectric:android-all-instrumented:9-robolectric-4913185-2-i7") + robolectricSdk("org.robolectric:android-all-instrumented:11-robolectric-6757853-i7") + robolectricSdk("org.robolectric:android-all-instrumented:14-robolectric-10818077-i7") + implementation(platform(libs.androidx.compose.bom)) + implementation(libs.androidx.compose.ui) + implementation(libs.androidx.tv.material) + implementation(libs.coil.compose) + debugImplementation(libs.androidx.compose.ui.test.manifest) + testImplementation(libs.junit) + testImplementation(libs.kotlinx.coroutines.test) + testImplementation(libs.robolectric) + implementation(libs.androidx.compose.material3) + testImplementation(libs.androidx.compose.ui.test.junit4) + testImplementation("io.github.takahirom.roborazzi:roborazzi:1.77.0") + testImplementation("io.github.takahirom.roborazzi:roborazzi-compose:1.77.0") +} diff --git a/wolfskin-design/discover-tokens.json b/wolfskin-design/discover-tokens.json new file mode 100644 index 00000000..83266ff5 --- /dev/null +++ b/wolfskin-design/discover-tokens.json @@ -0,0 +1,279 @@ +{ + "discover": { + "sheetPaddingX": { + "$type": "dimension", + "px": 64, + "dp": 32, + "source": "locked index.html:227" + }, + "sheetPaddingY": { + "$type": "dimension", + "px": 80, + "dp": 40, + "source": "locked index.html:227" + }, + "sheetGap": { + "$type": "dimension", + "px": 18, + "dp": 9, + "source": "locked index.html:227" + }, + "sheetSubGap": { + "$type": "dimension", + "px": 14, + "dp": 7, + "source": "locked index.html:229" + }, + "sheetRowPadding": { + "$type": "dimension", + "px": 26, + "dp": 13, + "source": "locked index.html:231" + }, + "sheetAvatar": { + "$type": "dimension", + "px": 60, + "dp": 30, + "source": "locked index.html:232" + }, + "sheetRadio": { + "$type": "dimension", + "px": 40, + "dp": 20, + "source": "locked index.html:234" + }, + "sheetRadioDot": { + "$type": "dimension", + "px": 16, + "dp": 8, + "source": "locked index.html:236" + }, + "sheetPersonGap": { + "$type": "dimension", + "px": 24, + "dp": 12, + "source": "locked index.html:231" + }, + "sheetButtonTop": { + "$type": "dimension", + "px": 12, + "dp": 6, + "source": "locked index.html:241" + }, + "chipTop": { + "$type": "dimension", + "px": 16, + "dp": 8, + "source": "locked index.html:184" + }, + "chipHeight": { + "$type": "dimension", + "px": 68, + "dp": 34, + "source": "locked index.html:185" + }, + "chipPadding": { + "$type": "dimension", + "px": 28, + "dp": 14, + "source": "locked index.html:185" + }, + "chipGap": { + "$type": "dimension", + "px": 16, + "dp": 8, + "source": "locked index.html:184" + }, + "heroTitleGap": { + "$type": "dimension", + "px": 16, + "dp": 8, + "source": "locked index.html:103" + }, + "heroKickerGap": { + "$type": "dimension", + "px": 10, + "dp": 5, + "source": "locked index.html:101" + }, + "heroMetaGap": { + "$type": "dimension", + "px": 14, + "dp": 7, + "source": "locked index.html:104" + }, + "heroOverviewGap": { + "$type": "dimension", + "px": 30, + "dp": 15, + "source": "locked index.html:105" + }, + "heroFactsGap": { + "$type": "dimension", + "px": 22, + "dp": 11, + "source": "locked index.html:104" + }, + "heroFactsHeight": { + "$type": "dimension", + "px": 38, + "dp": 19, + "source": "locked index.html:104" + }, + "heroSheetRight": { + "$type": "dimension", + "px": 180, + "dp": 90, + "source": "locked index.html:97" + }, + "heroSheetTop": { + "$type": "dimension", + "px": 140, + "dp": 70, + "source": "locked index.html:98" + }, + "heroSheetWidth": { + "$type": "dimension", + "px": 360, + "dp": 180, + "source": "locked index.html:98" + }, + "heroSheetHeight": { + "$type": "dimension", + "px": 540, + "dp": 270, + "source": "locked index.html:98" + }, + "dotSize": { + "$type": "dimension", + "px": 14, + "dp": 7, + "source": "locked index.html:114" + }, + "dotActive": { + "$type": "dimension", + "px": 44, + "dp": 22, + "source": "locked index.html:115" + }, + "dotGap": { + "$type": "dimension", + "px": 14, + "dp": 7, + "source": "locked index.html:113" + }, + "dotMargin": { + "$type": "dimension", + "px": 18, + "dp": 9, + "source": "locked index.html:113" + }, + "dotChevron": { + "$type": "dimension", + "px": 40, + "dp": 20, + "source": "locked index.html:116" + }, + "stateTop": { + "$type": "dimension", + "px": 20, + "dp": 10, + "source": "locked index.html:194" + }, + "statePaddingX": { + "$type": "dimension", + "px": 40, + "dp": 20, + "source": "locked index.html:194" + }, + "statePaddingY": { + "$type": "dimension", + "px": 34, + "dp": 17, + "source": "locked index.html:194" + }, + "stateTextGap": { + "$type": "dimension", + "px": 24, + "dp": 12, + "source": "locked index.html:198" + }, + "noteTop": { + "$type": "dimension", + "px": 14, + "dp": 7, + "source": "locked index.html:191" + }, + "headerTop": { + "$type": "dimension", + "px": 150, + "dp": 75, + "source": "locked index.html:199" + }, + "headerGap": { + "$type": "dimension", + "px": 24, + "dp": 12, + "source": "locked index.html:202" + }, + "entryPaddingX": { + "$type": "dimension", + "px": 22, + "dp": 11, + "source": "locked index.html:149" + }, + "entryPaddingY": { + "$type": "dimension", + "px": 20, + "dp": 10, + "source": "locked index.html:149" + }, + "entryText": { + "$type": "typography", + "px": 30, + "sp": 15, + "weight": 800, + "letterSpacingEm": -0.01, + "$value": { + "fontSize": "15sp", + "fontWeight": 800 + }, + "source": "locked index.html:149" + }, + "sheetRadioRing": { + "$type": "dimension", + "px": 3, + "dp": 1.5, + "source": "locked index.html:234" + }, + "skeletonNameWidth": { + "$type": "dimension", + "px": 260, + "dp": 130, + "source": "locked index.html:1851" + }, + "skeletonNameHeight": { + "$type": "dimension", + "px": 34, + "dp": 17, + "source": "locked index.html:1851" + }, + "sheetSubTop": {"$type": "dimension", "px": -8, "dp": -4, "source": "locked index.html:229"}, + "sheetRatingTop": {"$type": "dimension", "px": -10, "dp": -5, "source": "locked index.html:168"}, + "sheetRatingBottom": {"$type": "dimension", "px": 6, "dp": 3, "source": "locked index.html:168"}, + "sheetLabelTop": {"$type": "dimension", "px": 8, "dp": 4, "source": "locked index.html:230"}, + "noteIcon": {"$type": "dimension", "px": 30, "dp": 15, "source": "locked index.html:192"}, + "noteGap": {"$type": "dimension", "px": 16, "dp": 8, "source": "locked index.html:191"}, + "frameBottomMin": {"$type": "dimension", "px": 80, "dp": 40, "source": "locked index.html:1042"}, + "anchorFitTop": {"$type": "dimension", "px": 700, "dp": 350, "source": "locked index.html:1062"}, + "anchorBottomClearance": {"$type": "dimension", "px": 40, "dp": 20, "source": "locked index.html:1062"}, + "reasonOpacity": {"$type": "number", "$value": 0.8, "source": "locked index.html:240"}, + "stageGap": {"$type": "dimension", "px": 10, "dp": 5, "source": "locked index.html:220"}, + "entryBorderOpacity": {"$type": "number", "$value": 0.08, "source": "locked index.html:149"}, + "ambientInset": {"$type": "dimension", "px": 80, "dp": 40, "source": "locked index.html:96"}, + "ambientBlur": {"$type": "dimension", "px": 60, "dp": 30, "source": "locked index.html:96"}, + "ambientScale": {"$type": "number", "$value": 1.1, "source": "locked index.html:96"}, + "ambientSaturation": {"$type": "number", "$value": 1.2, "source": "locked index.html:96"}, + "ambientBrightness": {"$type": "number", "$value": 0.55, "source": "locked index.html:96"} + } +} diff --git a/wolfskin-design/generate_request_marks.py b/wolfskin-design/generate_request_marks.py new file mode 100755 index 00000000..bba6a960 --- /dev/null +++ b/wolfskin-design/generate_request_marks.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python3 +"""Rasterize locked prototype rating marks at the Coming-in row's native pixel size.""" +from pathlib import Path +import hashlib +import json +import cairosvg + +ROOT = Path(__file__).resolve().parent +SOURCE = ROOT / "request-marks" +OUTPUT = ROOT / "src/main/res/drawable-nodpi" + + +def main() -> None: + """Keep the original SVGs and record hashes alongside generated television-size PNGs.""" + OUTPUT.mkdir(parents=True, exist_ok=True) + tokens = json.loads((ROOT / "tokens.json").read_text()) + supplement = json.loads((ROOT / "shell-tokens.json").read_text()) + height = int(tokens["type"]["label"]["px"]) + wordmark_ratio = supplement["requests"]["ratingsWordmarkRatio"]["$value"] + manifest = [] + for source in sorted(SOURCE.glob("*.svg")): + target = OUTPUT / f"coming_in_rating_{source.stem}.png" + width = round(height * wordmark_ratio) if source.stem in ("imdb", "tmdb") else height + cairosvg.svg2png(url=str(source), write_to=str(target), output_width=width, output_height=height) + for path in (source, target): + manifest.append(f"{hashlib.sha256(path.read_bytes()).hexdigest()} {path.relative_to(ROOT)}") + (ROOT / "request-marks.sha256").write_text("\n".join(manifest) + "\n") + + +if __name__ == "__main__": + main() diff --git a/wolfskin-design/generate_tokens.py b/wolfskin-design/generate_tokens.py new file mode 100755 index 00000000..51a49b20 --- /dev/null +++ b/wolfskin-design/generate_tokens.py @@ -0,0 +1,137 @@ +#!/usr/bin/env python3 +"""Generate Compose and CSS tokens and a build-verifiable drift manifest.""" +from __future__ import annotations + +import argparse +import hashlib +import json +from pathlib import Path + +ROOT = Path(__file__).resolve().parent +KOTLIN = Path("src/main/java/org/justinvisser/wolfskin/design/WolfskinTokens.kt") + + +def number(value: float) -> str: + """Render stable Kotlin decimal literals.""" + return str(float(value)) + + +def property_name(name: str) -> str: + """Keep source names valid as Kotlin identifiers.""" + return name.replace("-", "_") + + +def compose_weight(weight: int) -> str: + """Use the platform bold face for intermediate weights that resolve to Regular in native captures.""" + return "FontWeight.Bold" if 600 <= weight <= 700 else f"FontWeight({weight})" + + +def render_tokens(tokens: dict) -> tuple[str, str]: + """Translate locked values into platform-resolvable Compose and CSS tokens.""" + lines = [ + "// Generated by generate_tokens.py; edit the JSON sources instead.", + "package org.justinvisser.wolfskin.design", + "", + "import androidx.compose.ui.graphics.Color as ComposeColor", + "import androidx.compose.ui.text.TextStyle", + "import androidx.compose.ui.text.font.FontWeight", + "import androidx.compose.ui.unit.dp", + "import androidx.compose.ui.unit.em", + "import androidx.compose.ui.unit.sp", + "", + "/** The locked TV design, converted at the source density. */", + "object WolfskinTokens {", + ] + css = ["/* Generated from the locked TV token sources. */", ":root {"] + for group_name, group in tokens.items(): + if group_name.startswith("$") or group_name in ("meta", "font"): + continue + lines.append(f" object {group_name[0].upper() + group_name[1:]} {{") + for name, token in group.items(): + if not isinstance(token, dict): + continue + name = property_name(name) + kind = token.get("$type") + value = token.get("$value") + if kind == "color": + rgba = value.lstrip("#") + argb = (rgba[6:8] if len(rgba) == 8 else "ff") + rgba[:6] + lines.append(f" val {name} = ComposeColor(0x{argb.upper()})") + css.append(f" --{group_name}-{name}: {value};") + elif kind == "typography" and "sp" in token: + size = token["sp"] + weight = token.get("weight", token["$value"]["fontWeight"]) + height = size * token.get("lineHeight", 1.3) + tracking = token.get("letterSpacingEm", 0) + lines.append(f" val {name} = TextStyle(fontSize = {number(size)}.sp, fontWeight = {compose_weight(weight)}, lineHeight = {number(height)}.sp, letterSpacing = {number(tracking)}.em)") + css.append(f" --{group_name}-{name}: {number(token['px'])}px;") + elif kind == "typography" and "sizes" in token: + for context, pixels in token["sizes"].items(): + lines.append(f" val {name}{context[0].upper() + context[1:]} = TextStyle(fontSize = {number(pixels / 2)}.sp, fontWeight = {compose_weight(token['weight'])})") + elif kind == "duration": + lines.append(f" const val {name} = {int(value.removesuffix('ms'))}") + css.append(f" --{group_name}-{name}: {value};") + elif kind == "transition" and value.get("type") == "spring": + lines.append(f" const val {name}DampingRatio = {number(value['dampingRatio'])}f") + lines.append(f" const val {name}Stiffness = {number(value['stiffness'])}f") + elif kind == "shadow": + for suffix in ("gapPx", "ringPx"): + lines.append(f" val {name}{suffix[0].upper() + suffix[1:-2]} = {number(token[suffix] / 2)}.dp") + elif isinstance(token.get("dp"), (float, int)): + lines.append(f" val {name} = {number(token['dp'])}.dp") + css.append(f" --{group_name}-{name}: {number(token['px'])}px;") + elif isinstance(token.get("dp"), list): + for suffix, dimension in zip(("Width", "Height"), token["dp"]): + lines.append(f" val {name}{suffix} = {number(dimension)}.dp") + elif isinstance(token.get("dp"), dict): + for suffix, dimension in token["dp"].items(): + lines.append(f" val {name}{suffix[0].upper() + suffix[1:]} = {number(dimension)}.dp") + if kind == "card": + lines.append(f" const val {name}Slots = {token['fullSlotsPerRow']}") + elif group_name == "image" and isinstance(token.get("px"), list): + for suffix, dimension in zip(("Width", "Height"), token["px"]): + lines.append(f" const val {name}{suffix} = {int(dimension)}") + elif group_name == "image" and isinstance(value, dict): + for suffix, count in value.items(): + lines.append(f" const val {name}{suffix[0].upper() + suffix[1:]} = {int(count)}") + elif isinstance(value, (float, int)) and not isinstance(value, bool): + lines.append(f" const val {name} = {number(value)}f") + elif kind in ("gradient", "filter", "rule") and isinstance(value, str): + lines.append(f" const val {name} = {json.dumps(value)}") + if kind == "gradient": + css.append(f" --{group_name}-{name}: {value};") + lines.append(" }") + lines.append("}") + css.append("}") + return "\n".join(lines) + "\n", "\n".join(css) + "\n" + + +def main() -> None: + """Write generated artifacts, or fail when committed artifacts drift.""" + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--check", action="store_true") + arguments = parser.parse_args() + tokens = json.loads((ROOT / "tokens.json").read_text()) + tokens.update(json.loads((ROOT / "shell-tokens.json").read_text())) + tokens.update(json.loads((ROOT / "title-tokens.json").read_text())) + tokens.update(json.loads((ROOT / "home-tokens.json").read_text())) + tokens.update(json.loads((ROOT / "discover-tokens.json").read_text())) + kotlin, css = render_tokens(tokens) + outputs = {str(KOTLIN): kotlin, "tokens.css": css} + inputs = ["tokens.json", "shell-tokens.json", "title-tokens.json", "home-tokens.json", "discover-tokens.json", "generate_tokens.py"] + checksums = {name: hashlib.sha256((ROOT / name).read_bytes()).hexdigest() for name in inputs} + checksums.update({name: hashlib.sha256(content.encode()).hexdigest() for name, content in outputs.items()}) + outputs["tokens.sha256"] = "".join(f"{checksum} {name}\n" for name, checksum in sorted(checksums.items())) + for name, content in outputs.items(): + path = ROOT / name + if arguments.check: + if not path.exists() or path.read_text() != content: + raise SystemExit(f"Token drift: run python3 wolfskin-design/generate_tokens.py ({name})") + else: + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text(content) + print("Token drift check passed" if arguments.check else "Generated Kotlin, CSS and drift manifest") + + +if __name__ == "__main__": + main() diff --git a/wolfskin-design/home-tokens.json b/wolfskin-design/home-tokens.json new file mode 100644 index 00000000..a574a31d --- /dev/null +++ b/wolfskin-design/home-tokens.json @@ -0,0 +1,322 @@ +{ + "home": { + "kickerGap": { + "$type": "dimension", + "px": 12, + "dp": 6.0, + "source": "locked index.html:94-165,180-198,1014-1029,1276-1289" + }, + "kickerBottom": { + "$type": "dimension", + "px": 10, + "dp": 5.0, + "source": "locked index.html:101" + }, + "titleBottom": { + "$type": "dimension", + "px": 16, + "dp": 8.0, + "source": "locked index.html:103" + }, + "factsHeight": { + "$type": "dimension", + "px": 38, + "dp": 19.0, + "source": "locked index.html:94-165,180-198,1014-1029,1276-1289" + }, + "factsBottom": { + "$type": "dimension", + "px": 14, + "dp": 7.0, + "source": "locked index.html:94-165,180-198,1014-1029,1276-1289" + }, + "factsGap": { + "$type": "dimension", + "px": 22, + "dp": 11.0, + "source": "locked index.html:94-165,180-198,1014-1029,1276-1289" + }, + "overviewBottom": { + "$type": "dimension", + "px": 30, + "dp": 15.0, + "source": "locked index.html:94-165,180-198,1014-1029,1276-1289" + }, + "cardPadding": { + "$type": "dimension", + "px": 22, + "dp": 11.0, + "source": "locked index.html:94-165,180-198,1014-1029,1276-1289" + }, + "cardOverlayTop": { + "$type": "dimension", + "px": 54, + "dp": 27.0, + "source": "locked index.html:94-165,180-198,1014-1029,1276-1289" + }, + "cardOverlayBottom": { + "$type": "dimension", + "px": 18, + "dp": 9.0, + "source": "locked index.html:94-165,180-198,1014-1029,1276-1289" + }, + "sectionTop": { + "$type": "dimension", + "px": 40, + "dp": 20.0, + "source": "locked index.html:94-165,180-198,1014-1029,1276-1289" + }, + "sectionAvatar": { + "$type": "dimension", + "px": 56, + "dp": 28.0, + "source": "locked index.html:94-165,180-198,1014-1029,1276-1289" + }, + "sectionGap": { + "$type": "dimension", + "px": 22, + "dp": 11.0, + "source": "locked index.html:180" + }, + "stateTextBottom": { + "$type": "dimension", + "px": 24, + "dp": 12.0, + "source": "locked index.html:198" + }, + "stateTop": { + "$type": "dimension", + "px": 20, + "dp": 10.0, + "source": "locked index.html:194" + }, + "statePaddingX": { + "$type": "dimension", + "px": 40, + "dp": 20.0, + "source": "locked index.html:94-165,180-198,1014-1029,1276-1289" + }, + "statePaddingY": { + "$type": "dimension", + "px": 34, + "dp": 17.0, + "source": "locked index.html:94-165,180-198,1014-1029,1276-1289" + }, + "stateGap": { + "$type": "dimension", + "px": 8, + "dp": 4.0, + "source": "locked index.html:195" + }, + "stateIcon": { + "$type": "dimension", + "px": 36, + "dp": 18.0, + "source": "locked index.html:94-165,180-198,1014-1029,1276-1289" + }, + "captionWidth": { + "$type": "dimension", + "px": 640, + "dp": 320.0, + "source": "locked index.html:94-165,180-198,1014-1029,1276-1289" + }, + "plateTop": { + "$type": "dimension", + "px": 14, + "dp": 7.0, + "source": "locked index.html:94-165,180-198,1014-1029,1276-1289" + }, + "plateSide": { + "$type": "dimension", + "px": 16, + "dp": 8.0, + "source": "locked index.html:94-165,180-198,1014-1029,1276-1289" + }, + "plateFade": { + "$type": "dimension", + "px": 46, + "dp": 23.0, + "source": "locked index.html:94-165,180-198,1014-1029,1276-1289" + }, + "ratingGap": { + "$type": "dimension", + "px": 20, + "dp": 10.0, + "source": "locked index.html:94-165,180-198,1014-1029,1276-1289" + }, + "ratingMarkGap": { + "$type": "dimension", + "px": 8, + "dp": 4.0, + "source": "locked index.html:94-165,180-198,1014-1029,1276-1289" + }, + "heroSkeletonWidth": { + "$type": "dimension", + "px": 640, + "dp": 320.0, + "source": "locked index.html:94-165,180-198,1014-1029,1276-1289" + }, + "heroSkeletonHeight": { + "$type": "dimension", + "px": 84, + "dp": 42.0, + "source": "locked index.html:94-165,180-198,1014-1029,1276-1289" + }, + "heroSkeletonFactsWidth": { + "$type": "dimension", + "px": 460, + "dp": 230.0, + "source": "locked index.html:94-165,180-198,1014-1029,1276-1289" + }, + "heroSkeletonFactsHeight": { + "$type": "dimension", + "px": 34, + "dp": 17.0, + "source": "locked index.html:94-165,180-198,1014-1029,1276-1289" + }, + "heroSkeletonButtonWidth": { + "$type": "dimension", + "px": 260, + "dp": 130.0, + "source": "locked index.html:94-165,180-198,1014-1029,1276-1289" + }, + "heroSkeletonGap": { + "$type": "dimension", + "px": 22, + "dp": 11.0, + "source": "locked index.html:94-165,180-198,1014-1029,1276-1289" + }, + "heroSkeletonButtonGap": { + "$type": "dimension", + "px": 40, + "dp": 20.0, + "source": "locked index.html:94-165,180-198,1014-1029,1276-1289" + }, + "artGlyph": { + "$type": "dimension", + "px": 44, + "dp": 22.0, + "source": "locked index.html:94-165,180-198,1014-1029,1276-1289" + }, + "cardSheetLeft": { + "$type": "dimension", + "px": 22, + "dp": 11.0, + "source": "locked index.html:94-165,180-198,1014-1029,1276-1289" + }, + "cardSheetTop": { + "$type": "dimension", + "px": 18, + "dp": 9.0, + "source": "locked index.html:94-165,180-198,1014-1029,1276-1289" + }, + "cardSheetInset": { + "$type": "dimension", + "px": 36, + "dp": 18.0, + "source": "locked index.html:94-165,180-198,1014-1029,1276-1289" + }, + "heroSheetRight": { + "$type": "dimension", + "px": 180, + "dp": 90.0, + "source": "locked index.html:94-165,180-198,1014-1029,1276-1289" + }, + "heroSheetTop": { + "$type": "dimension", + "px": 150, + "dp": 75.0, + "source": "locked index.html:94-165,180-198,1014-1029,1276-1289" + }, + "cardBlur": { + "$type": "dimension", + "px": 26, + "dp": 13.0, + "source": "locked index.html:94-165,180-198,1014-1029,1276-1289" + }, + "heroBlur": { + "$type": "dimension", + "px": 60, + "dp": 30.0, + "source": "locked index.html:94-165,180-198,1014-1029,1276-1289" + }, + "progressInset": { + "$type": "dimension", + "px": 18, + "dp": 9.0, + "source": "locked index.html:94-165,180-198,1014-1029,1276-1289" + }, + "progressBottom": { + "$type": "dimension", + "px": 10, + "dp": 5.0, + "source": "locked index.html:94-165,180-198,1014-1029,1276-1289" + }, + "endTop": { + "$type": "dimension", + "px": 40, + "dp": 20.0, + "source": "locked index.html:94-165,180-198,1014-1029,1276-1289" + }, + "frameBottom": { + "$type": "dimension", + "px": 80, + "dp": 40.0, + "source": "locked index.html:1042" + }, + "toastPadding": { + "$type": "dimension", + "px": 28, + "dp": 14.0, + "source": "locked index.html:94-165,180-198,1014-1029,1276-1289" + }, + "toastTop": { + "$type": "dimension", + "px": 150, + "dp": 75.0, + "source": "locked index.html:94-165,180-198,1014-1029,1276-1289" + }, + "toastWidth": { + "$type": "dimension", + "px": 760, + "dp": 380.0, + "source": "locked index.html:94-165,180-198,1014-1029,1276-1289" + }, + "toastPaddingY": { "$type": "dimension", "px": 22, "dp": 11, "source": "locked index.html:270" }, + "toastGap": { "$type": "dimension", "px": 14, "dp": 7, "source": "locked index.html:270" }, + "toastShadowBlur": { "$type": "dimension", "px": 60, "dp": 30, "source": "locked index.html:270" }, + "toastShadowY": { "$type": "dimension", "px": 20, "dp": 10, "source": "locked index.html:270" }, + "toastShadowOpacity": { "$type": "number", "$value": 0.5, "source": "locked index.html:270" }, + "cardWashInset": { + "$type": "dimension", + "px": 30, + "dp": 15.0, + "source": "locked index.html:129" + }, + "heroWashInset": { + "$type": "dimension", + "px": 80, + "dp": 40.0, + "source": "locked index.html:96" + }, + "noteTop": { + "$type": "dimension", + "px": 14, + "dp": 7.0, + "source": "locked index.html:191" + }, + "noteGap": { + "$type": "dimension", + "px": 16, + "dp": 8.0, + "source": "locked index.html:191" + }, + "hairline": { "$type": "dimension", "px": 2, "dp": 1.0, "source": "locked index.html:87,146,194" }, + "savedHeight": { "$type": "dimension", "px": 52, "dp": 26.0, "source": "locked index.html:87" }, + "savedPadding": { "$type": "dimension", "px": 20, "dp": 10.0, "source": "locked index.html:87" }, + "savedGap": { "$type": "dimension", "px": 10, "dp": 5.0, "source": "locked index.html:87" }, + "savedIcon": { "$type": "dimension", "px": 28, "dp": 14.0, "source": "locked index.html:88" }, + "savedRadius": { "$type": "dimension", "px": 28, "dp": 14.0, "source": "locked index.html:87" }, + "posterProgressBottom": { "$type": "dimension", "px": 12, "dp": 6.0, "source": "locked index.html:138-140" } + } +} diff --git a/wolfskin-design/request-marks.sha256 b/wolfskin-design/request-marks.sha256 new file mode 100644 index 00000000..c29ddefc --- /dev/null +++ b/wolfskin-design/request-marks.sha256 @@ -0,0 +1,12 @@ +01aa8a3c3e9db48f0e1c6af25056940986784315bf66f48a8120a7317bf6d75a request-marks/fresh.svg +743b6139dc12019d0940568869065722593f44ce416a7e9c7b8d9ef92942bb3f src/main/res/drawable-nodpi/coming_in_rating_fresh.png +27f93b15a075b015e2448eca7949f7a3da03c37fbf26cecf6df3bdab45fda993 request-marks/imdb.svg +a738afd57519b1b4a38192927b48bd45755ce75e4673c6b12b9b3e0c2e388372 src/main/res/drawable-nodpi/coming_in_rating_imdb.png +510d0f9fb77d72190ebf03208f04215a4e86f71e165488518ac75aa49cf4a79d request-marks/rotten.svg +0aade711ba57b6b201c7395ece97108df928b6076d8120404cdf4155a4242632 src/main/res/drawable-nodpi/coming_in_rating_rotten.png +b8dcf4d27eba2446380980c96d82b1f64aa6859fa2ea1cdab867f849f9fec4fd request-marks/spilled.svg +fa4f50258009cd1d16f0d0f5a3c216dc88a57409b1bccc379512ae914cc9d714 src/main/res/drawable-nodpi/coming_in_rating_spilled.png +d537fb228cf3ded904ef09b136fe3fec72548ebc1fea3fbbd1ad9e36364db38b request-marks/tmdb.svg +8e1cb507f876f324bb5c53bf4e60775712f1fdddbffe94fd249e6e74099e045e src/main/res/drawable-nodpi/coming_in_rating_tmdb.png +2ad511c7a101a7f2f8810434911df8c13cc126fa691272242037237172600bc3 request-marks/upright.svg +6ff8a05501bc1c15b96c0130271c41baaa2ddb74f64916f58b9e7f918931d789 src/main/res/drawable-nodpi/coming_in_rating_upright.png diff --git a/wolfskin-design/request-marks/fresh.svg b/wolfskin-design/request-marks/fresh.svg new file mode 100644 index 00000000..977253a9 --- /dev/null +++ b/wolfskin-design/request-marks/fresh.svg @@ -0,0 +1,20 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/wolfskin-design/request-marks/imdb.svg b/wolfskin-design/request-marks/imdb.svg new file mode 100644 index 00000000..b2a908bc --- /dev/null +++ b/wolfskin-design/request-marks/imdb.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/wolfskin-design/request-marks/rotten.svg b/wolfskin-design/request-marks/rotten.svg new file mode 100644 index 00000000..04bef05b --- /dev/null +++ b/wolfskin-design/request-marks/rotten.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wolfskin-design/request-marks/spilled.svg b/wolfskin-design/request-marks/spilled.svg new file mode 100644 index 00000000..af36063b --- /dev/null +++ b/wolfskin-design/request-marks/spilled.svg @@ -0,0 +1,46 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wolfskin-design/request-marks/tmdb.svg b/wolfskin-design/request-marks/tmdb.svg new file mode 100644 index 00000000..62a66055 --- /dev/null +++ b/wolfskin-design/request-marks/tmdb.svg @@ -0,0 +1 @@ +Asset 4 \ No newline at end of file diff --git a/wolfskin-design/request-marks/upright.svg b/wolfskin-design/request-marks/upright.svg new file mode 100644 index 00000000..bf1cc85a --- /dev/null +++ b/wolfskin-design/request-marks/upright.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wolfskin-design/shell-tokens.json b/wolfskin-design/shell-tokens.json new file mode 100644 index 00000000..e66ac6ec --- /dev/null +++ b/wolfskin-design/shell-tokens.json @@ -0,0 +1,433 @@ +{ + "requests": { + "sheetPaddingY": { "$type": "dimension", "px": 80, "dp": 40, "source": "index.html:227" }, + "sheetPaddingX": { "$type": "dimension", "px": 64, "dp": 32, "source": "index.html:227" }, + "sheetGap": { "$type": "dimension", "px": 18, "dp": 9, "source": "index.html:227" }, + "sheetTitleLineHeight": { "$type": "dimension", "px": 56, "dp": 28, "source": "index.html:228; locked st-083/st-086: content begins at 154px after 80px padding and 18px gap" }, + "sheetTitleBaseline": { "$type": "dimension", "px": 44, "dp": 22, "source": "locked st-083: modal ink-bottom 123px, native baseline boundary 124px minus 80px padding" }, + "titleLineHeight": { "$type": "dimension", "px": 39, "dp": 19.5, "source": "index.html:250; 30px font with 1.3 line box" }, + "titleBaseline": { "$type": "dimension", "px": 31, "dp": 15.5, "source": "locked st-082/st-086: ink-bottom 45px, 15px text-block inset, baseline boundary 1px below ink" }, + "factsLineHeight": { "$type": "dimension", "px": 31.2, "dp": 15.6, "source": "index.html:251; 24px font with 1.3 line box" }, + "factsBaseline": { "$type": "dimension", "px": 24, "dp": 12, "source": "locked st-082/st-086: ink-bottom 77px, 15px block inset, 39px title box and 1px baseline boundary" }, + "stageLineHeight": { "$type": "dimension", "px": 39.6, "dp": 19.8, "source": "index.html:251-252; inline-flex stage within the 28px/1.3 parent strut" }, + "stageLabelLineHeight": { "$type": "dimension", "px": 33.8, "dp": 16.9, "source": "index.html:220; 26px font with 1.3 leading" }, + "stageBaseline": { "$type": "dimension", "px": 24, "dp": 12, "source": "locked st-082/st-086: ink-bottom 112px, 15px block inset, 39px title, 31.2px facts, 4px margin and 1px baseline boundary" }, + "emptyMargin": { "$type": "dimension", "px": 20, "dp": 10, "source": "index.html:1905" }, + "rowPaddingY": { "$type": "dimension", "px": 14, "dp": 7, "source": "index.html:247" }, + "rowPaddingX": { "$type": "dimension", "px": 18, "dp": 9, "source": "index.html:247" }, + "rowGap": { "$type": "dimension", "px": 24, "dp": 12, "source": "index.html:247" }, + "listGap": { "$type": "dimension", "px": 6, "dp": 3, "source": "index.html:255" }, + "stageMargin": { "$type": "dimension", "px": 4, "dp": 2, "source": "index.html:252" }, + "stageGlyph": { "$type": "dimension", "px": 28, "dp": 14, "source": "index.html:221" }, + "stageGap": { "$type": "dimension", "px": 10, "dp": 5, "source": "index.html:220" }, + "readinessGapX": { "$type": "dimension", "px": 22, "dp": 11, "source": "index.html:312" }, + "readinessGapY": { "$type": "dimension", "px": 10, "dp": 5, "source": "index.html:312" }, + "readinessMargin": { "$type": "dimension", "px": 8, "dp": 4, "source": "index.html:312" }, + "readinessGlyph": { "$type": "dimension", "px": 26, "dp": 13, "source": "index.html:314" }, + "chevron": { "$type": "dimension", "px": 30, "dp": 15, "source": "index.html:317" }, + "chevronAlpha": { "$type": "number", "$value": 0.6, "source": "index.html:317" }, + "receiptPaddingY": { "$type": "dimension", "px": 28, "dp": 14, "source": "index.html:243" }, + "receiptPaddingX": { "$type": "dimension", "px": 30, "dp": 15, "source": "index.html:243" }, + "receiptGap": { "$type": "dimension", "px": 10, "dp": 5, "source": "index.html:243" }, + "receiptGlyph": { "$type": "dimension", "px": 36, "dp": 18, "source": "index.html:245" }, + "buttonMargin": { "$type": "dimension", "px": 12, "dp": 6, "source": "index.html:241" }, + "skeletonTitleWidth": { "$type": "dimension", "px": 360, "dp": 180, "source": "index.html:1902" }, + "skeletonTitleHeight": { "$type": "dimension", "px": 34, "dp": 17, "source": "index.html:1902" }, + "skeletonSubtitleWidth": { "$type": "dimension", "px": 240, "dp": 120, "source": "index.html:1902" }, + "skeletonSubtitleHeight": { "$type": "dimension", "px": 26, "dp": 13, "source": "index.html:1902" }, + "skeletonGap": { "$type": "dimension", "px": 12, "dp": 6, "source": "index.html:1902" }, + "ratingsGap": { "$type": "dimension", "px": 20, "dp": 10, "source": "index.html:156" }, + "ratingsEntryGap": { "$type": "dimension", "px": 8, "dp": 4, "source": "index.html:157" }, + "shadowBlur": { "$type": "dimension", "px": 80, "dp": 40, "source": "index.html:227" }, + "shadowOffset": { "$type": "dimension", "px": -30, "dp": -15, "source": "index.html:227" }, + "shadowColor": { "$type": "color", "$value": "#00000080", "source": "index.html:227" }, + "ratingsWordmarkRatio": { "$type": "number", "$value": 1.8, "source": "index.html:160" } + }, + "shell": { + "navLabelFade": { + "$type": "duration", + "$value": "200ms", + "source": "index.html:81; nav label color transition uses 200 ms ease-out" + }, + "zero": { + "$type": "dimension", + "px": 0, + "dp": 0.0, + "source": "locked index.html:71-92, 256-263, 303-328; spec 6.1 and nav-shell measured bounds" + }, + "stageWidth": { + "$type": "dimension", + "px": 1920, + "dp": 960.0, + "source": "locked index.html:71-92, 256-263, 303-328; spec 6.1 and nav-shell measured bounds" + }, + "stageHeight": { + "$type": "dimension", + "px": 1080, + "dp": 540.0, + "source": "locked index.html:71-92, 256-263, 303-328; spec 6.1 and nav-shell measured bounds" + }, + "wordmarkWidth": { + "$type": "dimension", + "px": 169, + "dp": 84.5, + "source": "locked index.html:71-92, 256-263, 303-328; spec 6.1 and nav-shell measured bounds" + }, + "wordmarkTop": { + "$type": "dimension", + "px": 73.6, + "dp": 36.8, + "source": "index.html:74,79: centre a 46.8 px line in the 64 px nav item" + }, + "navHomeWidth": { + "$type": "dimension", + "px": 149, + "dp": 74.5, + "source": "locked index.html:71-92, 256-263, 303-328; spec 6.1 and nav-shell measured bounds" + }, + "navDiscoverWidth": { + "$type": "dimension", + "px": 198, + "dp": 99.0, + "source": "locked index.html:71-92, 256-263, 303-328; spec 6.1 and nav-shell measured bounds" + }, + "navMoviesWidth": { + "$type": "dimension", + "px": 171, + "dp": 85.5, + "source": "locked index.html:71-92, 256-263, 303-328; spec 6.1 and nav-shell measured bounds" + }, + "navShowsWidth": { + "$type": "dimension", + "px": 161, + "dp": 80.5, + "source": "locked index.html:71-92, 256-263, 303-328; spec 6.1 and nav-shell measured bounds" + }, + "navAnimeWidth": { + "$type": "dimension", + "px": 158, + "dp": 79.0, + "source": "locked index.html:71-92, 256-263, 303-328; spec 6.1 and nav-shell measured bounds" + }, + "navItemTop": { + "$type": "dimension", + "px": 65, + "dp": 32.5, + "source": "locked index.html:71-92, 256-263, 303-328; spec 6.1 and nav-shell measured bounds" + }, + "pickerTitleTop": { + "$type": "dimension", + "px": 272.3, + "dp": 136.15, + "source": "locked index.html:71-92, 256-263, 303-328; spec 6.1 and nav-shell measured bounds" + }, + "pickerPeopleTop": { + "$type": "dimension", + "px": 425.5, + "dp": 212.75, + "source": "locked index.html:71-92, 256-263, 303-328; spec 6.1 and nav-shell measured bounds" + }, + "pickerNameGap": { + "$type": "dimension", + "px": 26, + "dp": 13.0, + "source": "locked index.html:71-92, 256-263, 303-328; spec 6.1 and nav-shell measured bounds" + }, + "pickerGearTop": { + "$type": "dimension", + "px": 751.7, + "dp": 375.85, + "source": "locked index.html:71-92, 256-263, 303-328; spec 6.1 and nav-shell measured bounds" + }, + "pickerGearCaptionTop": { + "$type": "dimension", + "px": 72, + "dp": 36.0, + "source": "locked index.html:71-92, 256-263, 303-328; spec 6.1 and nav-shell measured bounds" + }, + "pickerLetter": { + "$type": "dimension", + "px": 100, + "dp": 50.0, + "source": "locked index.html:71-92, 256-263, 303-328; spec 6.1 and nav-shell measured bounds" + }, + "pickerSkeletonNameWidth": { + "$type": "dimension", + "px": 140, + "dp": 70.0, + "source": "locked index.html:71-92, 256-263, 303-328; spec 6.1 and nav-shell measured bounds" + }, + "pickerSkeletonNameHeight": { + "$type": "dimension", + "px": 40, + "dp": 20.0, + "source": "locked index.html:71-92, 256-263, 303-328; spec 6.1 and nav-shell measured bounds" + }, + "pickerLoadingTitleTop": { + "$type": "dimension", + "px": 247.4, + "dp": 123.7, + "source": "locked index.html:71-92, 256-263, 303-328; spec 6.1 and nav-shell measured bounds" + }, + "pickerLoadingPeopleTop": { + "$type": "dimension", + "px": 400.6, + "dp": 200.3, + "source": "locked index.html:71-92, 256-263, 303-328; spec 6.1 and nav-shell measured bounds" + }, + "pickerLoadingButtonTop": { + "$type": "dimension", + "px": 756.6, + "dp": 378.3, + "source": "locked index.html:71-92, 256-263, 303-328; spec 6.1 and nav-shell measured bounds" + }, + "pickerErrorTitleTop": { + "$type": "dimension", + "px": 297.6, + "dp": 148.8, + "source": "locked index.html:71-92, 256-263, 303-328; spec 6.1 and nav-shell measured bounds" + }, + "pickerErrorPanelTop": { + "$type": "dimension", + "px": 450.8, + "dp": 225.4, + "source": "locked index.html:71-92, 256-263, 303-328; spec 6.1 and nav-shell measured bounds" + }, + "pickerErrorPanelWidth": { + "$type": "dimension", + "px": 980, + "dp": 490.0, + "source": "locked index.html:71-92, 256-263, 303-328; spec 6.1 and nav-shell measured bounds" + }, + "pickerErrorPanelHeight": { + "$type": "dimension", + "px": 185.6, + "dp": 92.8, + "source": "locked index.html:71-92, 256-263, 303-328; spec 6.1 and nav-shell measured bounds" + }, + "pickerErrorButtonTop": { + "$type": "dimension", + "px": 706.4, + "dp": 353.2, + "source": "locked index.html:71-92, 256-263, 303-328; spec 6.1 and nav-shell measured bounds" + }, + "settingsHeaderTop": { + "$type": "dimension", + "px": 150, + "dp": 75.0, + "source": "locked index.html:71-92, 256-263, 303-328; spec 6.1 and nav-shell measured bounds" + }, + "settingsHeaderAvatar": { + "$type": "dimension", + "px": 52, + "dp": 26.0, + "source": "locked index.html:71-92, 256-263, 303-328; spec 6.1 and nav-shell measured bounds" + }, + "settingsHeaderGap": { + "$type": "dimension", + "px": 24, + "dp": 12.0, + "source": "locked index.html:71-92, 256-263, 303-328; spec 6.1 and nav-shell measured bounds" + }, + "settingsRowTop": { + "$type": "dimension", + "px": 10, + "dp": 5.0, + "source": "locked index.html:71-92, 256-263, 303-328; spec 6.1 and nav-shell measured bounds" + }, + "settingsRowPadding": { + "$type": "dimension", + "px": 30, + "dp": 15.0, + "source": "locked index.html:71-92, 256-263, 303-328; spec 6.1 and nav-shell measured bounds" + }, + "settingsRowGap": { + "$type": "dimension", + "px": 24, + "dp": 12.0, + "source": "locked index.html:71-92, 256-263, 303-328; spec 6.1 and nav-shell measured bounds" + }, + "settingsIcon": { + "$type": "dimension", + "px": 36, + "dp": 18.0, + "source": "locked index.html:71-92, 256-263, 303-328; spec 6.1 and nav-shell measured bounds" + }, + "settingsPillHeight": { + "$type": "dimension", + "px": 40, + "dp": 20.0, + "source": "locked index.html:71-92, 256-263, 303-328; spec 6.1 and nav-shell measured bounds" + }, + "settingsPillStroke": { + "$type": "dimension", + "px": 2, + "dp": 1.0, + "source": "index.html:122; pill border 2 px inside its 40 px border-box" + }, + "settingsPillDashRatio": { + "$type": "number", + "$value": 3, + "source": "st-091 frozen browser top border: 6 px dashes at 2 px stroke width" + }, + "settingsPillDashGapRatio": { + "$type": "number", + "$value": 2, + "source": "st-091 frozen browser top border: 4 px gaps at 2 px stroke width" + }, + "settingsPillBorder": { + "$type": "color", + "$value": "#ffffff38", + "source": "index.html:122; white at 22 percent opacity, rounded to 8-bit alpha" + }, + "settingsPillFocusedBorder": { + "$type": "color", + "$value": "#0b0b1066", + "source": "index.html:328; focused pill ink at 40 percent opacity" + }, + "settingsPillPadding": { + "$type": "dimension", + "px": 16, + "dp": 8.0, + "source": "locked index.html:71-92, 256-263, 303-328; spec 6.1 and nav-shell measured bounds" + }, + "settingsPillGap": { + "$type": "dimension", + "px": 12, + "dp": 6.0, + "source": "locked index.html:71-92, 256-263, 303-328; spec 6.1 and nav-shell measured bounds" + }, + "settingsChevron": { + "$type": "dimension", + "px": 30, + "dp": 15.0, + "source": "locked index.html:71-92, 256-263, 303-328; spec 6.1 and nav-shell measured bounds" + }, + "settingsEndPadding": { + "$type": "dimension", + "px": 620, + "dp": 310.0, + "source": "locked index.html:71-92, 256-263, 303-328; spec 6.1 and nav-shell measured bounds" + }, + "panelPaddingX": { + "$type": "dimension", + "px": 30, + "dp": 15.0, + "source": "locked index.html:71-92, 256-263, 303-328; spec 6.1 and nav-shell measured bounds" + }, + "panelPaddingY": { + "$type": "dimension", + "px": 28, + "dp": 14.0, + "source": "locked index.html:71-92, 256-263, 303-328; spec 6.1 and nav-shell measured bounds" + }, + "panelGap": { + "$type": "dimension", + "px": 10, + "dp": 5.0, + "source": "locked index.html:71-92, 256-263, 303-328; spec 6.1 and nav-shell measured bounds" + }, + "panelHeadingGap": { + "$type": "dimension", + "px": 14, + "dp": 7.0, + "source": "index.html:244: receipt heading icon-to-title gap" + }, + "panelIcon": { + "$type": "dimension", + "px": 36, + "dp": 18.0, + "source": "locked index.html:71-92, 256-263, 303-328; spec 6.1 and nav-shell measured bounds" + }, + "skeletonRadius": { + "$type": "dimension", + "px": 10, + "dp": 5.0, + "source": "locked index.html:71-92, 256-263, 303-328; spec 6.1 and nav-shell measured bounds" + }, + "gearOpacity": { + "$type": "number", + "$value": 0.7, + "source": "locked index.html CSS / measured st-* bounds" + }, + "navBandOpacity": { + "$type": "number", + "$value": 0.72, + "source": "locked index.html CSS / measured st-* bounds" + }, + "navSolidStop": { + "$type": "number", + "$value": 0.84, + "source": "locked index.html CSS / measured st-* bounds" + } + }, + "library": { + "chipHeight": {"$type":"dimension","px":68,"dp":34,"source":"index.html:185"}, + "chipPadding": {"$type":"dimension","px":28,"dp":14,"source":"index.html:185"}, + "chipGap": {"$type":"dimension","px":16,"dp":8,"source":"index.html:184-185"}, + "chipTop": {"$type":"dimension","px":16,"dp":8,"source":"index.html:184"}, + "chipIcon": {"$type":"dimension","px":26,"dp":13,"source":"index.html:185"}, + "captionWidth": {"$type":"dimension","px":640,"dp":320,"source":"index.html:151"}, + "captionSeparatorOpacity": {"$type":"number","$value":0.4,"source":"index.html:1207; spec 4.4"}, + "captionFactsGap": {"$type":"dimension","px":18,"dp":9,"source":"index.html:154"}, + "badgeIcon": {"$type":"dimension","px":28,"dp":14,"source":"index.html:142"}, + "plateTop": {"$type":"dimension","px":14,"dp":7,"source":"index.html:162"}, + "plateSide": {"$type":"dimension","px":16,"dp":8,"source":"index.html:162"}, + "plateBottom": {"$type":"dimension","px":46,"dp":23,"source":"index.html:162"}, + "plateInlineDescent": {"$type":"dimension","px":6.6,"dp":3.3,"source":"index.html:156,162 inline-flex baseline strut; proto-104 rplate 100.2px minus 14+33.6+46"}, + "plateFloor": {"$type":"typography","px":24,"sp":12,"weight":700,"$value":{"fontWeight":700},"source":"index.html:802"}, + "plateStep": {"$type":"number","$value":0.25,"source":"spec 4.8"}, + "plateGapEm": {"$type":"number","$value":0.64,"source":"index.html:164"}, + "markGapEm": {"$type":"number","$value":0.29,"source":"index.html:165"}, + "wordmarkRatio": {"$type":"number","$value":1.8,"source":"index.html:160"}, + "plateOpacity": {"$type":"number","$value":0.9,"source":"index.html:162"}, + "plateMidOpacity": {"$type":"number","$value":0.72,"source":"index.html:162"}, + "plateMidStop": {"$type":"number","$value":0.52,"source":"index.html:162"}, + "railWidth": {"$type":"dimension","px":52,"dp":26,"source":"index.html:204"}, + "railLetterHeight": {"$type":"dimension","px":30,"dp":15,"source":"index.html:205"}, + "railFocusHeight": {"$type":"dimension","px":44,"dp":22,"source":"index.html:208"}, + "railLetter": {"$type":"typography","px":24,"sp":12,"weight":700,"$value":{"fontWeight":700},"source":"index.html:205; prototype wins over spec 4.3 caption weight"}, + "railFocusedLetter": {"$type":"typography","px":28,"sp":14,"weight":700,"$value":{"fontWeight":700},"source":"index.html:208; prototype wins over spec 4.3 caption size"}, + "panelPaddingX": {"$type":"dimension","px":40,"dp":20,"source":"index.html:194"}, + "panelPaddingY": {"$type":"dimension","px":34,"dp":17,"source":"index.html:194"}, + "panelTextGap": {"$type":"dimension","px":24,"dp":12,"source":"index.html:198"}, + "panelTitleGap": {"$type":"dimension","px":8,"dp":4,"source":"index.html:195"}, + "panelIconGap": {"$type":"dimension","px":14,"dp":7,"source":"index.html:195"}, + "panelTop": {"$type":"dimension","px":20,"dp":10,"source":"index.html:194"}, + "borderWidth": {"$type":"dimension","px":2,"dp":1,"source":"index.html:188,194,299"}, + "chipContentGap": {"$type":"dimension","px":12,"dp":6,"source":"index.html:185"}, + "chipLabelOpacity": {"$type":"number","$value":0.7,"source":"index.html:190"}, + "tailIcon": {"$type":"dimension","px":44,"dp":22,"source":"index.html:300"}, + "tailPadding": {"$type":"dimension","px":20,"dp":10,"source":"index.html:299"}, + "tailGap": {"$type":"dimension","px":10,"dp":5,"source":"index.html:299"}, + "badgeRing": {"$type":"dimension","px":3,"dp":1.5,"source":"index.html:144"}, + "badgeIcon": {"$type":"dimension","px":28,"dp":14,"source":"index.html:142"}, + "seeAllGap": {"$type":"dimension","px":8,"dp":4,"source":"index.html:146"}, + "tailDescription": {"$type":"typography","px":24,"sp":12,"weight":500,"$value":{"fontWeight":500},"source":"index.html:301"}, + "headerSubtitle": {"$type":"typography","px":30,"sp":15,"weight":400,"$value":{"fontWeight":400},"source":"index.html:201"}, + "imageReads": {"$type":"number","$value":4,"source":"spec 4.9, tokens.json image.concurrentReads"}, + "unknownCriticOpacity": {"$type":"number","$value":0.55,"source":"spec 4.7, index.html:161"}, + "fallbackPadding": {"$type":"dimension","px":22,"dp":11,"source":"index.html:130"}, + "fallbackIcon": {"$type":"dimension","px":44,"dp":22,"source":"index.html:130"}, + "fallbackHueMultiplier": {"$type":"number","$value":31,"source":"index.html:705"}, + "fallbackSaturationTop": {"$type":"number","$value":0.22,"source":"index.html:130"}, + "fallbackLightnessTop": {"$type":"number","$value":0.22,"source":"index.html:130"}, + "fallbackSaturationBottom": {"$type":"number","$value":0.26,"source":"index.html:130"}, + "fallbackLightnessBottom": {"$type":"number","$value":0.1,"source":"index.html:130"}, + "fallbackIconOpacity": {"$type":"number","$value":0.45,"source":"index.html:132"} + }, + "lift": { + "cardBlur": {"$type":"dimension","px":50,"dp":25,"source":"index.html:134; spec 4.5"}, + "cardY": {"$type":"dimension","px":18,"dp":9,"source":"index.html:134"}, + "cardOpacity": {"$type":"number","$value":0.65,"source":"index.html:134"}, + "buttonBlur": {"$type":"dimension","px":40,"dp":20,"source":"index.html:110; spec 4.5"}, + "buttonY": {"$type":"dimension","px":12,"dp":6,"source":"spec 4.5"}, + "buttonOpacity": {"$type":"number","$value":0.5,"source":"spec 4.5"}, + "heroBlur": {"$type":"dimension","px":80,"dp":40,"source":"index.html:97"}, + "heroY": {"$type":"dimension","px":30,"dp":15,"source":"index.html:97"}, + "heroOpacity": {"$type":"number","$value":0.6,"source":"index.html:97"}, + "sheetBlur": {"$type":"dimension","px":80,"dp":40,"source":"index.html:227"}, + "sheetX": {"$type":"dimension","px":-30,"dp":-15,"source":"index.html:227"}, + "sheetOpacity": {"$type":"number","$value":0.5,"source":"index.html:227"} + } +} diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-all-hands-on-deck-class-1-a-2021-s5e1-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-all-hands-on-deck-class-1-a-2021-s5e1-backdrop.jpg new file mode 100644 index 00000000..f5b2f94c Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-all-hands-on-deck-class-1-a-2021-s5e1-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-all-hands-on-deck-class-1-a-2021-s5e1-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-all-hands-on-deck-class-1-a-2021-s5e1-poster.jpg new file mode 100644 index 00000000..cf571b93 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-all-hands-on-deck-class-1-a-2021-s5e1-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-announcement-2022-s1e7-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-announcement-2022-s1e7-backdrop.jpg new file mode 100644 index 00000000..a874a0c0 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-announcement-2022-s1e7-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-announcement-2022-s1e7-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-announcement-2022-s1e7-poster.jpg new file mode 100644 index 00000000..df5dc498 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-announcement-2022-s1e7-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-episode-1-2025-s1e1-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-episode-1-2025-s1e1-backdrop.jpg new file mode 100644 index 00000000..f2519b04 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-episode-1-2025-s1e1-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-episode-1-2025-s1e1-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-episode-1-2025-s1e1-poster.jpg new file mode 100644 index 00000000..77febd79 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-episode-1-2025-s1e1-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-episode-2-2016-s1e2-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-episode-2-2016-s1e2-backdrop.jpg new file mode 100644 index 00000000..3f8bdeec Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-episode-2-2016-s1e2-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-episode-2-2016-s1e2-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-episode-2-2016-s1e2-poster.jpg new file mode 100644 index 00000000..d29448bb Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-episode-2-2016-s1e2-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-erickerhead-2026-s9e6-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-erickerhead-2026-s9e6-backdrop.jpg new file mode 100644 index 00000000..1c4c0ffc Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-erickerhead-2026-s9e6-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-erickerhead-2026-s9e6-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-erickerhead-2026-s9e6-poster.jpg new file mode 100644 index 00000000..b95c4890 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-erickerhead-2026-s9e6-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-girls-interrupted-2007-s1e7-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-girls-interrupted-2007-s1e7-backdrop.jpg new file mode 100644 index 00000000..ffff979b Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-girls-interrupted-2007-s1e7-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-girls-interrupted-2007-s1e7-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-girls-interrupted-2007-s1e7-poster.jpg new file mode 100644 index 00000000..38428e76 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-girls-interrupted-2007-s1e7-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-i-heart-ny-2002-s4e18-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-i-heart-ny-2002-s4e18-backdrop.jpg new file mode 100644 index 00000000..57beacc1 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-i-heart-ny-2002-s4e18-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-i-heart-ny-2002-s4e18-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-i-heart-ny-2002-s4e18-poster.jpg new file mode 100644 index 00000000..e546cc6d Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-i-heart-ny-2002-s4e18-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-new-day-2021-s1e2-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-new-day-2021-s1e2-backdrop.jpg new file mode 100644 index 00000000..1f747323 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-new-day-2021-s1e2-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-new-day-2021-s1e2-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-new-day-2021-s1e2-poster.jpg new file mode 100644 index 00000000..2f23d1fa Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-new-day-2021-s1e2-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-no-honeymoon-2020-s1e8-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-no-honeymoon-2020-s1e8-backdrop.jpg new file mode 100644 index 00000000..9d95ba77 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-no-honeymoon-2020-s1e8-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-no-honeymoon-2020-s1e8-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-no-honeymoon-2020-s1e8-poster.jpg new file mode 100644 index 00000000..49c61208 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-no-honeymoon-2020-s1e8-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-notapusy-2005-s3e4-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-notapusy-2005-s3e4-backdrop.jpg new file mode 100644 index 00000000..ecb7e8cd Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-notapusy-2005-s3e4-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-notapusy-2005-s3e4-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-notapusy-2005-s3e4-poster.jpg new file mode 100644 index 00000000..02b0dd43 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-notapusy-2005-s3e4-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-one-of-us-2024-s1e7-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-one-of-us-2024-s1e7-backdrop.jpg new file mode 100644 index 00000000..66bb4d00 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-one-of-us-2024-s1e7-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-one-of-us-2024-s1e7-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-one-of-us-2024-s1e7-poster.jpg new file mode 100644 index 00000000..00a07ca7 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-one-of-us-2024-s1e7-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-remembrance-day-2026-s2e1-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-remembrance-day-2026-s2e1-backdrop.jpg new file mode 100644 index 00000000..23a242da Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-remembrance-day-2026-s2e1-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-remembrance-day-2026-s2e1-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-remembrance-day-2026-s2e1-poster.jpg new file mode 100644 index 00000000..930943b0 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-remembrance-day-2026-s2e1-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-sex-and-the-country-2001-s4e9-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-sex-and-the-country-2001-s4e9-backdrop.jpg new file mode 100644 index 00000000..57beacc1 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-sex-and-the-country-2001-s4e9-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-sex-and-the-country-2001-s4e9-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-sex-and-the-country-2001-s4e9-poster.jpg new file mode 100644 index 00000000..e546cc6d Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-sex-and-the-country-2001-s4e9-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-south-american-biker-gangs-2026-s29e1-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-south-american-biker-gangs-2026-s29e1-backdrop.jpg new file mode 100644 index 00000000..cd0aec39 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-south-american-biker-gangs-2026-s29e1-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-south-american-biker-gangs-2026-s29e1-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-south-american-biker-gangs-2026-s29e1-poster.jpg new file mode 100644 index 00000000..d8568d54 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-south-american-biker-gangs-2026-s29e1-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-the-breakup-part-2-2001-s1e17-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-the-breakup-part-2-2001-s1e17-backdrop.jpg new file mode 100644 index 00000000..b42ba953 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-the-breakup-part-2-2001-s1e17-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-the-breakup-part-2-2001-s1e17-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-the-breakup-part-2-2001-s1e17-poster.jpg new file mode 100644 index 00000000..23b668cb Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-the-breakup-part-2-2001-s1e17-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-the-man-who-would-be-vogue-2018-s2e1-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-the-man-who-would-be-vogue-2018-s2e1-backdrop.jpg new file mode 100644 index 00000000..84944d39 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-the-man-who-would-be-vogue-2018-s2e1-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-the-man-who-would-be-vogue-2018-s2e1-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-the-man-who-would-be-vogue-2018-s2e1-poster.jpg new file mode 100644 index 00000000..4086bf17 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-the-man-who-would-be-vogue-2018-s2e1-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-the-uncomfortability-2010-s1e2-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-the-uncomfortability-2010-s1e2-backdrop.jpg new file mode 100644 index 00000000..bc22e11a Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-the-uncomfortability-2010-s1e2-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-the-uncomfortability-2010-s1e2-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-the-uncomfortability-2010-s1e2-poster.jpg new file mode 100644 index 00000000..ae305043 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-the-uncomfortability-2010-s1e2-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-three-monsters-1992-s1e6-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-three-monsters-1992-s1e6-backdrop.jpg new file mode 100644 index 00000000..ba65ca2d Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-three-monsters-1992-s1e6-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-three-monsters-1992-s1e6-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-three-monsters-1992-s1e6-poster.jpg new file mode 100644 index 00000000..f5843766 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-three-monsters-1992-s1e6-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-tomorrow-2024-s3e1-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-tomorrow-2024-s3e1-backdrop.jpg new file mode 100644 index 00000000..9c9cca57 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-tomorrow-2024-s3e1-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-tomorrow-2024-s3e1-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-tomorrow-2024-s3e1-poster.jpg new file mode 100644 index 00000000..bbf0ab28 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-tomorrow-2024-s3e1-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-what-more-do-i-need-2008-s5e7-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-what-more-do-i-need-2008-s5e7-backdrop.jpg new file mode 100644 index 00000000..40ec3001 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-what-more-do-i-need-2008-s5e7-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-what-more-do-i-need-2008-s5e7-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-what-more-do-i-need-2008-s5e7-poster.jpg new file mode 100644 index 00000000..13f0f7b3 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/episode-what-more-do-i-need-2008-s5e7-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-101-dalmatians-ii-patch-s-london-adventure-2003-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-101-dalmatians-ii-patch-s-london-adventure-2003-backdrop.jpg new file mode 100644 index 00000000..f0d6f752 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-101-dalmatians-ii-patch-s-london-adventure-2003-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-101-dalmatians-ii-patch-s-london-adventure-2003-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-101-dalmatians-ii-patch-s-london-adventure-2003-poster.jpg new file mode 100644 index 00000000..b9b72894 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-101-dalmatians-ii-patch-s-london-adventure-2003-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-12-years-a-slave-2013-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-12-years-a-slave-2013-backdrop.jpg new file mode 100644 index 00000000..d93357e5 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-12-years-a-slave-2013-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-12-years-a-slave-2013-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-12-years-a-slave-2013-poster.jpg new file mode 100644 index 00000000..ff1f55e6 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-12-years-a-slave-2013-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-a-bronx-tale-1993-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-a-bronx-tale-1993-backdrop.jpg new file mode 100644 index 00000000..15c11ff7 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-a-bronx-tale-1993-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-a-bronx-tale-1993-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-a-bronx-tale-1993-poster.jpg new file mode 100644 index 00000000..f7444271 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-a-bronx-tale-1993-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-a-silent-voice-the-movie-2016-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-a-silent-voice-the-movie-2016-backdrop.jpg new file mode 100644 index 00000000..b386b136 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-a-silent-voice-the-movie-2016-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-a-silent-voice-the-movie-2016-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-a-silent-voice-the-movie-2016-poster.jpg new file mode 100644 index 00000000..580b22f4 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-a-silent-voice-the-movie-2016-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-absolution-2024-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-absolution-2024-backdrop.jpg new file mode 100644 index 00000000..eb28037c Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-absolution-2024-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-absolution-2024-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-absolution-2024-poster.jpg new file mode 100644 index 00000000..3ce49112 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-absolution-2024-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-across-the-hall-2009-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-across-the-hall-2009-backdrop.jpg new file mode 100644 index 00000000..6c1ee8ac Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-across-the-hall-2009-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-across-the-hall-2009-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-across-the-hall-2009-poster.jpg new file mode 100644 index 00000000..52362b4e Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-across-the-hall-2009-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-addicted-2014-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-addicted-2014-backdrop.jpg new file mode 100644 index 00000000..5c016976 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-addicted-2014-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-addicted-2014-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-addicted-2014-poster.jpg new file mode 100644 index 00000000..e9a03c14 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-addicted-2014-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-adulterers-2016-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-adulterers-2016-backdrop.jpg new file mode 100644 index 00000000..331391ed Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-adulterers-2016-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-adulterers-2016-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-adulterers-2016-poster.jpg new file mode 100644 index 00000000..8b65745b Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-adulterers-2016-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-all-the-money-in-the-world-2017-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-all-the-money-in-the-world-2017-backdrop.jpg new file mode 100644 index 00000000..ac4b828a Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-all-the-money-in-the-world-2017-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-all-the-money-in-the-world-2017-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-all-the-money-in-the-world-2017-poster.jpg new file mode 100644 index 00000000..8beb2f7f Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-all-the-money-in-the-world-2017-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-alone-with-her-2006-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-alone-with-her-2006-backdrop.jpg new file mode 100644 index 00000000..ddf8f1dc Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-alone-with-her-2006-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-alone-with-her-2006-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-alone-with-her-2006-poster.jpg new file mode 100644 index 00000000..7ce6fa96 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-alone-with-her-2006-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-american-gangster-2007-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-american-gangster-2007-backdrop.jpg new file mode 100644 index 00000000..cb5c5de7 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-american-gangster-2007-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-american-gangster-2007-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-american-gangster-2007-poster.jpg new file mode 100644 index 00000000..0f41d299 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-american-gangster-2007-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-annie-hall-1977-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-annie-hall-1977-backdrop.jpg new file mode 100644 index 00000000..16d0b27d Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-annie-hall-1977-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-annie-hall-1977-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-annie-hall-1977-poster.jpg new file mode 100644 index 00000000..9023a691 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-annie-hall-1977-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-ant-man-and-the-wasp-quantumania-2023-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-ant-man-and-the-wasp-quantumania-2023-backdrop.jpg new file mode 100644 index 00000000..2a99846d Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-ant-man-and-the-wasp-quantumania-2023-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-ant-man-and-the-wasp-quantumania-2023-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-ant-man-and-the-wasp-quantumania-2023-poster.jpg new file mode 100644 index 00000000..030addf0 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-ant-man-and-the-wasp-quantumania-2023-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-apocalypse-now-1979-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-apocalypse-now-1979-backdrop.jpg new file mode 100644 index 00000000..93292da3 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-apocalypse-now-1979-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-apocalypse-now-1979-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-apocalypse-now-1979-poster.jpg new file mode 100644 index 00000000..09cd6aa8 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-apocalypse-now-1979-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-appleseed-alpha-2014-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-appleseed-alpha-2014-backdrop.jpg new file mode 100644 index 00000000..82579b86 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-appleseed-alpha-2014-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-appleseed-alpha-2014-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-appleseed-alpha-2014-poster.jpg new file mode 100644 index 00000000..62bd0afa Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-appleseed-alpha-2014-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-aquaman-and-the-lost-kingdom-2023-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-aquaman-and-the-lost-kingdom-2023-backdrop.jpg new file mode 100644 index 00000000..6693cb6d Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-aquaman-and-the-lost-kingdom-2023-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-aquaman-and-the-lost-kingdom-2023-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-aquaman-and-the-lost-kingdom-2023-poster.jpg new file mode 100644 index 00000000..4550bdaa Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-aquaman-and-the-lost-kingdom-2023-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-arctic-dogs-2019-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-arctic-dogs-2019-backdrop.jpg new file mode 100644 index 00000000..1794c99d Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-arctic-dogs-2019-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-arctic-dogs-2019-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-arctic-dogs-2019-poster.jpg new file mode 100644 index 00000000..07552443 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-arctic-dogs-2019-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-arrival-2016-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-arrival-2016-backdrop.jpg new file mode 100644 index 00000000..605724e7 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-arrival-2016-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-arrival-2016-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-arrival-2016-poster.jpg new file mode 100644 index 00000000..fe224a15 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-arrival-2016-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-avatar-aang-the-last-airbender-2026-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-avatar-aang-the-last-airbender-2026-backdrop.jpg new file mode 100644 index 00000000..d3b12fe0 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-avatar-aang-the-last-airbender-2026-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-avatar-aang-the-last-airbender-2026-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-avatar-aang-the-last-airbender-2026-poster.jpg new file mode 100644 index 00000000..f57f1052 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-avatar-aang-the-last-airbender-2026-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-avengers-age-of-ultron-2015-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-avengers-age-of-ultron-2015-backdrop.jpg new file mode 100644 index 00000000..f739d620 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-avengers-age-of-ultron-2015-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-avengers-age-of-ultron-2015-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-avengers-age-of-ultron-2015-poster.jpg new file mode 100644 index 00000000..300840ff Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-avengers-age-of-ultron-2015-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-avengers-confidential-black-widow-punisher-2014-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-avengers-confidential-black-widow-punisher-2014-backdrop.jpg new file mode 100644 index 00000000..8163931a Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-avengers-confidential-black-widow-punisher-2014-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-avengers-confidential-black-widow-punisher-2014-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-avengers-confidential-black-widow-punisher-2014-poster.jpg new file mode 100644 index 00000000..b096fff2 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-avengers-confidential-black-widow-punisher-2014-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-avengers-infinity-war-2018-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-avengers-infinity-war-2018-backdrop.jpg new file mode 100644 index 00000000..90dc4672 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-avengers-infinity-war-2018-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-avengers-infinity-war-2018-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-avengers-infinity-war-2018-poster.jpg new file mode 100644 index 00000000..57df9298 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-avengers-infinity-war-2018-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-awake-2007-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-awake-2007-backdrop.jpg new file mode 100644 index 00000000..6ddd7f59 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-awake-2007-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-awake-2007-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-awake-2007-poster.jpg new file mode 100644 index 00000000..32595897 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-awake-2007-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-batman-ninja-2018-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-batman-ninja-2018-backdrop.jpg new file mode 100644 index 00000000..9b538d9f Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-batman-ninja-2018-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-batman-ninja-2018-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-batman-ninja-2018-poster.jpg new file mode 100644 index 00000000..7f59127b Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-batman-ninja-2018-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-batman-the-dark-knight-returns-part-1-2012-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-batman-the-dark-knight-returns-part-1-2012-backdrop.jpg new file mode 100644 index 00000000..9d385801 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-batman-the-dark-knight-returns-part-1-2012-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-batman-the-dark-knight-returns-part-1-2012-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-batman-the-dark-knight-returns-part-1-2012-poster.jpg new file mode 100644 index 00000000..ce5623fe Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-batman-the-dark-knight-returns-part-1-2012-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-batman-v-superman-dawn-of-justice-2016-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-batman-v-superman-dawn-of-justice-2016-backdrop.jpg new file mode 100644 index 00000000..b4fa63b9 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-batman-v-superman-dawn-of-justice-2016-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-batman-v-superman-dawn-of-justice-2016-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-batman-v-superman-dawn-of-justice-2016-poster.jpg new file mode 100644 index 00000000..f8115170 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-batman-v-superman-dawn-of-justice-2016-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-black-adam-2022-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-black-adam-2022-backdrop.jpg new file mode 100644 index 00000000..3232fb22 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-black-adam-2022-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-black-adam-2022-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-black-adam-2022-poster.jpg new file mode 100644 index 00000000..dde008b5 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-black-adam-2022-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-black-bear-2020-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-black-bear-2020-backdrop.jpg new file mode 100644 index 00000000..4b0b262f Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-black-bear-2020-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-black-bear-2020-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-black-bear-2020-poster.jpg new file mode 100644 index 00000000..61c8860f Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-black-bear-2020-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-black-panther-2018-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-black-panther-2018-backdrop.jpg new file mode 100644 index 00000000..f0b8de8a Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-black-panther-2018-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-black-panther-2018-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-black-panther-2018-poster.jpg new file mode 100644 index 00000000..6fdaa3d2 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-black-panther-2018-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-black-panther-wakanda-forever-2022-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-black-panther-wakanda-forever-2022-backdrop.jpg new file mode 100644 index 00000000..ac7ad532 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-black-panther-wakanda-forever-2022-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-black-panther-wakanda-forever-2022-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-black-panther-wakanda-forever-2022-poster.jpg new file mode 100644 index 00000000..d0219a75 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-black-panther-wakanda-forever-2022-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-blame-2017-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-blame-2017-backdrop.jpg new file mode 100644 index 00000000..f39cf5ce Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-blame-2017-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-blame-2017-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-blame-2017-poster.jpg new file mode 100644 index 00000000..8d50255f Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-blame-2017-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-bleach-the-movie-fade-to-black-2008-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-bleach-the-movie-fade-to-black-2008-backdrop.jpg new file mode 100644 index 00000000..f426d0ce Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-bleach-the-movie-fade-to-black-2008-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-bleach-the-movie-fade-to-black-2008-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-bleach-the-movie-fade-to-black-2008-poster.jpg new file mode 100644 index 00000000..d3619fbd Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-bleach-the-movie-fade-to-black-2008-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-bohemian-rhapsody-2018-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-bohemian-rhapsody-2018-backdrop.jpg new file mode 100644 index 00000000..b6b5a7cd Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-bohemian-rhapsody-2018-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-bohemian-rhapsody-2018-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-bohemian-rhapsody-2018-poster.jpg new file mode 100644 index 00000000..20d2f9ee Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-bohemian-rhapsody-2018-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-braveheart-1995-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-braveheart-1995-backdrop.jpg new file mode 100644 index 00000000..c1c84c59 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-braveheart-1995-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-braveheart-1995-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-braveheart-1995-poster.jpg new file mode 100644 index 00000000..32fd8d4d Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-braveheart-1995-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-butterfly-on-a-wheel-2007-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-butterfly-on-a-wheel-2007-backdrop.jpg new file mode 100644 index 00000000..e49fe1d5 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-butterfly-on-a-wheel-2007-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-butterfly-on-a-wheel-2007-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-butterfly-on-a-wheel-2007-poster.jpg new file mode 100644 index 00000000..b54cc5c7 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-butterfly-on-a-wheel-2007-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-by-any-means-2026-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-by-any-means-2026-backdrop.jpg new file mode 100644 index 00000000..e536359f Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-by-any-means-2026-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-by-any-means-2026-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-by-any-means-2026-poster.jpg new file mode 100644 index 00000000..92fd601f Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-by-any-means-2026-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-captain-america-civil-war-2016-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-captain-america-civil-war-2016-backdrop.jpg new file mode 100644 index 00000000..5700c4e7 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-captain-america-civil-war-2016-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-captain-america-civil-war-2016-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-captain-america-civil-war-2016-poster.jpg new file mode 100644 index 00000000..426142ef Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-captain-america-civil-war-2016-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-captain-america-the-first-avenger-2011-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-captain-america-the-first-avenger-2011-backdrop.jpg new file mode 100644 index 00000000..411ceebe Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-captain-america-the-first-avenger-2011-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-captain-america-the-first-avenger-2011-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-captain-america-the-first-avenger-2011-poster.jpg new file mode 100644 index 00000000..bba96574 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-captain-america-the-first-avenger-2011-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-captain-america-the-winter-soldier-2014-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-captain-america-the-winter-soldier-2014-backdrop.jpg new file mode 100644 index 00000000..5661fcff Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-captain-america-the-winter-soldier-2014-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-captain-america-the-winter-soldier-2014-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-captain-america-the-winter-soldier-2014-poster.jpg new file mode 100644 index 00000000..c2dc5612 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-captain-america-the-winter-soldier-2014-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-careful-what-you-wish-for-2015-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-careful-what-you-wish-for-2015-backdrop.jpg new file mode 100644 index 00000000..988e20d5 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-careful-what-you-wish-for-2015-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-careful-what-you-wish-for-2015-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-careful-what-you-wish-for-2015-poster.jpg new file mode 100644 index 00000000..b58ce600 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-careful-what-you-wish-for-2015-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-castle-in-the-sky-1986-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-castle-in-the-sky-1986-backdrop.jpg new file mode 100644 index 00000000..f785c549 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-castle-in-the-sky-1986-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-castle-in-the-sky-1986-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-castle-in-the-sky-1986-poster.jpg new file mode 100644 index 00000000..a6a99fee Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-castle-in-the-sky-1986-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-chicago-2002-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-chicago-2002-backdrop.jpg new file mode 100644 index 00000000..6b3d02a3 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-chicago-2002-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-chicago-2002-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-chicago-2002-poster.jpg new file mode 100644 index 00000000..1def9414 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-chicago-2002-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-citizen-kane-1941-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-citizen-kane-1941-backdrop.jpg new file mode 100644 index 00000000..d41a10ef Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-citizen-kane-1941-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-citizen-kane-1941-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-citizen-kane-1941-poster.jpg new file mode 100644 index 00000000..f26414a7 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-citizen-kane-1941-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-coherence-2014-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-coherence-2014-backdrop.jpg new file mode 100644 index 00000000..37da64f9 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-coherence-2014-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-coherence-2014-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-coherence-2014-poster.jpg new file mode 100644 index 00000000..f3601b9b Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-coherence-2014-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-conclave-2024-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-conclave-2024-backdrop.jpg new file mode 100644 index 00000000..db0a7fcd Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-conclave-2024-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-conclave-2024-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-conclave-2024-poster.jpg new file mode 100644 index 00000000..c6aecefa Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-conclave-2024-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-crime-of-passion-1956-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-crime-of-passion-1956-backdrop.jpg new file mode 100644 index 00000000..6c70a452 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-crime-of-passion-1956-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-crime-of-passion-1956-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-crime-of-passion-1956-poster.jpg new file mode 100644 index 00000000..4acfa871 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-crime-of-passion-1956-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-deep-water-2022-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-deep-water-2022-backdrop.jpg new file mode 100644 index 00000000..bec98992 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-deep-water-2022-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-deep-water-2022-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-deep-water-2022-poster.jpg new file mode 100644 index 00000000..018d4f4b Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-deep-water-2022-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-derailed-2005-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-derailed-2005-backdrop.jpg new file mode 100644 index 00000000..e958449b Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-derailed-2005-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-derailed-2005-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-derailed-2005-poster.jpg new file mode 100644 index 00000000..d93f3124 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-derailed-2005-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-die-my-love-2025-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-die-my-love-2025-backdrop.jpg new file mode 100644 index 00000000..754e713f Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-die-my-love-2025-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-die-my-love-2025-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-die-my-love-2025-poster.jpg new file mode 100644 index 00000000..f6eca818 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-die-my-love-2025-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-dream-house-2011-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-dream-house-2011-backdrop.jpg new file mode 100644 index 00000000..29ecc103 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-dream-house-2011-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-dream-house-2011-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-dream-house-2011-poster.jpg new file mode 100644 index 00000000..d3444637 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-dream-house-2011-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-dream-lover-1994-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-dream-lover-1994-backdrop.jpg new file mode 100644 index 00000000..7f5a31ac Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-dream-lover-1994-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-dream-lover-1994-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-dream-lover-1994-poster.jpg new file mode 100644 index 00000000..3b563cf9 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-dream-lover-1994-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-drop-2025-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-drop-2025-backdrop.jpg new file mode 100644 index 00000000..ee642530 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-drop-2025-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-drop-2025-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-drop-2025-poster.jpg new file mode 100644 index 00000000..4cf7d66b Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-drop-2025-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-eastern-promises-2007-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-eastern-promises-2007-backdrop.jpg new file mode 100644 index 00000000..9096a0fa Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-eastern-promises-2007-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-eastern-promises-2007-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-eastern-promises-2007-poster.jpg new file mode 100644 index 00000000..01a26f3b Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-eastern-promises-2007-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-easy-a-2010-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-easy-a-2010-backdrop.jpg new file mode 100644 index 00000000..c27fa57b Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-easy-a-2010-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-easy-a-2010-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-easy-a-2010-poster.jpg new file mode 100644 index 00000000..45e13a32 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-easy-a-2010-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-el-camino-a-breaking-bad-movie-2019-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-el-camino-a-breaking-bad-movie-2019-backdrop.jpg new file mode 100644 index 00000000..8edc02a6 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-el-camino-a-breaking-bad-movie-2019-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-el-camino-a-breaking-bad-movie-2019-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-el-camino-a-breaking-bad-movie-2019-poster.jpg new file mode 100644 index 00000000..7a62df45 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-el-camino-a-breaking-bad-movie-2019-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-emancipation-2022-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-emancipation-2022-backdrop.jpg new file mode 100644 index 00000000..ac0777c7 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-emancipation-2022-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-emancipation-2022-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-emancipation-2022-poster.jpg new file mode 100644 index 00000000..c1bee971 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-emancipation-2022-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-faces-1968-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-faces-1968-backdrop.jpg new file mode 100644 index 00000000..60273dd9 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-faces-1968-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-faces-1968-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-faces-1968-poster.jpg new file mode 100644 index 00000000..43f996bd Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-faces-1968-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-fatale-2020-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-fatale-2020-backdrop.jpg new file mode 100644 index 00000000..b13c33c6 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-fatale-2020-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-fatale-2020-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-fatale-2020-poster.jpg new file mode 100644 index 00000000..dda9d622 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-fatale-2020-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-fighting-with-my-family-2019-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-fighting-with-my-family-2019-backdrop.jpg new file mode 100644 index 00000000..46835996 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-fighting-with-my-family-2019-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-fighting-with-my-family-2019-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-fighting-with-my-family-2019-poster.jpg new file mode 100644 index 00000000..169c466d Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-fighting-with-my-family-2019-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-force-of-nature-the-dry-2-2024-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-force-of-nature-the-dry-2-2024-backdrop.jpg new file mode 100644 index 00000000..3735ee63 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-force-of-nature-the-dry-2-2024-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-force-of-nature-the-dry-2-2024-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-force-of-nature-the-dry-2-2024-poster.jpg new file mode 100644 index 00000000..93ba0d71 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-force-of-nature-the-dry-2-2024-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-free-state-of-jones-2016-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-free-state-of-jones-2016-backdrop.jpg new file mode 100644 index 00000000..a7e5ddff Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-free-state-of-jones-2016-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-free-state-of-jones-2016-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-free-state-of-jones-2016-poster.jpg new file mode 100644 index 00000000..e69af7c0 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-free-state-of-jones-2016-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-from-up-on-poppy-hill-2011-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-from-up-on-poppy-hill-2011-backdrop.jpg new file mode 100644 index 00000000..32a28bd7 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-from-up-on-poppy-hill-2011-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-from-up-on-poppy-hill-2011-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-from-up-on-poppy-hill-2011-poster.jpg new file mode 100644 index 00000000..264076e2 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-from-up-on-poppy-hill-2011-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-ghost-in-the-shell-1995-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-ghost-in-the-shell-1995-backdrop.jpg new file mode 100644 index 00000000..716b8a87 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-ghost-in-the-shell-1995-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-ghost-in-the-shell-1995-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-ghost-in-the-shell-1995-poster.jpg new file mode 100644 index 00000000..58d221ba Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-ghost-in-the-shell-1995-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-ghost-in-the-shell-2-innocence-2004-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-ghost-in-the-shell-2-innocence-2004-backdrop.jpg new file mode 100644 index 00000000..4a9931ed Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-ghost-in-the-shell-2-innocence-2004-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-ghost-in-the-shell-2-innocence-2004-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-ghost-in-the-shell-2-innocence-2004-poster.jpg new file mode 100644 index 00000000..ae262147 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-ghost-in-the-shell-2-innocence-2004-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-gosford-park-2001-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-gosford-park-2001-backdrop.jpg new file mode 100644 index 00000000..42c4cea6 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-gosford-park-2001-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-gosford-park-2001-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-gosford-park-2001-poster.jpg new file mode 100644 index 00000000..6a6aa651 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-gosford-park-2001-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-grave-of-the-fireflies-1988-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-grave-of-the-fireflies-1988-backdrop.jpg new file mode 100644 index 00000000..0e1add06 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-grave-of-the-fireflies-1988-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-grave-of-the-fireflies-1988-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-grave-of-the-fireflies-1988-poster.jpg new file mode 100644 index 00000000..1b71996a Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-grave-of-the-fireflies-1988-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-howl-s-moving-castle-2004-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-howl-s-moving-castle-2004-backdrop.jpg new file mode 100644 index 00000000..0aeef2ba Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-howl-s-moving-castle-2004-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-howl-s-moving-castle-2004-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-howl-s-moving-castle-2004-poster.jpg new file mode 100644 index 00000000..042a6c80 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-howl-s-moving-castle-2004-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-in-the-heights-2021-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-in-the-heights-2021-backdrop.jpg new file mode 100644 index 00000000..7cd4ee24 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-in-the-heights-2021-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-in-the-heights-2021-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-in-the-heights-2021-poster.jpg new file mode 100644 index 00000000..e05bfdb0 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-in-the-heights-2021-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-jennifer-s-body-2009-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-jennifer-s-body-2009-backdrop.jpg new file mode 100644 index 00000000..032771a0 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-jennifer-s-body-2009-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-jennifer-s-body-2009-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-jennifer-s-body-2009-poster.jpg new file mode 100644 index 00000000..41cc1eb5 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-jennifer-s-body-2009-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-kiki-s-delivery-service-1989-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-kiki-s-delivery-service-1989-backdrop.jpg new file mode 100644 index 00000000..2a108f0c Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-kiki-s-delivery-service-1989-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-kiki-s-delivery-service-1989-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-kiki-s-delivery-service-1989-poster.jpg new file mode 100644 index 00000000..80a59b1e Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-kiki-s-delivery-service-1989-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-lemony-snicket-s-a-series-of-unfortunate-events-2004-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-lemony-snicket-s-a-series-of-unfortunate-events-2004-backdrop.jpg new file mode 100644 index 00000000..38203b77 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-lemony-snicket-s-a-series-of-unfortunate-events-2004-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-lemony-snicket-s-a-series-of-unfortunate-events-2004-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-lemony-snicket-s-a-series-of-unfortunate-events-2004-poster.jpg new file mode 100644 index 00000000..4c78fee9 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-lemony-snicket-s-a-series-of-unfortunate-events-2004-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-locke-2014-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-locke-2014-backdrop.jpg new file mode 100644 index 00000000..a24e64ab Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-locke-2014-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-locke-2014-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-locke-2014-poster.jpg new file mode 100644 index 00000000..94ebe97d Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-locke-2014-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-look-who-s-back-2015-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-look-who-s-back-2015-backdrop.jpg new file mode 100644 index 00000000..a064686f Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-look-who-s-back-2015-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-look-who-s-back-2015-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-look-who-s-back-2015-poster.jpg new file mode 100644 index 00000000..423043cf Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-look-who-s-back-2015-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-memories-1995-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-memories-1995-backdrop.jpg new file mode 100644 index 00000000..2fcaeaad Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-memories-1995-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-memories-1995-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-memories-1995-poster.jpg new file mode 100644 index 00000000..f3725b42 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-memories-1995-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-mercy-2026-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-mercy-2026-backdrop.jpg new file mode 100644 index 00000000..45591cc8 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-mercy-2026-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-mercy-2026-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-mercy-2026-poster.jpg new file mode 100644 index 00000000..cfc0d812 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-mercy-2026-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-night-is-short-walk-on-girl-2017-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-night-is-short-walk-on-girl-2017-backdrop.jpg new file mode 100644 index 00000000..da38be48 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-night-is-short-walk-on-girl-2017-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-night-is-short-walk-on-girl-2017-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-night-is-short-walk-on-girl-2017-poster.jpg new file mode 100644 index 00000000..c6fa6a26 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-night-is-short-walk-on-girl-2017-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-normal-2026-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-normal-2026-backdrop.jpg new file mode 100644 index 00000000..51711864 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-normal-2026-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-normal-2026-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-normal-2026-poster.jpg new file mode 100644 index 00000000..f4c89db7 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-normal-2026-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-outlaw-king-2018-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-outlaw-king-2018-backdrop.jpg new file mode 100644 index 00000000..54ac5a2a Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-outlaw-king-2018-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-outlaw-king-2018-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-outlaw-king-2018-poster.jpg new file mode 100644 index 00000000..d6760468 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-outlaw-king-2018-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-panic-room-2002-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-panic-room-2002-backdrop.jpg new file mode 100644 index 00000000..ec877751 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-panic-room-2002-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-panic-room-2002-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-panic-room-2002-poster.jpg new file mode 100644 index 00000000..0b2a0d30 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-panic-room-2002-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-peaky-blinders-the-immortal-man-2026-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-peaky-blinders-the-immortal-man-2026-backdrop.jpg new file mode 100644 index 00000000..e9d7155a Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-peaky-blinders-the-immortal-man-2026-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-peaky-blinders-the-immortal-man-2026-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-peaky-blinders-the-immortal-man-2026-poster.jpg new file mode 100644 index 00000000..a4814472 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-peaky-blinders-the-immortal-man-2026-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-ponyo-2008-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-ponyo-2008-backdrop.jpg new file mode 100644 index 00000000..8aa4ecbd Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-ponyo-2008-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-ponyo-2008-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-ponyo-2008-poster.jpg new file mode 100644 index 00000000..f548e831 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-ponyo-2008-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-porco-rosso-1992-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-porco-rosso-1992-backdrop.jpg new file mode 100644 index 00000000..63d8112e Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-porco-rosso-1992-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-porco-rosso-1992-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-porco-rosso-1992-poster.jpg new file mode 100644 index 00000000..4a6a2bd1 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-porco-rosso-1992-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-princess-mononoke-1997-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-princess-mononoke-1997-backdrop.jpg new file mode 100644 index 00000000..9486d2cf Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-princess-mononoke-1997-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-princess-mononoke-1997-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-princess-mononoke-1997-poster.jpg new file mode 100644 index 00000000..21dd9359 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-princess-mononoke-1997-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-prisoners-2013-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-prisoners-2013-backdrop.jpg new file mode 100644 index 00000000..724008c5 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-prisoners-2013-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-prisoners-2013-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-prisoners-2013-poster.jpg new file mode 100644 index 00000000..411b149b Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-prisoners-2013-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-racing-stripes-2005-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-racing-stripes-2005-backdrop.jpg new file mode 100644 index 00000000..1d332cec Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-racing-stripes-2005-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-racing-stripes-2005-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-racing-stripes-2005-poster.jpg new file mode 100644 index 00000000..cc2ef2ce Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-racing-stripes-2005-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-reincarnated-2012-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-reincarnated-2012-backdrop.jpg new file mode 100644 index 00000000..326e8ebc Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-reincarnated-2012-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-reincarnated-2012-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-reincarnated-2012-poster.jpg new file mode 100644 index 00000000..e9ab449c Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-reincarnated-2012-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-requiem-for-a-dream-2000-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-requiem-for-a-dream-2000-backdrop.jpg new file mode 100644 index 00000000..21842ef2 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-requiem-for-a-dream-2000-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-requiem-for-a-dream-2000-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-requiem-for-a-dream-2000-poster.jpg new file mode 100644 index 00000000..6f89abc3 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-requiem-for-a-dream-2000-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-rogue-one-a-star-wars-story-2016-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-rogue-one-a-star-wars-story-2016-backdrop.jpg new file mode 100644 index 00000000..ff0c14c0 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-rogue-one-a-star-wars-story-2016-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-rogue-one-a-star-wars-story-2016-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-rogue-one-a-star-wars-story-2016-poster.jpg new file mode 100644 index 00000000..c79e70a1 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-rogue-one-a-star-wars-story-2016-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-secondhand-lions-2003-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-secondhand-lions-2003-backdrop.jpg new file mode 100644 index 00000000..7ea43937 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-secondhand-lions-2003-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-secondhand-lions-2003-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-secondhand-lions-2003-poster.jpg new file mode 100644 index 00000000..33408fa0 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-secondhand-lions-2003-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-self-reliance-2024-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-self-reliance-2024-backdrop.jpg new file mode 100644 index 00000000..3cc0d123 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-self-reliance-2024-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-self-reliance-2024-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-self-reliance-2024-poster.jpg new file mode 100644 index 00000000..0f6017ed Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-self-reliance-2024-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-serpico-1973-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-serpico-1973-backdrop.jpg new file mode 100644 index 00000000..c9649485 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-serpico-1973-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-serpico-1973-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-serpico-1973-poster.jpg new file mode 100644 index 00000000..8ddd6e52 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-serpico-1973-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-shaft-2000-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-shaft-2000-backdrop.jpg new file mode 100644 index 00000000..13f14f93 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-shaft-2000-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-shaft-2000-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-shaft-2000-poster.jpg new file mode 100644 index 00000000..6b2b79ce Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-shaft-2000-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-shipwrecked-nightmare-at-sea-2026-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-shipwrecked-nightmare-at-sea-2026-backdrop.jpg new file mode 100644 index 00000000..6e98e242 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-shipwrecked-nightmare-at-sea-2026-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-shipwrecked-nightmare-at-sea-2026-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-shipwrecked-nightmare-at-sea-2026-poster.jpg new file mode 100644 index 00000000..f200a28d Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-shipwrecked-nightmare-at-sea-2026-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-sinbad-legend-of-the-seven-seas-2003-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-sinbad-legend-of-the-seven-seas-2003-backdrop.jpg new file mode 100644 index 00000000..d04685fe Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-sinbad-legend-of-the-seven-seas-2003-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-sinbad-legend-of-the-seven-seas-2003-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-sinbad-legend-of-the-seven-seas-2003-poster.jpg new file mode 100644 index 00000000..428bb38b Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-sinbad-legend-of-the-seven-seas-2003-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-sleeping-with-other-people-2015-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-sleeping-with-other-people-2015-backdrop.jpg new file mode 100644 index 00000000..df5bb046 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-sleeping-with-other-people-2015-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-sleeping-with-other-people-2015-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-sleeping-with-other-people-2015-poster.jpg new file mode 100644 index 00000000..a5ffff1f Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-sleeping-with-other-people-2015-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-snowpiercer-2013-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-snowpiercer-2013-backdrop.jpg new file mode 100644 index 00000000..c1281a9c Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-snowpiercer-2013-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-snowpiercer-2013-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-snowpiercer-2013-poster.jpg new file mode 100644 index 00000000..be1873fd Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-snowpiercer-2013-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-spider-man-brand-new-day-2026-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-spider-man-brand-new-day-2026-backdrop.jpg new file mode 100644 index 00000000..2fdaadb4 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-spider-man-brand-new-day-2026-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-spider-man-brand-new-day-2026-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-spider-man-brand-new-day-2026-poster.jpg new file mode 100644 index 00000000..51fa155f Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-spider-man-brand-new-day-2026-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-spider-man-far-from-home-2019-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-spider-man-far-from-home-2019-backdrop.jpg new file mode 100644 index 00000000..d09f655a Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-spider-man-far-from-home-2019-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-spider-man-far-from-home-2019-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-spider-man-far-from-home-2019-poster.jpg new file mode 100644 index 00000000..28521997 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-spider-man-far-from-home-2019-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-spider-man-homecoming-2017-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-spider-man-homecoming-2017-backdrop.jpg new file mode 100644 index 00000000..6088fadf Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-spider-man-homecoming-2017-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-spider-man-homecoming-2017-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-spider-man-homecoming-2017-poster.jpg new file mode 100644 index 00000000..97fc9c05 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-spider-man-homecoming-2017-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-spider-man-no-way-home-2021-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-spider-man-no-way-home-2021-backdrop.jpg new file mode 100644 index 00000000..a76afec9 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-spider-man-no-way-home-2021-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-spider-man-no-way-home-2021-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-spider-man-no-way-home-2021-poster.jpg new file mode 100644 index 00000000..bc92a4cd Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-spider-man-no-way-home-2021-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-spirited-away-2001-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-spirited-away-2001-backdrop.jpg new file mode 100644 index 00000000..af91c123 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-spirited-away-2001-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-spirited-away-2001-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-spirited-away-2001-poster.jpg new file mode 100644 index 00000000..5a79da62 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-spirited-away-2001-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-steins-gate-the-movie-load-region-of-deja-vu-2013-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-steins-gate-the-movie-load-region-of-deja-vu-2013-backdrop.jpg new file mode 100644 index 00000000..f6675060 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-steins-gate-the-movie-load-region-of-deja-vu-2013-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-steins-gate-the-movie-load-region-of-deja-vu-2013-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-steins-gate-the-movie-load-region-of-deja-vu-2013-poster.jpg new file mode 100644 index 00000000..e85ddb90 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-steins-gate-the-movie-load-region-of-deja-vu-2013-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-taxi-driver-1976-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-taxi-driver-1976-backdrop.jpg new file mode 100644 index 00000000..7946ea40 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-taxi-driver-1976-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-taxi-driver-1976-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-taxi-driver-1976-poster.jpg new file mode 100644 index 00000000..c410b981 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-taxi-driver-1976-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-alto-knights-2025-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-alto-knights-2025-backdrop.jpg new file mode 100644 index 00000000..ea619c14 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-alto-knights-2025-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-alto-knights-2025-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-alto-knights-2025-poster.jpg new file mode 100644 index 00000000..bb009cbf Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-alto-knights-2025-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-amazing-spider-man-2-2014-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-amazing-spider-man-2-2014-backdrop.jpg new file mode 100644 index 00000000..7c5878b7 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-amazing-spider-man-2-2014-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-amazing-spider-man-2-2014-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-amazing-spider-man-2-2014-poster.jpg new file mode 100644 index 00000000..4de2711f Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-amazing-spider-man-2-2014-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-amazing-spider-man-2012-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-amazing-spider-man-2012-backdrop.jpg new file mode 100644 index 00000000..75ae9b64 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-amazing-spider-man-2012-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-amazing-spider-man-2012-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-amazing-spider-man-2012-poster.jpg new file mode 100644 index 00000000..c1aec876 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-amazing-spider-man-2012-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-animatrix-2003-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-animatrix-2003-backdrop.jpg new file mode 100644 index 00000000..7d67ccb0 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-animatrix-2003-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-animatrix-2003-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-animatrix-2003-poster.jpg new file mode 100644 index 00000000..65553d47 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-animatrix-2003-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-avengers-2012-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-avengers-2012-backdrop.jpg new file mode 100644 index 00000000..83636f25 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-avengers-2012-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-avengers-2012-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-avengers-2012-poster.jpg new file mode 100644 index 00000000..be87067c Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-avengers-2012-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-boy-and-the-heron-2023-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-boy-and-the-heron-2023-backdrop.jpg new file mode 100644 index 00000000..a19dc77b Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-boy-and-the-heron-2023-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-boy-and-the-heron-2023-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-boy-and-the-heron-2023-poster.jpg new file mode 100644 index 00000000..094df64e Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-boy-and-the-heron-2023-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-breakfast-club-1985-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-breakfast-club-1985-backdrop.jpg new file mode 100644 index 00000000..9f979cd8 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-breakfast-club-1985-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-breakfast-club-1985-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-breakfast-club-1985-poster.jpg new file mode 100644 index 00000000..d1823120 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-breakfast-club-1985-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-dry-2021-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-dry-2021-backdrop.jpg new file mode 100644 index 00000000..2f016498 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-dry-2021-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-dry-2021-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-dry-2021-poster.jpg new file mode 100644 index 00000000..a0379f2f Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-dry-2021-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-girl-who-leapt-through-time-2006-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-girl-who-leapt-through-time-2006-backdrop.jpg new file mode 100644 index 00000000..6e920467 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-girl-who-leapt-through-time-2006-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-girl-who-leapt-through-time-2006-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-girl-who-leapt-through-time-2006-poster.jpg new file mode 100644 index 00000000..ded6cd2a Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-girl-who-leapt-through-time-2006-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-godfather-1972-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-godfather-1972-backdrop.jpg new file mode 100644 index 00000000..8fbb8f2a Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-godfather-1972-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-godfather-1972-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-godfather-1972-poster.jpg new file mode 100644 index 00000000..94111d9b Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-godfather-1972-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-godfather-part-ii-1974-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-godfather-part-ii-1974-backdrop.jpg new file mode 100644 index 00000000..6dbff534 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-godfather-part-ii-1974-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-godfather-part-ii-1974-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-godfather-part-ii-1974-poster.jpg new file mode 100644 index 00000000..1328c99e Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-godfather-part-ii-1974-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-godfather-part-iii-1990-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-godfather-part-iii-1990-backdrop.jpg new file mode 100644 index 00000000..d2080487 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-godfather-part-iii-1990-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-godfather-part-iii-1990-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-godfather-part-iii-1990-poster.jpg new file mode 100644 index 00000000..abbe5e99 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-godfather-part-iii-1990-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-great-gatsby-2013-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-great-gatsby-2013-backdrop.jpg new file mode 100644 index 00000000..7a4f8a32 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-great-gatsby-2013-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-great-gatsby-2013-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-great-gatsby-2013-poster.jpg new file mode 100644 index 00000000..e949fb3e Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-great-gatsby-2013-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-hours-2002-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-hours-2002-backdrop.jpg new file mode 100644 index 00000000..507a78c4 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-hours-2002-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-hours-2002-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-hours-2002-poster.jpg new file mode 100644 index 00000000..f87e919f Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-hours-2002-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-killing-of-a-sacred-deer-2017-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-killing-of-a-sacred-deer-2017-backdrop.jpg new file mode 100644 index 00000000..dd755ee8 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-killing-of-a-sacred-deer-2017-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-killing-of-a-sacred-deer-2017-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-killing-of-a-sacred-deer-2017-poster.jpg new file mode 100644 index 00000000..83464d4c Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-killing-of-a-sacred-deer-2017-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-last-of-the-mohicans-1992-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-last-of-the-mohicans-1992-backdrop.jpg new file mode 100644 index 00000000..3256d38d Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-last-of-the-mohicans-1992-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-last-of-the-mohicans-1992-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-last-of-the-mohicans-1992-poster.jpg new file mode 100644 index 00000000..950e9ba1 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-last-of-the-mohicans-1992-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-last-samurai-2003-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-last-samurai-2003-backdrop.jpg new file mode 100644 index 00000000..509af2d6 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-last-samurai-2003-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-last-samurai-2003-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-last-samurai-2003-poster.jpg new file mode 100644 index 00000000..0d58440c Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-last-samurai-2003-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-lighthouse-2019-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-lighthouse-2019-backdrop.jpg new file mode 100644 index 00000000..862c064a Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-lighthouse-2019-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-lighthouse-2019-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-lighthouse-2019-poster.jpg new file mode 100644 index 00000000..15f26533 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-lighthouse-2019-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-matrix-1999-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-matrix-1999-backdrop.jpg new file mode 100644 index 00000000..c3bf8f52 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-matrix-1999-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-matrix-1999-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-matrix-1999-poster.jpg new file mode 100644 index 00000000..c292dce5 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-matrix-1999-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-matrix-reloaded-2003-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-matrix-reloaded-2003-backdrop.jpg new file mode 100644 index 00000000..dcbf7b96 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-matrix-reloaded-2003-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-matrix-reloaded-2003-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-matrix-reloaded-2003-poster.jpg new file mode 100644 index 00000000..ab11f50f Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-matrix-reloaded-2003-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-matrix-resurrections-2021-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-matrix-resurrections-2021-backdrop.jpg new file mode 100644 index 00000000..99d85a40 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-matrix-resurrections-2021-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-matrix-resurrections-2021-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-matrix-resurrections-2021-poster.jpg new file mode 100644 index 00000000..4477ef1e Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-matrix-resurrections-2021-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-matrix-revolutions-2003-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-matrix-revolutions-2003-backdrop.jpg new file mode 100644 index 00000000..2cc02692 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-matrix-revolutions-2003-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-matrix-revolutions-2003-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-matrix-revolutions-2003-poster.jpg new file mode 100644 index 00000000..7236cc4e Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-matrix-revolutions-2003-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-patriot-2000-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-patriot-2000-backdrop.jpg new file mode 100644 index 00000000..ce7ce498 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-patriot-2000-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-patriot-2000-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-patriot-2000-poster.jpg new file mode 100644 index 00000000..c8582133 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-patriot-2000-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-secret-life-of-pets-2-2019-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-secret-life-of-pets-2-2019-backdrop.jpg new file mode 100644 index 00000000..698f4ad2 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-secret-life-of-pets-2-2019-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-secret-life-of-pets-2-2019-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-secret-life-of-pets-2-2019-poster.jpg new file mode 100644 index 00000000..fe50c2f8 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-secret-life-of-pets-2-2019-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-substance-2024-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-substance-2024-backdrop.jpg new file mode 100644 index 00000000..47a8b372 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-substance-2024-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-substance-2024-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-substance-2024-poster.jpg new file mode 100644 index 00000000..72accfed Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-substance-2024-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-tale-of-the-princess-kaguya-2013-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-tale-of-the-princess-kaguya-2013-backdrop.jpg new file mode 100644 index 00000000..b9157b91 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-tale-of-the-princess-kaguya-2013-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-tale-of-the-princess-kaguya-2013-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-tale-of-the-princess-kaguya-2013-poster.jpg new file mode 100644 index 00000000..882621cb Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-tale-of-the-princess-kaguya-2013-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-uprising-2026-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-uprising-2026-backdrop.jpg new file mode 100644 index 00000000..638eab3d Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-uprising-2026-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-uprising-2026-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-uprising-2026-poster.jpg new file mode 100644 index 00000000..21976395 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-uprising-2026-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-wild-robot-2024-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-wild-robot-2024-backdrop.jpg new file mode 100644 index 00000000..bb48460b Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-wild-robot-2024-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-wild-robot-2024-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-wild-robot-2024-poster.jpg new file mode 100644 index 00000000..0894754d Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-wild-robot-2024-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-wind-rises-2013-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-wind-rises-2013-backdrop.jpg new file mode 100644 index 00000000..2af40e28 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-wind-rises-2013-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-wind-rises-2013-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-wind-rises-2013-poster.jpg new file mode 100644 index 00000000..b7688c77 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-wind-rises-2013-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-witcher-nightmare-of-the-wolf-2021-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-witcher-nightmare-of-the-wolf-2021-backdrop.jpg new file mode 100644 index 00000000..cb5bfb28 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-witcher-nightmare-of-the-wolf-2021-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-witcher-nightmare-of-the-wolf-2021-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-witcher-nightmare-of-the-wolf-2021-poster.jpg new file mode 100644 index 00000000..6db33db1 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-witcher-nightmare-of-the-wolf-2021-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-witcher-sirens-of-the-deep-2025-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-witcher-sirens-of-the-deep-2025-backdrop.jpg new file mode 100644 index 00000000..aad8ea2c Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-witcher-sirens-of-the-deep-2025-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-witcher-sirens-of-the-deep-2025-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-witcher-sirens-of-the-deep-2025-poster.jpg new file mode 100644 index 00000000..8a54bc7f Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-the-witcher-sirens-of-the-deep-2025-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-thelma-louise-1991-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-thelma-louise-1991-backdrop.jpg new file mode 100644 index 00000000..a35327a9 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-thelma-louise-1991-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-thelma-louise-1991-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-thelma-louise-1991-poster.jpg new file mode 100644 index 00000000..5a4ff0ab Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-thelma-louise-1991-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-triangle-of-sadness-2022-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-triangle-of-sadness-2022-backdrop.jpg new file mode 100644 index 00000000..7c9b445d Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-triangle-of-sadness-2022-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-triangle-of-sadness-2022-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-triangle-of-sadness-2022-poster.jpg new file mode 100644 index 00000000..aee092c6 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-triangle-of-sadness-2022-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-tsotsi-2005-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-tsotsi-2005-backdrop.jpg new file mode 100644 index 00000000..e119de53 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-tsotsi-2005-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-tsotsi-2005-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-tsotsi-2005-poster.jpg new file mode 100644 index 00000000..362ddd82 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-tsotsi-2005-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-unknown-number-the-high-school-catfish-2025-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-unknown-number-the-high-school-catfish-2025-backdrop.jpg new file mode 100644 index 00000000..f456c01d Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-unknown-number-the-high-school-catfish-2025-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-unknown-number-the-high-school-catfish-2025-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-unknown-number-the-high-school-catfish-2025-poster.jpg new file mode 100644 index 00000000..e32685f3 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-unknown-number-the-high-school-catfish-2025-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-vice-2018-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-vice-2018-backdrop.jpg new file mode 100644 index 00000000..2918db3a Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-vice-2018-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-vice-2018-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-vice-2018-poster.jpg new file mode 100644 index 00000000..76855126 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-vice-2018-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-vicky-cristina-barcelona-2008-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-vicky-cristina-barcelona-2008-backdrop.jpg new file mode 100644 index 00000000..20eaa159 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-vicky-cristina-barcelona-2008-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-vicky-cristina-barcelona-2008-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-vicky-cristina-barcelona-2008-poster.jpg new file mode 100644 index 00000000..1351cad1 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-vicky-cristina-barcelona-2008-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-warriors-of-the-wind-1984-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-warriors-of-the-wind-1984-backdrop.jpg new file mode 100644 index 00000000..1fb22b96 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-warriors-of-the-wind-1984-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-warriors-of-the-wind-1984-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-warriors-of-the-wind-1984-poster.jpg new file mode 100644 index 00000000..918e424f Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-warriors-of-the-wind-1984-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-we-bury-the-dead-2026-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-we-bury-the-dead-2026-backdrop.jpg new file mode 100644 index 00000000..4a24720d Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-we-bury-the-dead-2026-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-we-bury-the-dead-2026-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-we-bury-the-dead-2026-poster.jpg new file mode 100644 index 00000000..a0d65904 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-we-bury-the-dead-2026-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-white-hot-the-rise-fall-of-abercrombie-fitch-2022-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-white-hot-the-rise-fall-of-abercrombie-fitch-2022-backdrop.jpg new file mode 100644 index 00000000..2f186030 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-white-hot-the-rise-fall-of-abercrombie-fitch-2022-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-white-hot-the-rise-fall-of-abercrombie-fitch-2022-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-white-hot-the-rise-fall-of-abercrombie-fitch-2022-poster.jpg new file mode 100644 index 00000000..3a123e80 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/movie-white-hot-the-rise-fall-of-abercrombie-fitch-2022-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-12-monkeys-2015-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-12-monkeys-2015-backdrop.jpg new file mode 100644 index 00000000..3d2825f5 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-12-monkeys-2015-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-12-monkeys-2015-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-12-monkeys-2015-poster.jpg new file mode 100644 index 00000000..96e3596e Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-12-monkeys-2015-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-56-days-2026-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-56-days-2026-backdrop.jpg new file mode 100644 index 00000000..dcda667a Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-56-days-2026-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-56-days-2026-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-56-days-2026-poster.jpg new file mode 100644 index 00000000..64ca587b Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-56-days-2026-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-90-day-fiance-before-the-90-days-2017-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-90-day-fiance-before-the-90-days-2017-backdrop.jpg new file mode 100644 index 00000000..24f66f2d Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-90-day-fiance-before-the-90-days-2017-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-90-day-fiance-before-the-90-days-2017-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-90-day-fiance-before-the-90-days-2017-poster.jpg new file mode 100644 index 00000000..3362da59 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-90-day-fiance-before-the-90-days-2017-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-90-day-fiance-the-other-way-2019-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-90-day-fiance-the-other-way-2019-backdrop.jpg new file mode 100644 index 00000000..b18891fd Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-90-day-fiance-the-other-way-2019-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-90-day-fiance-the-other-way-2019-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-90-day-fiance-the-other-way-2019-poster.jpg new file mode 100644 index 00000000..b4d256eb Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-90-day-fiance-the-other-way-2019-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-a-knight-of-the-seven-kingdoms-2026-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-a-knight-of-the-seven-kingdoms-2026-backdrop.jpg new file mode 100644 index 00000000..ce12fc71 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-a-knight-of-the-seven-kingdoms-2026-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-a-knight-of-the-seven-kingdoms-2026-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-a-knight-of-the-seven-kingdoms-2026-poster.jpg new file mode 100644 index 00000000..79f1351c Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-a-knight-of-the-seven-kingdoms-2026-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-absolutely-fabulous-1992-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-absolutely-fabulous-1992-backdrop.jpg new file mode 100644 index 00000000..2df9722d Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-absolutely-fabulous-1992-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-absolutely-fabulous-1992-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-absolutely-fabulous-1992-poster.jpg new file mode 100644 index 00000000..afd371a9 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-absolutely-fabulous-1992-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-accel-world-2012-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-accel-world-2012-backdrop.jpg new file mode 100644 index 00000000..1f5f6bdc Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-accel-world-2012-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-accel-world-2012-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-accel-world-2012-poster.jpg new file mode 100644 index 00000000..207b1dd1 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-accel-world-2012-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-accused-2023-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-accused-2023-backdrop.jpg new file mode 100644 index 00000000..d41c6397 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-accused-2023-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-accused-2023-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-accused-2023-poster.jpg new file mode 100644 index 00000000..74af010a Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-accused-2023-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-adults-2025-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-adults-2025-backdrop.jpg new file mode 100644 index 00000000..9cc0ffe2 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-adults-2025-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-adults-2025-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-adults-2025-poster.jpg new file mode 100644 index 00000000..53a7ba33 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-adults-2025-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-after-life-2019-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-after-life-2019-backdrop.jpg new file mode 100644 index 00000000..eaf9a4fa Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-after-life-2019-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-after-life-2019-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-after-life-2019-poster.jpg new file mode 100644 index 00000000..4fae4e33 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-after-life-2019-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-agatha-christie-s-marple-2004-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-agatha-christie-s-marple-2004-backdrop.jpg new file mode 100644 index 00000000..0c52f2e6 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-agatha-christie-s-marple-2004-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-agatha-christie-s-marple-2004-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-agatha-christie-s-marple-2004-poster.jpg new file mode 100644 index 00000000..ea7dda99 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-agatha-christie-s-marple-2004-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-ahsoka-2023-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-ahsoka-2023-backdrop.jpg new file mode 100644 index 00000000..7343fb32 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-ahsoka-2023-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-ahsoka-2023-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-ahsoka-2023-poster.jpg new file mode 100644 index 00000000..a29d6cb4 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-ahsoka-2023-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-all-american-homecoming-2022-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-all-american-homecoming-2022-backdrop.jpg new file mode 100644 index 00000000..09fbb9dc Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-all-american-homecoming-2022-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-all-american-homecoming-2022-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-all-american-homecoming-2022-poster.jpg new file mode 100644 index 00000000..09ccfc33 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-all-american-homecoming-2022-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-all-creatures-great-and-small-1978-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-all-creatures-great-and-small-1978-backdrop.jpg new file mode 100644 index 00000000..909ae1ba Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-all-creatures-great-and-small-1978-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-all-creatures-great-and-small-1978-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-all-creatures-great-and-small-1978-poster.jpg new file mode 100644 index 00000000..5b1666e6 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-all-creatures-great-and-small-1978-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-all-creatures-great-small-2020-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-all-creatures-great-small-2020-backdrop.jpg new file mode 100644 index 00000000..d2bcc88d Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-all-creatures-great-small-2020-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-all-creatures-great-small-2020-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-all-creatures-great-small-2020-poster.jpg new file mode 100644 index 00000000..b506f990 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-all-creatures-great-small-2020-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-american-crime-story-2016-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-american-crime-story-2016-backdrop.jpg new file mode 100644 index 00000000..84944d39 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-american-crime-story-2016-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-american-crime-story-2016-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-american-crime-story-2016-poster.jpg new file mode 100644 index 00000000..4086bf17 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-american-crime-story-2016-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-american-dad-2005-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-american-dad-2005-backdrop.jpg new file mode 100644 index 00000000..75a1948b Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-american-dad-2005-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-american-dad-2005-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-american-dad-2005-poster.jpg new file mode 100644 index 00000000..1f9e239a Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-american-dad-2005-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-american-gods-2017-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-american-gods-2017-backdrop.jpg new file mode 100644 index 00000000..4817c690 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-american-gods-2017-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-american-gods-2017-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-american-gods-2017-poster.jpg new file mode 100644 index 00000000..c02c46da Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-american-gods-2017-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-american-housewife-2016-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-american-housewife-2016-backdrop.jpg new file mode 100644 index 00000000..bf758ae0 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-american-housewife-2016-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-american-housewife-2016-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-american-housewife-2016-poster.jpg new file mode 100644 index 00000000..5f92bf05 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-american-housewife-2016-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-american-primeval-2025-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-american-primeval-2025-backdrop.jpg new file mode 100644 index 00000000..c3bfe5e1 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-american-primeval-2025-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-american-primeval-2025-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-american-primeval-2025-poster.jpg new file mode 100644 index 00000000..7f10e6aa Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-american-primeval-2025-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-and-just-like-that-2021-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-and-just-like-that-2021-backdrop.jpg new file mode 100644 index 00000000..59c981e5 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-and-just-like-that-2021-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-and-just-like-that-2021-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-and-just-like-that-2021-poster.jpg new file mode 100644 index 00000000..9904c74b Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-and-just-like-that-2021-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-andor-2022-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-andor-2022-backdrop.jpg new file mode 100644 index 00000000..a874a0c0 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-andor-2022-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-andor-2022-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-andor-2022-poster.jpg new file mode 100644 index 00000000..df5dc498 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-andor-2022-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-andromeda-2000-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-andromeda-2000-backdrop.jpg new file mode 100644 index 00000000..199249d7 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-andromeda-2000-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-andromeda-2000-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-andromeda-2000-poster.jpg new file mode 100644 index 00000000..67b766b0 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-andromeda-2000-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-anne-with-an-e-2017-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-anne-with-an-e-2017-backdrop.jpg new file mode 100644 index 00000000..15e325c9 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-anne-with-an-e-2017-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-anne-with-an-e-2017-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-anne-with-an-e-2017-poster.jpg new file mode 100644 index 00000000..55d443b4 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-anne-with-an-e-2017-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-aqua-teen-hunger-force-2000-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-aqua-teen-hunger-force-2000-backdrop.jpg new file mode 100644 index 00000000..d0e37959 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-aqua-teen-hunger-force-2000-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-aqua-teen-hunger-force-2000-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-aqua-teen-hunger-force-2000-poster.jpg new file mode 100644 index 00000000..e0c97321 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-aqua-teen-hunger-force-2000-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-arifureta-from-commonplace-to-world-s-strongest-2019-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-arifureta-from-commonplace-to-world-s-strongest-2019-backdrop.jpg new file mode 100644 index 00000000..9300e20f Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-arifureta-from-commonplace-to-world-s-strongest-2019-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-arifureta-from-commonplace-to-world-s-strongest-2019-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-arifureta-from-commonplace-to-world-s-strongest-2019-poster.jpg new file mode 100644 index 00000000..6a8f9a24 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-arifureta-from-commonplace-to-world-s-strongest-2019-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-arrested-development-2003-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-arrested-development-2003-backdrop.jpg new file mode 100644 index 00000000..ecb7e8cd Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-arrested-development-2003-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-arrested-development-2003-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-arrested-development-2003-poster.jpg new file mode 100644 index 00000000..02b0dd43 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-arrested-development-2003-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-arrow-2012-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-arrow-2012-backdrop.jpg new file mode 100644 index 00000000..b32f5aca Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-arrow-2012-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-arrow-2012-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-arrow-2012-poster.jpg new file mode 100644 index 00000000..adee3bb7 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-arrow-2012-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-atlantis-2013-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-atlantis-2013-backdrop.jpg new file mode 100644 index 00000000..39ecc0d6 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-atlantis-2013-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-atlantis-2013-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-atlantis-2013-poster.jpg new file mode 100644 index 00000000..5cd5f098 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-atlantis-2013-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-avatar-seven-havens-2026-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-avatar-seven-havens-2026-backdrop.jpg new file mode 100644 index 00000000..dacfd59e Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-avatar-seven-havens-2026-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-avatar-seven-havens-2026-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-avatar-seven-havens-2026-poster.jpg new file mode 100644 index 00000000..61f459c6 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-avatar-seven-havens-2026-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-avatar-the-last-airbender-2005-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-avatar-the-last-airbender-2005-backdrop.jpg new file mode 100644 index 00000000..f60120da Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-avatar-the-last-airbender-2005-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-avatar-the-last-airbender-2005-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-avatar-the-last-airbender-2005-poster.jpg new file mode 100644 index 00000000..6f99263a Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-avatar-the-last-airbender-2005-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-avatar-the-last-airbender-2024-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-avatar-the-last-airbender-2024-backdrop.jpg new file mode 100644 index 00000000..ad740218 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-avatar-the-last-airbender-2024-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-avatar-the-last-airbender-2024-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-avatar-the-last-airbender-2024-poster.jpg new file mode 100644 index 00000000..9d46c2ff Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-avatar-the-last-airbender-2024-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-awkward-2011-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-awkward-2011-backdrop.jpg new file mode 100644 index 00000000..1ca5e56c Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-awkward-2011-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-awkward-2011-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-awkward-2011-poster.jpg new file mode 100644 index 00000000..8da6e8e2 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-awkward-2011-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-b-b-vol-liefde-2021-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-b-b-vol-liefde-2021-backdrop.jpg new file mode 100644 index 00000000..57ece15e Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-b-b-vol-liefde-2021-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-b-b-vol-liefde-2021-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-b-b-vol-liefde-2021-poster.jpg new file mode 100644 index 00000000..a12ac33e Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-b-b-vol-liefde-2021-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-back-to-life-2019-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-back-to-life-2019-backdrop.jpg new file mode 100644 index 00000000..7ffef681 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-back-to-life-2019-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-back-to-life-2019-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-back-to-life-2019-poster.jpg new file mode 100644 index 00000000..b00730a8 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-back-to-life-2019-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-ballers-2015-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-ballers-2015-backdrop.jpg new file mode 100644 index 00000000..c4685e84 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-ballers-2015-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-ballers-2015-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-ballers-2015-poster.jpg new file mode 100644 index 00000000..f1c18f69 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-ballers-2015-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-baretta-1975-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-baretta-1975-backdrop.jpg new file mode 100644 index 00000000..4d61dfbe Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-baretta-1975-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-baretta-1975-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-baretta-1975-poster.jpg new file mode 100644 index 00000000..ceef0c9d Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-baretta-1975-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-based-on-a-true-story-2023-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-based-on-a-true-story-2023-backdrop.jpg new file mode 100644 index 00000000..b59c0e58 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-based-on-a-true-story-2023-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-based-on-a-true-story-2023-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-based-on-a-true-story-2023-poster.jpg new file mode 100644 index 00000000..386d3d90 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-based-on-a-true-story-2023-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-batman-the-brave-and-the-bold-2008-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-batman-the-brave-and-the-bold-2008-backdrop.jpg new file mode 100644 index 00000000..69e567cb Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-batman-the-brave-and-the-bold-2008-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-batman-the-brave-and-the-bold-2008-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-batman-the-brave-and-the-bold-2008-poster.jpg new file mode 100644 index 00000000..a864f50c Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-batman-the-brave-and-the-bold-2008-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-batwoman-2019-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-batwoman-2019-backdrop.jpg new file mode 100644 index 00000000..d04a1a20 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-batwoman-2019-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-batwoman-2019-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-batwoman-2019-poster.jpg new file mode 100644 index 00000000..7ca86592 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-batwoman-2019-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-beat-bobby-flay-2013-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-beat-bobby-flay-2013-backdrop.jpg new file mode 100644 index 00000000..e6c36ddd Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-beat-bobby-flay-2013-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-beat-bobby-flay-2013-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-beat-bobby-flay-2013-poster.jpg new file mode 100644 index 00000000..fe11122d Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-beat-bobby-flay-2013-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-benson-1979-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-benson-1979-backdrop.jpg new file mode 100644 index 00000000..32bd63a9 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-benson-1979-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-benson-1979-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-benson-1979-poster.jpg new file mode 100644 index 00000000..fe264c76 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-benson-1979-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-big-boys-2022-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-big-boys-2022-backdrop.jpg new file mode 100644 index 00000000..c7c91e2d Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-big-boys-2022-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-big-boys-2022-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-big-boys-2022-poster.jpg new file mode 100644 index 00000000..93e1e86a Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-big-boys-2022-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-big-city-greens-2018-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-big-city-greens-2018-backdrop.jpg new file mode 100644 index 00000000..381774e7 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-big-city-greens-2018-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-big-city-greens-2018-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-big-city-greens-2018-poster.jpg new file mode 100644 index 00000000..ef024946 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-big-city-greens-2018-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-big-mouth-2017-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-big-mouth-2017-backdrop.jpg new file mode 100644 index 00000000..760e0262 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-big-mouth-2017-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-big-mouth-2017-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-big-mouth-2017-poster.jpg new file mode 100644 index 00000000..4f535fec Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-big-mouth-2017-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-black-ish-2014-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-black-ish-2014-backdrop.jpg new file mode 100644 index 00000000..967fb621 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-black-ish-2014-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-black-ish-2014-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-black-ish-2014-poster.jpg new file mode 100644 index 00000000..97c885ad Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-black-ish-2014-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-black-lightning-2018-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-black-lightning-2018-backdrop.jpg new file mode 100644 index 00000000..3a0854c9 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-black-lightning-2018-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-black-lightning-2018-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-black-lightning-2018-poster.jpg new file mode 100644 index 00000000..733f5cbc Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-black-lightning-2018-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-black-rabbit-2025-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-black-rabbit-2025-backdrop.jpg new file mode 100644 index 00000000..48df9d46 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-black-rabbit-2025-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-black-rabbit-2025-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-black-rabbit-2025-poster.jpg new file mode 100644 index 00000000..3ff9aeed Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-black-rabbit-2025-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-bleach-2004-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-bleach-2004-backdrop.jpg new file mode 100644 index 00000000..ef8eaaa3 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-bleach-2004-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-bleach-2004-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-bleach-2004-poster.jpg new file mode 100644 index 00000000..b233e033 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-bleach-2004-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-blue-planet-ii-2017-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-blue-planet-ii-2017-backdrop.jpg new file mode 100644 index 00000000..8175e568 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-blue-planet-ii-2017-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-blue-planet-ii-2017-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-blue-planet-ii-2017-poster.jpg new file mode 100644 index 00000000..5e193ab2 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-blue-planet-ii-2017-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-brassic-2019-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-brassic-2019-backdrop.jpg new file mode 100644 index 00000000..86d3d806 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-brassic-2019-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-brassic-2019-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-brassic-2019-poster.jpg new file mode 100644 index 00000000..73b77df2 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-brassic-2019-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-breaking-bad-2008-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-breaking-bad-2008-backdrop.jpg new file mode 100644 index 00000000..e4ac4ae3 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-breaking-bad-2008-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-breaking-bad-2008-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-breaking-bad-2008-poster.jpg new file mode 100644 index 00000000..c4f7217c Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-breaking-bad-2008-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-breeders-2020-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-breeders-2020-backdrop.jpg new file mode 100644 index 00000000..9d95ba77 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-breeders-2020-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-breeders-2020-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-breeders-2020-poster.jpg new file mode 100644 index 00000000..49c61208 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-breeders-2020-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-californication-2007-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-californication-2007-backdrop.jpg new file mode 100644 index 00000000..ffff979b Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-californication-2007-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-californication-2007-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-californication-2007-poster.jpg new file mode 100644 index 00000000..38428e76 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-californication-2007-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-call-the-midwife-2012-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-call-the-midwife-2012-backdrop.jpg new file mode 100644 index 00000000..1ee28b8d Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-call-the-midwife-2012-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-call-the-midwife-2012-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-call-the-midwife-2012-poster.jpg new file mode 100644 index 00000000..466a1a7b Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-call-the-midwife-2012-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-chainsaw-man-2022-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-chainsaw-man-2022-backdrop.jpg new file mode 100644 index 00000000..f1fbee3e Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-chainsaw-man-2022-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-chainsaw-man-2022-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-chainsaw-man-2022-poster.jpg new file mode 100644 index 00000000..a3779772 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-chainsaw-man-2022-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-chernobyl-2019-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-chernobyl-2019-backdrop.jpg new file mode 100644 index 00000000..818a6665 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-chernobyl-2019-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-chernobyl-2019-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-chernobyl-2019-poster.jpg new file mode 100644 index 00000000..7664f4b0 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-chernobyl-2019-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-community-2009-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-community-2009-backdrop.jpg new file mode 100644 index 00000000..8deb8d5c Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-community-2009-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-community-2009-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-community-2009-poster.jpg new file mode 100644 index 00000000..e75072ae Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-community-2009-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-cyberpunk-edgerunners-2022-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-cyberpunk-edgerunners-2022-backdrop.jpg new file mode 100644 index 00000000..2920cf5a Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-cyberpunk-edgerunners-2022-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-cyberpunk-edgerunners-2022-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-cyberpunk-edgerunners-2022-poster.jpg new file mode 100644 index 00000000..8d338532 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-cyberpunk-edgerunners-2022-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-dan-da-dan-2024-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-dan-da-dan-2024-backdrop.jpg new file mode 100644 index 00000000..0cbc4b07 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-dan-da-dan-2024-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-dan-da-dan-2024-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-dan-da-dan-2024-poster.jpg new file mode 100644 index 00000000..f42cec16 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-dan-da-dan-2024-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-dead-end-job-2026-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-dead-end-job-2026-backdrop.jpg new file mode 100644 index 00000000..3525c2fc Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-dead-end-job-2026-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-dead-end-job-2026-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-dead-end-job-2026-poster.jpg new file mode 100644 index 00000000..f5546d88 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-dead-end-job-2026-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-derry-girls-2018-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-derry-girls-2018-backdrop.jpg new file mode 100644 index 00000000..76fae98c Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-derry-girls-2018-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-derry-girls-2018-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-derry-girls-2018-poster.jpg new file mode 100644 index 00000000..56a8cd79 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-derry-girls-2018-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-desperate-housewives-2004-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-desperate-housewives-2004-backdrop.jpg new file mode 100644 index 00000000..40ec3001 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-desperate-housewives-2004-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-desperate-housewives-2004-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-desperate-housewives-2004-poster.jpg new file mode 100644 index 00000000..0c4c38bc Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-desperate-housewives-2004-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-dopesick-2021-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-dopesick-2021-backdrop.jpg new file mode 100644 index 00000000..8d9f2727 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-dopesick-2021-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-dopesick-2021-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-dopesick-2021-poster.jpg new file mode 100644 index 00000000..ac0b5900 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-dopesick-2021-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-dr-stone-2019-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-dr-stone-2019-backdrop.jpg new file mode 100644 index 00000000..5ac396b6 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-dr-stone-2019-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-dr-stone-2019-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-dr-stone-2019-poster.jpg new file mode 100644 index 00000000..0783ed8c Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-dr-stone-2019-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-dune-prophecy-2024-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-dune-prophecy-2024-backdrop.jpg new file mode 100644 index 00000000..5b940b9f Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-dune-prophecy-2024-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-dune-prophecy-2024-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-dune-prophecy-2024-poster.jpg new file mode 100644 index 00000000..eef2a4f3 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-dune-prophecy-2024-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-east-of-eden-2026-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-east-of-eden-2026-backdrop.jpg new file mode 100644 index 00000000..89dfafbf Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-east-of-eden-2026-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-east-of-eden-2026-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-east-of-eden-2026-poster.jpg new file mode 100644 index 00000000..6f06f2c9 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-east-of-eden-2026-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-etoile-2025-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-etoile-2025-backdrop.jpg new file mode 100644 index 00000000..a8e9576c Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-etoile-2025-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-etoile-2025-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-etoile-2025-poster.jpg new file mode 100644 index 00000000..f078bc89 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-etoile-2025-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-fallout-2024-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-fallout-2024-backdrop.jpg new file mode 100644 index 00000000..c9d6a190 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-fallout-2024-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-fallout-2024-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-fallout-2024-poster.jpg new file mode 100644 index 00000000..5e87a07d Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-fallout-2024-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-fawlty-towers-1975-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-fawlty-towers-1975-backdrop.jpg new file mode 100644 index 00000000..2c9c258f Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-fawlty-towers-1975-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-fawlty-towers-1975-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-fawlty-towers-1975-poster.jpg new file mode 100644 index 00000000..53b406da Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-fawlty-towers-1975-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-firefly-2002-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-firefly-2002-backdrop.jpg new file mode 100644 index 00000000..fa3b7604 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-firefly-2002-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-firefly-2002-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-firefly-2002-poster.jpg new file mode 100644 index 00000000..9ad599b3 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-firefly-2002-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-fleabag-2016-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-fleabag-2016-backdrop.jpg new file mode 100644 index 00000000..e5a83462 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-fleabag-2016-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-fleabag-2016-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-fleabag-2016-poster.jpg new file mode 100644 index 00000000..bd3ccea5 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-fleabag-2016-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-frieren-beyond-journey-s-end-2023-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-frieren-beyond-journey-s-end-2023-backdrop.jpg new file mode 100644 index 00000000..a42a2c94 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-frieren-beyond-journey-s-end-2023-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-frieren-beyond-journey-s-end-2023-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-frieren-beyond-journey-s-end-2023-poster.jpg new file mode 100644 index 00000000..cb94104e Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-frieren-beyond-journey-s-end-2023-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-fullmetal-alchemist-brotherhood-2009-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-fullmetal-alchemist-brotherhood-2009-backdrop.jpg new file mode 100644 index 00000000..91ce4909 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-fullmetal-alchemist-brotherhood-2009-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-fullmetal-alchemist-brotherhood-2009-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-fullmetal-alchemist-brotherhood-2009-poster.jpg new file mode 100644 index 00000000..935e4944 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-fullmetal-alchemist-brotherhood-2009-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-gilmore-girls-2000-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-gilmore-girls-2000-backdrop.jpg new file mode 100644 index 00000000..b42ba953 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-gilmore-girls-2000-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-gilmore-girls-2000-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-gilmore-girls-2000-poster.jpg new file mode 100644 index 00000000..23b668cb Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-gilmore-girls-2000-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-ginny-georgia-2021-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-ginny-georgia-2021-backdrop.jpg new file mode 100644 index 00000000..1271d577 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-ginny-georgia-2021-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-ginny-georgia-2021-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-ginny-georgia-2021-poster.jpg new file mode 100644 index 00000000..1fca7bf6 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-ginny-georgia-2021-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-gravity-falls-2012-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-gravity-falls-2012-backdrop.jpg new file mode 100644 index 00000000..b9ef40fa Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-gravity-falls-2012-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-gravity-falls-2012-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-gravity-falls-2012-poster.jpg new file mode 100644 index 00000000..41c051e0 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-gravity-falls-2012-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-hellcats-2010-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-hellcats-2010-backdrop.jpg new file mode 100644 index 00000000..38e856b0 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-hellcats-2010-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-hellcats-2010-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-hellcats-2010-poster.jpg new file mode 100644 index 00000000..2427108b Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-hellcats-2010-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-high-potential-2024-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-high-potential-2024-backdrop.jpg new file mode 100644 index 00000000..66bb4d00 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-high-potential-2024-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-high-potential-2024-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-high-potential-2024-poster.jpg new file mode 100644 index 00000000..00a07ca7 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-high-potential-2024-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-how-to-change-your-mind-2022-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-how-to-change-your-mind-2022-backdrop.jpg new file mode 100644 index 00000000..9e4171e3 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-how-to-change-your-mind-2022-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-how-to-change-your-mind-2022-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-how-to-change-your-mind-2022-poster.jpg new file mode 100644 index 00000000..e80c7999 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-how-to-change-your-mind-2022-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-how-to-get-to-heaven-from-belfast-2026-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-how-to-get-to-heaven-from-belfast-2026-backdrop.jpg new file mode 100644 index 00000000..a605895b Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-how-to-get-to-heaven-from-belfast-2026-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-how-to-get-to-heaven-from-belfast-2026-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-how-to-get-to-heaven-from-belfast-2026-poster.jpg new file mode 100644 index 00000000..eb5fc487 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-how-to-get-to-heaven-from-belfast-2026-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-interrogation-2020-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-interrogation-2020-backdrop.jpg new file mode 100644 index 00000000..c347e016 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-interrogation-2020-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-interrogation-2020-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-interrogation-2020-poster.jpg new file mode 100644 index 00000000..f3a21b66 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-interrogation-2020-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-invincible-2021-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-invincible-2021-backdrop.jpg new file mode 100644 index 00000000..e8120387 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-invincible-2021-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-invincible-2021-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-invincible-2021-poster.jpg new file mode 100644 index 00000000..c278e37e Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-invincible-2021-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-it-s-always-sunny-in-philadelphia-2005-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-it-s-always-sunny-in-philadelphia-2005-backdrop.jpg new file mode 100644 index 00000000..cbdc6525 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-it-s-always-sunny-in-philadelphia-2005-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-it-s-always-sunny-in-philadelphia-2005-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-it-s-always-sunny-in-philadelphia-2005-poster.jpg new file mode 100644 index 00000000..652923ee Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-it-s-always-sunny-in-philadelphia-2005-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-jujutsu-kaisen-2020-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-jujutsu-kaisen-2020-backdrop.jpg new file mode 100644 index 00000000..79e7d6bd Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-jujutsu-kaisen-2020-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-jujutsu-kaisen-2020-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-jujutsu-kaisen-2020-poster.jpg new file mode 100644 index 00000000..45f5ff22 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-jujutsu-kaisen-2020-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-kaiju-no-8-2024-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-kaiju-no-8-2024-backdrop.jpg new file mode 100644 index 00000000..480b2a8e Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-kaiju-no-8-2024-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-kaiju-no-8-2024-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-kaiju-no-8-2024-poster.jpg new file mode 100644 index 00000000..062496fa Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-kaiju-no-8-2024-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-landman-2024-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-landman-2024-backdrop.jpg new file mode 100644 index 00000000..009fbfc2 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-landman-2024-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-landman-2024-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-landman-2024-poster.jpg new file mode 100644 index 00000000..3d348798 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-landman-2024-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-last-samurai-standing-2025-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-last-samurai-standing-2025-backdrop.jpg new file mode 100644 index 00000000..c85a210b Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-last-samurai-standing-2025-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-last-samurai-standing-2025-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-last-samurai-standing-2025-poster.jpg new file mode 100644 index 00000000..a9789909 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-last-samurai-standing-2025-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-lord-of-the-flies-2026-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-lord-of-the-flies-2026-backdrop.jpg new file mode 100644 index 00000000..1249a8f3 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-lord-of-the-flies-2026-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-lord-of-the-flies-2026-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-lord-of-the-flies-2026-poster.jpg new file mode 100644 index 00000000..b1229ed8 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-lord-of-the-flies-2026-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-love-death-robots-2019-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-love-death-robots-2019-backdrop.jpg new file mode 100644 index 00000000..3694bfc4 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-love-death-robots-2019-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-love-death-robots-2019-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-love-death-robots-2019-poster.jpg new file mode 100644 index 00000000..08449aa9 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-love-death-robots-2019-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-love-is-blind-2020-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-love-is-blind-2020-backdrop.jpg new file mode 100644 index 00000000..5cea5b52 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-love-is-blind-2020-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-love-is-blind-2020-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-love-is-blind-2020-poster.jpg new file mode 100644 index 00000000..62ccf357 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-love-is-blind-2020-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-maniac-2018-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-maniac-2018-backdrop.jpg new file mode 100644 index 00000000..9d46de1d Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-maniac-2018-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-maniac-2018-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-maniac-2018-poster.jpg new file mode 100644 index 00000000..a1985217 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-maniac-2018-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-maximum-pleasure-guaranteed-2026-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-maximum-pleasure-guaranteed-2026-backdrop.jpg new file mode 100644 index 00000000..20748a70 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-maximum-pleasure-guaranteed-2026-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-maximum-pleasure-guaranteed-2026-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-maximum-pleasure-guaranteed-2026-poster.jpg new file mode 100644 index 00000000..abe1b2e2 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-maximum-pleasure-guaranteed-2026-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-minx-2022-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-minx-2022-backdrop.jpg new file mode 100644 index 00000000..bd459fde Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-minx-2022-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-minx-2022-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-minx-2022-poster.jpg new file mode 100644 index 00000000..a8797fe5 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-minx-2022-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-mussolini-son-of-the-century-2024-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-mussolini-son-of-the-century-2024-backdrop.jpg new file mode 100644 index 00000000..21674163 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-mussolini-son-of-the-century-2024-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-mussolini-son-of-the-century-2024-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-mussolini-son-of-the-century-2024-poster.jpg new file mode 100644 index 00000000..925d5c49 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-mussolini-son-of-the-century-2024-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-my-hero-academia-2016-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-my-hero-academia-2016-backdrop.jpg new file mode 100644 index 00000000..f5b2f94c Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-my-hero-academia-2016-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-my-hero-academia-2016-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-my-hero-academia-2016-poster.jpg new file mode 100644 index 00000000..cf571b93 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-my-hero-academia-2016-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-neon-genesis-evangelion-1995-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-neon-genesis-evangelion-1995-backdrop.jpg new file mode 100644 index 00000000..d80e17c1 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-neon-genesis-evangelion-1995-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-neon-genesis-evangelion-1995-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-neon-genesis-evangelion-1995-poster.jpg new file mode 100644 index 00000000..f86cd698 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-neon-genesis-evangelion-1995-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-norsemen-2016-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-norsemen-2016-backdrop.jpg new file mode 100644 index 00000000..58805e67 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-norsemen-2016-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-norsemen-2016-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-norsemen-2016-poster.jpg new file mode 100644 index 00000000..e7206b88 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-norsemen-2016-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-offspring-2010-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-offspring-2010-backdrop.jpg new file mode 100644 index 00000000..bc22e11a Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-offspring-2010-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-offspring-2010-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-offspring-2010-poster.jpg new file mode 100644 index 00000000..ae305043 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-offspring-2010-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-one-piece-2023-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-one-piece-2023-backdrop.jpg new file mode 100644 index 00000000..3fa4a282 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-one-piece-2023-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-one-piece-2023-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-one-piece-2023-poster.jpg new file mode 100644 index 00000000..286e6260 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-one-piece-2023-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-only-murders-in-the-building-2021-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-only-murders-in-the-building-2021-backdrop.jpg new file mode 100644 index 00000000..0b768d54 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-only-murders-in-the-building-2021-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-only-murders-in-the-building-2021-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-only-murders-in-the-building-2021-poster.jpg new file mode 100644 index 00000000..a6b147a4 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-only-murders-in-the-building-2021-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-outlander-blood-of-my-blood-2025-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-outlander-blood-of-my-blood-2025-backdrop.jpg new file mode 100644 index 00000000..23a242da Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-outlander-blood-of-my-blood-2025-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-outlander-blood-of-my-blood-2025-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-outlander-blood-of-my-blood-2025-poster.jpg new file mode 100644 index 00000000..930943b0 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-outlander-blood-of-my-blood-2025-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-over-the-garden-wall-2014-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-over-the-garden-wall-2014-backdrop.jpg new file mode 100644 index 00000000..43ac4428 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-over-the-garden-wall-2014-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-over-the-garden-wall-2014-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-over-the-garden-wall-2014-poster.jpg new file mode 100644 index 00000000..34b1ed84 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-over-the-garden-wall-2014-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-peaky-blinders-2013-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-peaky-blinders-2013-backdrop.jpg new file mode 100644 index 00000000..da587ec3 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-peaky-blinders-2013-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-peaky-blinders-2013-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-peaky-blinders-2013-poster.jpg new file mode 100644 index 00000000..25ceea88 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-peaky-blinders-2013-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-pluribus-2025-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-pluribus-2025-backdrop.jpg new file mode 100644 index 00000000..e64c0268 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-pluribus-2025-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-pluribus-2025-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-pluribus-2025-poster.jpg new file mode 100644 index 00000000..1ea4711b Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-pluribus-2025-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-record-of-ragnarok-2021-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-record-of-ragnarok-2021-backdrop.jpg new file mode 100644 index 00000000..d68a4060 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-record-of-ragnarok-2021-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-record-of-ragnarok-2021-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-record-of-ragnarok-2021-poster.jpg new file mode 100644 index 00000000..97d481d6 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-record-of-ragnarok-2021-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-rick-and-morty-2013-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-rick-and-morty-2013-backdrop.jpg new file mode 100644 index 00000000..1c4c0ffc Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-rick-and-morty-2013-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-rick-and-morty-2013-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-rick-and-morty-2013-poster.jpg new file mode 100644 index 00000000..b95c4890 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-rick-and-morty-2013-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-ripley-2024-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-ripley-2024-backdrop.jpg new file mode 100644 index 00000000..2e7399c1 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-ripley-2024-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-ripley-2024-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-ripley-2024-poster.jpg new file mode 100644 index 00000000..de0b32dd Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-ripley-2024-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-rivals-2024-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-rivals-2024-backdrop.jpg new file mode 100644 index 00000000..fe7025e4 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-rivals-2024-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-rivals-2024-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-rivals-2024-poster.jpg new file mode 100644 index 00000000..296ac67a Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-rivals-2024-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-rooster-2026-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-rooster-2026-backdrop.jpg new file mode 100644 index 00000000..f0f7a19e Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-rooster-2026-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-rooster-2026-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-rooster-2026-poster.jpg new file mode 100644 index 00000000..b698f8a6 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-rooster-2026-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-sakamoto-days-2025-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-sakamoto-days-2025-backdrop.jpg new file mode 100644 index 00000000..3186e89a Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-sakamoto-days-2025-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-sakamoto-days-2025-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-sakamoto-days-2025-poster.jpg new file mode 100644 index 00000000..ed9358b3 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-sakamoto-days-2025-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-say-nothing-2024-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-say-nothing-2024-backdrop.jpg new file mode 100644 index 00000000..445862dc Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-say-nothing-2024-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-say-nothing-2024-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-say-nothing-2024-poster.jpg new file mode 100644 index 00000000..cf50fc09 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-say-nothing-2024-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-secret-level-2024-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-secret-level-2024-backdrop.jpg new file mode 100644 index 00000000..54d2a13e Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-secret-level-2024-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-secret-level-2024-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-secret-level-2024-poster.jpg new file mode 100644 index 00000000..1b6e67f6 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-secret-level-2024-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-sentenced-to-be-a-hero-2025-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-sentenced-to-be-a-hero-2025-backdrop.jpg new file mode 100644 index 00000000..8d081a15 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-sentenced-to-be-a-hero-2025-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-sentenced-to-be-a-hero-2025-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-sentenced-to-be-a-hero-2025-poster.jpg new file mode 100644 index 00000000..2fb1c815 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-sentenced-to-be-a-hero-2025-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-severance-2022-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-severance-2022-backdrop.jpg new file mode 100644 index 00000000..a24c03bd Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-severance-2022-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-severance-2022-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-severance-2022-poster.jpg new file mode 100644 index 00000000..5a29d6f9 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-severance-2022-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-sex-and-the-city-1998-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-sex-and-the-city-1998-backdrop.jpg new file mode 100644 index 00000000..57beacc1 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-sex-and-the-city-1998-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-sex-and-the-city-1998-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-sex-and-the-city-1998-poster.jpg new file mode 100644 index 00000000..e546cc6d Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-sex-and-the-city-1998-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-silo-2023-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-silo-2023-backdrop.jpg new file mode 100644 index 00000000..bcc1c4b7 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-silo-2023-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-silo-2023-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-silo-2023-poster.jpg new file mode 100644 index 00000000..b493bc7b Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-silo-2023-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-six-feet-under-2001-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-six-feet-under-2001-backdrop.jpg new file mode 100644 index 00000000..4d2c02ad Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-six-feet-under-2001-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-six-feet-under-2001-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-six-feet-under-2001-poster.jpg new file mode 100644 index 00000000..559d6bd1 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-six-feet-under-2001-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-skymed-2022-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-skymed-2022-backdrop.jpg new file mode 100644 index 00000000..c7ec326b Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-skymed-2022-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-skymed-2022-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-skymed-2022-poster.jpg new file mode 100644 index 00000000..2540dad7 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-skymed-2022-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-so-you-think-you-can-dance-2008-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-so-you-think-you-can-dance-2008-backdrop.jpg new file mode 100644 index 00000000..feb777b2 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-so-you-think-you-can-dance-2008-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-so-you-think-you-can-dance-2008-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-so-you-think-you-can-dance-2008-poster.jpg new file mode 100644 index 00000000..a2e91496 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-so-you-think-you-can-dance-2008-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-south-park-1997-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-south-park-1997-backdrop.jpg new file mode 100644 index 00000000..cd0aec39 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-south-park-1997-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-south-park-1997-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-south-park-1997-poster.jpg new file mode 100644 index 00000000..d8568d54 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-south-park-1997-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-spy-x-family-2022-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-spy-x-family-2022-backdrop.jpg new file mode 100644 index 00000000..8764e6eb Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-spy-x-family-2022-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-spy-x-family-2022-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-spy-x-family-2022-poster.jpg new file mode 100644 index 00000000..fc326930 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-spy-x-family-2022-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-100-2014-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-100-2014-backdrop.jpg new file mode 100644 index 00000000..8d41cb22 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-100-2014-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-100-2014-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-100-2014-poster.jpg new file mode 100644 index 00000000..4d254cb0 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-100-2014-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-abbott-and-costello-show-1952-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-abbott-and-costello-show-1952-backdrop.jpg new file mode 100644 index 00000000..53e1d593 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-abbott-and-costello-show-1952-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-abbott-and-costello-show-1952-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-abbott-and-costello-show-1952-poster.jpg new file mode 100644 index 00000000..7d6768ea Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-abbott-and-costello-show-1952-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-afterparty-2022-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-afterparty-2022-backdrop.jpg new file mode 100644 index 00000000..72ca19db Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-afterparty-2022-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-afterparty-2022-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-afterparty-2022-poster.jpg new file mode 100644 index 00000000..9beacde2 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-afterparty-2022-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-baby-sitters-club-2020-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-baby-sitters-club-2020-backdrop.jpg new file mode 100644 index 00000000..d72d7c7e Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-baby-sitters-club-2020-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-baby-sitters-club-2020-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-baby-sitters-club-2020-poster.jpg new file mode 100644 index 00000000..7e4e7be2 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-baby-sitters-club-2020-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-bear-2022-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-bear-2022-backdrop.jpg new file mode 100644 index 00000000..9c9cca57 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-bear-2022-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-bear-2022-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-bear-2022-poster.jpg new file mode 100644 index 00000000..bbf0ab28 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-bear-2022-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-beast-in-me-2025-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-beast-in-me-2025-backdrop.jpg new file mode 100644 index 00000000..e7727a79 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-beast-in-me-2025-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-beast-in-me-2025-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-beast-in-me-2025-poster.jpg new file mode 100644 index 00000000..c78c5cf0 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-beast-in-me-2025-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-bold-type-2017-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-bold-type-2017-backdrop.jpg new file mode 100644 index 00000000..dd84deab Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-bold-type-2017-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-bold-type-2017-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-bold-type-2017-poster.jpg new file mode 100644 index 00000000..f663eb8b Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-bold-type-2017-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-boys-2019-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-boys-2019-backdrop.jpg new file mode 100644 index 00000000..a834d9fb Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-boys-2019-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-boys-2019-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-boys-2019-poster.jpg new file mode 100644 index 00000000..f67ff16f Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-boys-2019-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-capture-2019-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-capture-2019-backdrop.jpg new file mode 100644 index 00000000..42256fc1 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-capture-2019-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-capture-2019-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-capture-2019-poster.jpg new file mode 100644 index 00000000..a4039011 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-capture-2019-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-diplomat-2023-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-diplomat-2023-backdrop.jpg new file mode 100644 index 00000000..b25ab5f3 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-diplomat-2023-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-diplomat-2023-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-diplomat-2023-poster.jpg new file mode 100644 index 00000000..2eb48b62 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-diplomat-2023-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-durrells-2016-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-durrells-2016-backdrop.jpg new file mode 100644 index 00000000..3f8bdeec Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-durrells-2016-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-durrells-2016-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-durrells-2016-poster.jpg new file mode 100644 index 00000000..d29448bb Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-durrells-2016-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-final-problem-2026-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-final-problem-2026-backdrop.jpg new file mode 100644 index 00000000..61a310d8 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-final-problem-2026-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-final-problem-2026-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-final-problem-2026-poster.jpg new file mode 100644 index 00000000..f0332826 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-final-problem-2026-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-four-seasons-2025-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-four-seasons-2025-backdrop.jpg new file mode 100644 index 00000000..a358664c Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-four-seasons-2025-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-four-seasons-2025-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-four-seasons-2025-poster.jpg new file mode 100644 index 00000000..fd252088 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-four-seasons-2025-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-get-down-2016-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-get-down-2016-backdrop.jpg new file mode 100644 index 00000000..1de4a3ca Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-get-down-2016-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-get-down-2016-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-get-down-2016-poster.jpg new file mode 100644 index 00000000..7bb38abd Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-get-down-2016-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-hunting-wives-2025-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-hunting-wives-2025-backdrop.jpg new file mode 100644 index 00000000..d1758fef Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-hunting-wives-2025-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-hunting-wives-2025-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-hunting-wives-2025-poster.jpg new file mode 100644 index 00000000..034273eb Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-hunting-wives-2025-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-last-of-us-2023-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-last-of-us-2023-backdrop.jpg new file mode 100644 index 00000000..fa28e38d Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-last-of-us-2023-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-last-of-us-2023-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-last-of-us-2023-poster.jpg new file mode 100644 index 00000000..7da462da Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-last-of-us-2023-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-legend-of-korra-2012-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-legend-of-korra-2012-backdrop.jpg new file mode 100644 index 00000000..ab6086bd Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-legend-of-korra-2012-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-legend-of-korra-2012-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-legend-of-korra-2012-poster.jpg new file mode 100644 index 00000000..a7086d5e Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-legend-of-korra-2012-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-lord-of-the-rings-the-rings-of-power-2022-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-lord-of-the-rings-the-rings-of-power-2022-backdrop.jpg new file mode 100644 index 00000000..0b88fd4b Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-lord-of-the-rings-the-rings-of-power-2022-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-lord-of-the-rings-the-rings-of-power-2022-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-lord-of-the-rings-the-rings-of-power-2022-poster.jpg new file mode 100644 index 00000000..dc387fcd Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-lord-of-the-rings-the-rings-of-power-2022-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-lost-flowers-of-alice-hart-2023-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-lost-flowers-of-alice-hart-2023-backdrop.jpg new file mode 100644 index 00000000..c5d17d97 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-lost-flowers-of-alice-hart-2023-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-lost-flowers-of-alice-hart-2023-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-lost-flowers-of-alice-hart-2023-poster.jpg new file mode 100644 index 00000000..71407f36 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-lost-flowers-of-alice-hart-2023-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-night-manager-2016-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-night-manager-2016-backdrop.jpg new file mode 100644 index 00000000..327aa449 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-night-manager-2016-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-night-manager-2016-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-night-manager-2016-poster.jpg new file mode 100644 index 00000000..7ab2dbf5 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-night-manager-2016-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-pitt-2025-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-pitt-2025-backdrop.jpg new file mode 100644 index 00000000..b593444a Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-pitt-2025-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-pitt-2025-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-pitt-2025-poster.jpg new file mode 100644 index 00000000..ad1ec8ff Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-pitt-2025-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-tatami-galaxy-2010-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-tatami-galaxy-2010-backdrop.jpg new file mode 100644 index 00000000..a267b4cb Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-tatami-galaxy-2010-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-tatami-galaxy-2010-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-tatami-galaxy-2010-poster.jpg new file mode 100644 index 00000000..5324dc75 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-tatami-galaxy-2010-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-walk-in-2022-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-walk-in-2022-backdrop.jpg new file mode 100644 index 00000000..e37f8d5c Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-walk-in-2022-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-walk-in-2022-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-walk-in-2022-poster.jpg new file mode 100644 index 00000000..715d0c80 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-walk-in-2022-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-white-lotus-2021-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-white-lotus-2021-backdrop.jpg new file mode 100644 index 00000000..1f747323 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-white-lotus-2021-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-white-lotus-2021-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-white-lotus-2021-poster.jpg new file mode 100644 index 00000000..2f23d1fa Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-white-lotus-2021-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-witcher-2019-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-witcher-2019-backdrop.jpg new file mode 100644 index 00000000..acca834e Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-witcher-2019-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-witcher-2019-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-witcher-2019-poster.jpg new file mode 100644 index 00000000..f5eb8f59 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-the-witcher-2019-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-undercover-2019-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-undercover-2019-backdrop.jpg new file mode 100644 index 00000000..ad972c17 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-undercover-2019-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-undercover-2019-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-undercover-2019-poster.jpg new file mode 100644 index 00000000..8611eab4 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-undercover-2019-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-upload-2020-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-upload-2020-backdrop.jpg new file mode 100644 index 00000000..f350a49c Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-upload-2020-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-upload-2020-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-upload-2020-poster.jpg new file mode 100644 index 00000000..547d3b7a Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-upload-2020-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-vinland-saga-2019-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-vinland-saga-2019-backdrop.jpg new file mode 100644 index 00000000..9ae58ec4 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-vinland-saga-2019-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-vinland-saga-2019-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-vinland-saga-2019-poster.jpg new file mode 100644 index 00000000..7d0ba17a Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-vinland-saga-2019-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-widow-s-bay-2026-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-widow-s-bay-2026-backdrop.jpg new file mode 100644 index 00000000..03b1c335 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-widow-s-bay-2026-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-widow-s-bay-2026-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-widow-s-bay-2026-poster.jpg new file mode 100644 index 00000000..8c02a0d7 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-widow-s-bay-2026-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-yellowjackets-2021-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-yellowjackets-2021-backdrop.jpg new file mode 100644 index 00000000..960c2d23 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-yellowjackets-2021-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-yellowjackets-2021-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-yellowjackets-2021-poster.jpg new file mode 100644 index 00000000..c7e16a57 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-yellowjackets-2021-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-yu-yu-hakusho-1992-backdrop.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-yu-yu-hakusho-1992-backdrop.jpg new file mode 100644 index 00000000..ba65ca2d Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-yu-yu-hakusho-1992-backdrop.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-yu-yu-hakusho-1992-poster.jpg b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-yu-yu-hakusho-1992-poster.jpg new file mode 100644 index 00000000..f5843766 Binary files /dev/null and b/wolfskin-design/src/debug/assets/wolfskin-home/assets/tv-yu-yu-hakusho-1992-poster.jpg differ diff --git a/wolfskin-design/src/debug/assets/wolfskin-home/fixture.json b/wolfskin-design/src/debug/assets/wolfskin-home/fixture.json new file mode 100644 index 00000000..450f0ece --- /dev/null +++ b/wolfskin-design/src/debug/assets/wolfskin-home/fixture.json @@ -0,0 +1 @@ +{"schemaVersion": 1, "generatedAt": "2026-11-04T20:42:12.030108+00:00", "profiles": [{"key": "justin", "name": "Justin", "initial": "J", "color": "#62c4ff", "destinations": {"Home": {"kind": "home"}, "Movies": {"kind": "library", "collection": "movies"}, "Shows": {"kind": "library", "collection": "shows"}, "Anime": {"kind": "library", "collection": "anime"}, "Discover": {"kind": "discover", "collection": "discover"}}, "movies": [{"id": "movie-the-girl-who-leapt-through-time-2006", "title": "The Girl Who Leapt Through Time", "year": 2006, "type": "movie", "runtimeSeconds": 5886, "seasonCount": null, "communityRating": 7.772, "criticRating": 87, "genres": ["Fantasy", "Animation", "Drama"], "overview": "When 17-year-old Makoto Konno gains the ability to 'leap' backwards through time, she immediately sets about improving her grades and preventing personal mishaps. However, she soon realises that changing the past\u2026", "poster": "assets/movie-the-girl-who-leapt-through-time-2006-poster.jpg", "backdrop": "assets/movie-the-girl-who-leapt-through-time-2006-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T17:39:11.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 14069, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 87, "rtCriticsLabel": "Fresh", "rtAudience": 90, "rtAudienceLabel": "Upright", "imdb": 7.6, "imdbVotes": 76917, "tmdb": 7.775, "tmdbVotes": 2345}}, {"id": "movie-locke-2014", "title": "Locke", "year": 2014, "type": "movie", "runtimeSeconds": 5090, "seasonCount": null, "communityRating": 6.891, "criticRating": 91, "genres": ["Drama", "Thriller"], "overview": "Ivan Locke has worked hard to craft a good life for himself. Tonight, that life will collapse around him. On the eve of the biggest challenge of his career, Ivan receives a phone call that sets in motion a series of\u2026", "poster": "assets/movie-locke-2014-poster.jpg", "backdrop": "assets/movie-locke-2014-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T17:38:48.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 210479, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 90, "rtCriticsLabel": "Certified Fresh", "rtAudience": 72, "rtAudienceLabel": "Upright", "imdb": 7.1, "imdbVotes": 171265, "tmdb": 6.889, "tmdbVotes": 3088}}, {"id": "movie-look-who-s-back-2015", "title": "Look Who's Back", "year": 2015, "type": "movie", "runtimeSeconds": 6936, "seasonCount": null, "communityRating": 6.793, "criticRating": null, "genres": ["Comedy"], "overview": "When Adolf Hitler reawakens at the site of his former bunker in present-day Berlin, he is mistaken for a comedian and quickly becomes a media phenomenon.", "poster": "assets/movie-look-who-s-back-2015-poster.jpg", "backdrop": "assets/movie-look-who-s-back-2015-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:27:48.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 318917, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": 81, "rtAudienceLabel": "Upright", "imdb": 7, "imdbVotes": 54672, "tmdb": 6.796, "tmdbVotes": 1990}}, {"id": "movie-memories-1995", "title": "Memories", "year": 1995, "type": "movie", "runtimeSeconds": 6805, "seasonCount": null, "communityRating": 7.465, "criticRating": null, "genres": ["Fantasy", "Animation", "Science Fiction"], "overview": "Three back-to-back anime films by three different directors make up this sci-fi trilogy three years in the making.", "poster": "assets/movie-memories-1995-poster.jpg", "backdrop": "assets/movie-memories-1995-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-30T21:36:03.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 42994, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": 82, "rtAudienceLabel": "Upright", "imdb": 7.5, "imdbVotes": 26638, "tmdb": 7.459, "tmdbVotes": 622}}, {"id": "movie-reincarnated-2012", "title": "Reincarnated", "year": 2012, "type": "movie", "runtimeSeconds": 5759, "seasonCount": null, "communityRating": 6.145, "criticRating": 28, "genres": ["Music", "Documentary"], "overview": "Evolution as an artist is often times what separates legends from the more mundane. After being heavily influenced by his experience in Jamaica \u2013 and his subsequent name change from Snoop Dogg to Snoop Lion \u2013 the LBC\u2026", "poster": "assets/movie-reincarnated-2012-poster.jpg", "backdrop": "assets/movie-reincarnated-2012-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:27:26.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 123431, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 28, "rtCriticsLabel": "Rotten", "rtAudience": 41, "rtAudienceLabel": "Spilled", "imdb": 6.2, "imdbVotes": 2563, "tmdb": 6.1, "tmdbVotes": 69}}, {"id": "movie-shipwrecked-nightmare-at-sea-2026", "title": "Shipwrecked: Nightmare at Sea", "year": 2026, "type": "movie", "runtimeSeconds": 5385, "seasonCount": null, "communityRating": 7.181, "criticRating": null, "genres": ["Documentary"], "overview": "Never-before-seen footage and survivor accounts trace the 2012 shipwreck of a luxury cruise and the disaster that ensued, in this immersive documentary.", "poster": "assets/movie-shipwrecked-nightmare-at-sea-2026-poster.jpg", "backdrop": "assets/movie-shipwrecked-nightmare-at-sea-2026-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-20T20:11:43.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 1715492, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": 6.5, "imdbVotes": 5080, "tmdb": 7.172, "tmdbVotes": 87}}, {"id": "movie-steins-gate-the-movie-load-region-of-deja-vu-2013", "title": "Steins;Gate: The Movie - Load Region of D\u00e9j\u00e0 Vu", "year": 2013, "type": "movie", "runtimeSeconds": 5403, "seasonCount": null, "communityRating": 7.8, "criticRating": null, "genres": ["Animation", "Mystery", "Sci-Fi"], "overview": "After the events of the anime, Rintarou begins to feel the repercussions of extensive time travel, and eventually completely fades from reality. Kurisu, being the only companion to remember him, now must find a way\u2026", "poster": "assets/movie-steins-gate-the-movie-load-region-of-deja-vu-2013-poster.jpg", "backdrop": "assets/movie-steins-gate-the-movie-load-region-of-deja-vu-2013-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-22T14:55:54.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}], "shows": [{"id": "tv-andor-2022", "title": "Andor", "year": 2022, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 8.293, "criticRating": null, "genres": ["Sci-Fi & Fantasy", "Action & Adventure", "Drama"], "overview": "In an era filled with danger, deception and intrigue, Cassian Andor will discover the difference he can make in the struggle against the tyrannical Galactic Empire. He embarks on a path that is destined to turn him\u2026", "poster": "assets/tv-andor-2022-poster.jpg", "backdrop": "assets/tv-andor-2022-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0432996Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 83867, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 96, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.321, "tmdbVotes": 2312}}, {"id": "tv-the-boys-2019", "title": "The Boys", "year": 2019, "type": "tv", "runtimeSeconds": null, "seasonCount": 5, "communityRating": 8.443, "criticRating": null, "genres": ["Sci-Fi & Fantasy", "Action & Adventure"], "overview": "A group of vigilantes known informally as \u201cThe Boys\u201d set out to take down corrupt superheroes with no more than blue-collar grit and a willingness to fight dirty.", "poster": "assets/tv-the-boys-2019-poster.jpg", "backdrop": "assets/tv-the-boys-2019-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0410131Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 76479, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 92, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.4, "tmdbVotes": 13628}}, {"id": "tv-californication-2007", "title": "Californication", "year": 2007, "type": "tv", "runtimeSeconds": 1680, "seasonCount": 7, "communityRating": 7.632, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "A self-loathing, alcoholic writer attempts to repair his damaged relationships with his daughter and her mother while combating sex addiction, a budding drug problem, and the seeming inability to avoid making bad\u2026", "poster": "assets/tv-californication-2007-poster.jpg", "backdrop": "assets/tv-californication-2007-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0428037Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 1215, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 57, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.62, "tmdbVotes": 1406}}, {"id": "tv-firefly-2002", "title": "Firefly", "year": 2002, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 8.347, "criticRating": null, "genres": ["Drama", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "In the year 2517, the universe is a vast frontier where lawlessness reigns and adventure awaits! Join Captain Malcolm Reynolds and his ragtag crew aboard the spaceship Serenity as they navigate the fringes of\u2026", "poster": "assets/tv-firefly-2002-poster.jpg", "backdrop": "assets/tv-firefly-2002-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-20T11:40:08.4202369Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 1437, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 77, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.351, "tmdbVotes": 2550}}, {"id": "tv-fleabag-2016", "title": "Fleabag", "year": 2016, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 8.278, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "A portrait into the mind of a dry-witted, sexual, angry, porn-watching, grief-riddled woman, trying to make sense of the world. As she hurls herself headlong at modern living, Fleabag is thrown roughly up against the\u2026", "poster": "assets/tv-fleabag-2016-poster.jpg", "backdrop": "assets/tv-fleabag-2016-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T17:42:25.4848214Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 67070, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.3, "tmdbVotes": 1993}}, {"id": "tv-gravity-falls-2012", "title": "Gravity Falls", "year": 2012, "type": "tv", "runtimeSeconds": 1320, "seasonCount": 2, "communityRating": 8.619, "criticRating": null, "genres": ["Action & Adventure", "Animation", "Comedy"], "overview": "Twin brother and sister Dipper and Mabel Pines are in for an unexpected adventure when they spend the summer helping their great uncle Stan run a tourist trap in the mysterious town of Gravity Falls, Oregon.", "poster": "assets/tv-gravity-falls-2012-poster.jpg", "backdrop": "assets/tv-gravity-falls-2012-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0435827Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 40075, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.624, "tmdbVotes": 3647}}, {"id": "tv-invincible-2021", "title": "INVINCIBLE", "year": 2021, "type": "tv", "runtimeSeconds": null, "seasonCount": 4, "communityRating": 8.638, "criticRating": null, "genres": ["Animation", "Drama", "Sci-Fi & Fantasy"], "overview": "Mark Grayson is a normal teenager except for the fact that his father is the most powerful superhero on the planet. Shortly after his seventeenth birthday, Mark begins to develop powers of his own and enters into his\u2026", "poster": "assets/tv-invincible-2021-poster.jpg", "backdrop": "assets/tv-invincible-2021-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.040159Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 95557, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 99, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.6, "tmdbVotes": 6155}}, {"id": "tv-the-legend-of-korra-2012", "title": "The Legend of Korra", "year": 2012, "type": "tv", "runtimeSeconds": 1380, "seasonCount": 4, "communityRating": 8.2, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "Avatar Korra, a headstrong, rebellious, feisty young woman who continually challenges and breaks with tradition, is on her quest to become a fully realized Avatar. In this story, the Avatar struggles to find balance\u2026", "poster": "assets/tv-the-legend-of-korra-2012-poster.jpg", "backdrop": "assets/tv-the-legend-of-korra-2012-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-20T00:19:23.2494945Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 33880, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 88, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.221, "tmdbVotes": 2482}}, {"id": "tv-love-death-robots-2019", "title": "Love, Death & Robots", "year": 2019, "type": "tv", "runtimeSeconds": null, "seasonCount": 4, "communityRating": 8.205, "criticRating": null, "genres": ["Animation", "Sci-Fi & Fantasy"], "overview": "Terrifying creatures, wicked surprises and dark comedy converge in this NSFW anthology of animated stories presented by Tim Miller and David Fincher.", "poster": "assets/tv-love-death-robots-2019-poster.jpg", "backdrop": "assets/tv-love-death-robots-2019-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-20T11:31:20.8818757Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 86831, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 89, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.203, "tmdbVotes": 4238}}, {"id": "tv-norsemen-2016", "title": "Norsemen", "year": 2016, "type": "tv", "runtimeSeconds": 1800, "seasonCount": 3, "communityRating": 7.177, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "Norsemen is an epic and humorous drama series set in the Viking Age. The residents of an 8th-century Viking village experience political rivalry, social change and innovations that upend their culture and way of life.", "poster": "assets/tv-norsemen-2016-poster.jpg", "backdrop": "assets/tv-norsemen-2016-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.034182Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 68126, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.2, "tmdbVotes": 233}}, {"id": "tv-rick-and-morty-2013", "title": "Rick and Morty", "year": 2013, "type": "tv", "runtimeSeconds": null, "seasonCount": 9, "communityRating": 8.679, "criticRating": null, "genres": ["Animation", "Comedy", "Sci-Fi & Fantasy"], "overview": "Follows a sociopathic genius scientist who drags his inherently timid grandson on adventures across the universe.", "poster": "assets/tv-rick-and-morty-2013-poster.jpg", "backdrop": "assets/tv-rick-and-morty-2013-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0419581Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 60625, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 91, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.7, "tmdbVotes": 11548}}, {"id": "tv-secret-level-2024", "title": "Secret Level", "year": 2024, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.411, "criticRating": null, "genres": ["Animation", "Sci-Fi & Fantasy", "Action & Adventure"], "overview": "Adult animated series of original short stories which are set within the worlds of beloved video games. Each episode serves as a gateway to a new adventure, unlocking exciting worlds from beloved gaming classics and\u2026", "poster": "assets/tv-secret-level-2024-poster.jpg", "backdrop": "assets/tv-secret-level-2024-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0336417Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 261579, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 65, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.392, "tmdbVotes": 612}}, {"id": "tv-silo-2023", "title": "Silo", "year": 2023, "type": "tv", "runtimeSeconds": null, "seasonCount": 3, "communityRating": 8.178, "criticRating": null, "genres": ["Sci-Fi & Fantasy", "Drama"], "overview": "In a ruined and toxic future, thousands live in a giant silo deep underground. After its sheriff breaks a cardinal rule and residents die mysteriously, engineer Juliette starts to uncover shocking secrets and the\u2026", "poster": "assets/tv-silo-2023-poster.jpg", "backdrop": "assets/tv-silo-2023-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0346526Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 125988, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 92, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.232, "tmdbVotes": 2881}}, {"id": "tv-south-park-1997", "title": "South Park", "year": 1997, "type": "tv", "runtimeSeconds": null, "seasonCount": 29, "communityRating": 8.336, "criticRating": null, "genres": ["Animation", "Comedy"], "overview": "Follow the misadventures of four irreverent grade-schoolers in the quiet, dysfunctional town of South Park, Colorado.", "poster": "assets/tv-south-park-1997-poster.jpg", "backdrop": "assets/tv-south-park-1997-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0456124Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 2190, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 80, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.332, "tmdbVotes": 5250}}], "anime": [{"id": "tv-bleach-2004", "title": "Bleach", "year": 2004, "type": "tv", "runtimeSeconds": 1440, "seasonCount": 17, "communityRating": 8.363, "criticRating": null, "genres": ["Action & Adventure", "Animation", "Sci-Fi & Fantasy"], "overview": "For as long as he can remember, Ichigo Kurosaki has been able to see ghosts. But when he meets Rukia, a Soul Reaper who battles evil spirits known as Hollows, he finds his life is changed forever. Now, with a\u2026", "poster": "assets/tv-bleach-2004-poster.jpg", "backdrop": "assets/tv-bleach-2004-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0359827Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 30984, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.4, "tmdbVotes": 2331}}, {"id": "tv-chainsaw-man-2022", "title": "Chainsaw Man", "year": 2022, "type": "tv", "runtimeSeconds": 1440, "seasonCount": 1, "communityRating": 8.515, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "Denji has a simple dream\u2014to live a happy and peaceful life, spending time with a girl he likes. This is a far cry from reality, however, as Denji is forced by the yakuza into killing devils in order to pay off his\u2026", "poster": "assets/tv-chainsaw-man-2022-poster.jpg", "backdrop": "assets/tv-chainsaw-man-2022-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-20T22:28:13.2095501Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 114410, "artwork": {"posterKind": "center_crop", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 97, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.508, "tmdbVotes": 2364}}, {"id": "tv-cyberpunk-edgerunners-2022", "title": "Cyberpunk: Edgerunners", "year": 2022, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 8.466, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "In a dystopia riddled with corruption and cybernetic implants, a talented but reckless street kid strives to become a mercenary outlaw \u2014 an edgerunner.", "poster": "assets/tv-cyberpunk-edgerunners-2022-poster.jpg", "backdrop": "assets/tv-cyberpunk-edgerunners-2022-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-20T22:28:13.2093107Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 105248, "artwork": {"posterKind": "center_crop", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 89, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.507, "tmdbVotes": 2132}}, {"id": "tv-dan-da-dan-2024", "title": "Dan Da Dan", "year": 2024, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 8.538, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Comedy"], "overview": "In a bet to prove whether ghosts or aliens exist, two high schoolers face terrifying paranormal threats, gain superpowers and maybe even fall in love?!", "poster": "assets/tv-dan-da-dan-2024-poster.jpg", "backdrop": "assets/tv-dan-da-dan-2024-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-22T10:31:16.2652252Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 240411, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.517, "tmdbVotes": 986}}, {"id": "tv-dr-stone-2019", "title": "Dr. STONE", "year": 2019, "type": "tv", "runtimeSeconds": 1440, "seasonCount": 4, "communityRating": 8.541, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Comedy"], "overview": "One fateful day, all of humanity was petrified by a blinding flash of light. After several millennia, high schooler Taiju awakens and finds himself lost in a world of statues. However, he\u2019s not alone! His\u2026", "poster": "assets/tv-dr-stone-2019-poster.jpg", "backdrop": "assets/tv-dr-stone-2019-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-20T22:28:13.2091579Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 86031, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.53, "tmdbVotes": 1814}}, {"id": "tv-frieren-beyond-journey-s-end-2023", "title": "Frieren: Beyond Journey's End", "year": 2023, "type": "tv", "runtimeSeconds": 1500, "seasonCount": 2, "communityRating": 8.803, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Drama"], "overview": "After the party of heroes defeated the Demon King, they restored peace to the land and returned to lives of solitude. Generations pass, and the elven mage Frieren comes face to face with humanity\u2019s mortality. She\u2026", "poster": "assets/tv-frieren-beyond-journey-s-end-2023-poster.jpg", "backdrop": "assets/tv-frieren-beyond-journey-s-end-2023-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-20T22:28:13.2094435Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 209867, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.826, "tmdbVotes": 1016}}, {"id": "tv-fullmetal-alchemist-brotherhood-2009", "title": "Fullmetal Alchemist: Brotherhood", "year": 2009, "type": "tv", "runtimeSeconds": 1500, "seasonCount": 1, "communityRating": 8.7, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "Disregard for alchemy\u2019s laws ripped half of Edward Elric\u2019s limbs from his body and left his brother Alphonse\u2019s soul clinging to a suit of armor. To restore what was lost, the brothers seek the Philosopher\u2019s Stone.\u2026", "poster": "assets/tv-fullmetal-alchemist-brotherhood-2009-poster.jpg", "backdrop": "assets/tv-fullmetal-alchemist-brotherhood-2009-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-20T10:27:12.3573939Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 31911, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.7, "tmdbVotes": 2633}}, {"id": "tv-jujutsu-kaisen-2020", "title": "JUJUTSU KAISEN", "year": 2020, "type": "tv", "runtimeSeconds": 1440, "seasonCount": 3, "communityRating": 8.583, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "Yuji Itadori is a boy with tremendous physical strength, though he lives a completely ordinary high school life. One day, to save a classmate who has been attacked by curses, he eats the finger of Ryomen Sukuna,\u2026", "poster": "assets/tv-jujutsu-kaisen-2020-poster.jpg", "backdrop": "assets/tv-jujutsu-kaisen-2020-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-20T22:28:13.207573Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 95479, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.574, "tmdbVotes": 4735}}, {"id": "tv-kaiju-no-8-2024", "title": "Kaiju No. 8", "year": 2024, "type": "tv", "runtimeSeconds": 1440, "seasonCount": 2, "communityRating": 8.436, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "In a world plagued by creatures known as Kaiju, Kafka Hibino aspired to enlist in The Defense Force. He makes a promise to enlist with his childhood friend, Mina Ashiro. Soon, life takes them in separate ways. While\u2026", "poster": "assets/tv-kaiju-no-8-2024-poster.jpg", "backdrop": "assets/tv-kaiju-no-8-2024-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-22T10:31:16.2646566Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 207468, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.4, "tmdbVotes": 836}}, {"id": "tv-my-hero-academia-2016", "title": "My Hero Academia", "year": 2016, "type": "tv", "runtimeSeconds": 1440, "seasonCount": 8, "communityRating": 8.607, "criticRating": null, "genres": ["Action & Adventure", "Animation", "Sci-Fi & Fantasy"], "overview": "After he saves a bully from a Villain, a normal student is granted a superpower that allows him to attend a high school training academy for Heroes.", "poster": "assets/tv-my-hero-academia-2016-poster.jpg", "backdrop": "assets/tv-my-hero-academia-2016-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-20T22:28:13.2089315Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 65930, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.6, "tmdbVotes": 5426}}, {"id": "tv-neon-genesis-evangelion-1995", "title": "Neon Genesis Evangelion", "year": 1995, "type": "tv", "runtimeSeconds": 1500, "seasonCount": 1, "communityRating": 8.568, "criticRating": null, "genres": ["Sci-Fi & Fantasy", "Animation", "Drama"], "overview": "At the turn of the century, the Angels returned to Earth, seeking to wipe out humanity in an apocalyptic fury. Devastated, mankind's last remnants moved underground to wait for the day when the Angels would come back\u2026", "poster": "assets/tv-neon-genesis-evangelion-1995-poster.jpg", "backdrop": "assets/tv-neon-genesis-evangelion-1995-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0340629Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 890, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.56, "tmdbVotes": 2205}}, {"id": "tv-record-of-ragnarok-2021", "title": "Record of Ragnarok", "year": 2021, "type": "tv", "runtimeSeconds": null, "seasonCount": 3, "communityRating": 8.402, "criticRating": null, "genres": ["Action & Adventure", "Animation", "Sci-Fi & Fantasy"], "overview": "Before eradicating humankind from the world, the gods give them one last chance to prove themselves worthy of survival. Let the Ragnarok battles begin.", "poster": "assets/tv-record-of-ragnarok-2021-poster.jpg", "backdrop": "assets/tv-record-of-ragnarok-2021-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-20T22:28:13.2085766Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 114868, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.403, "tmdbVotes": 1929}}, {"id": "tv-sakamoto-days-2025", "title": "SAKAMOTO DAYS", "year": 2025, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 8.071, "criticRating": null, "genres": ["Animation", "Comedy", "Action & Adventure"], "overview": "Once the greatest hitman of all, Taro Sakamoto retired in the name of love. But when his past catches up, he must fight to protect his beloved family.", "poster": "assets/tv-sakamoto-days-2025-poster.jpg", "backdrop": "assets/tv-sakamoto-days-2025-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-22T10:31:16.266066Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 207332, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.057, "tmdbVotes": 375}}, {"id": "tv-sentenced-to-be-a-hero-2025", "title": "Sentenced to Be a Hero", "year": 2025, "type": "tv", "runtimeSeconds": 1440, "seasonCount": 1, "communityRating": 8.338, "criticRating": null, "genres": ["Animation", "Sci-Fi & Fantasy", "Action & Adventure"], "overview": "In a world where heroism is a punishment, Xylo Forbartz, a condemned goddess killer, battles endless hordes of monstrous abominations as part of Penal Hero Unit 9004. Death is no escape, only a cycle of resurrection\u2026", "poster": "assets/tv-sentenced-to-be-a-hero-2025-poster.jpg", "backdrop": "assets/tv-sentenced-to-be-a-hero-2025-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-22T10:31:16.2666791Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 249907, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.244, "tmdbVotes": 129}}, {"id": "tv-spy-x-family-2022", "title": "SPY x FAMILY", "year": 2022, "type": "tv", "runtimeSeconds": 1440, "seasonCount": 3, "communityRating": 8.506, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Comedy"], "overview": "A spy, an assassin and a telepath come together to pose as a family, each for their own reasons, while hiding their true identities from each other.", "poster": "assets/tv-spy-x-family-2022-poster.jpg", "backdrop": "assets/tv-spy-x-family-2022-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-22T10:31:16.2670364Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 120089, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.5, "tmdbVotes": 2382}}, {"id": "tv-the-tatami-galaxy-2010", "title": "The Tatami Galaxy", "year": 2010, "type": "tv", "runtimeSeconds": 1500, "seasonCount": 2, "communityRating": 8.271, "criticRating": null, "genres": ["Animation", "Comedy", "Drama"], "overview": "When a college dropout stops for a late night bite at a mysterious ramen stand, he crosses paths with a self-proclaimed deity of matrimony. This bizarre meeting sends the young man hurtling through a horrifying\u2026", "poster": "assets/tv-the-tatami-galaxy-2010-poster.jpg", "backdrop": "assets/tv-the-tatami-galaxy-2010-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-18T05:52:51.0023256Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 36243, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.3, "tmdbVotes": 152}}, {"id": "tv-vinland-saga-2019", "title": "Vinland Saga", "year": 2019, "type": "tv", "runtimeSeconds": 1500, "seasonCount": 2, "communityRating": 8.527, "criticRating": null, "genres": ["Animation", "War & Politics", "Action & Adventure"], "overview": "For a thousand years, the Vikings have made quite a name and reputation for themselves as the strongest families with a thirst for violence. Thorfinn, the son of one of the Vikings' greatest warriors, spends his\u2026", "poster": "assets/tv-vinland-saga-2019-poster.jpg", "backdrop": "assets/tv-vinland-saga-2019-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-20T22:28:13.207389Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 88803, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.509, "tmdbVotes": 1064}}, {"id": "tv-yu-yu-hakusho-1992", "title": "Yu Yu Hakusho", "year": 1992, "type": "tv", "runtimeSeconds": 1440, "seasonCount": 4, "communityRating": 8.5, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "After dying to save a boy, delinquent tough guy Yusuke Urameshi is granted another chance at life by redeeming himself as a \"Spirit Detective.\"", "poster": "assets/tv-yu-yu-hakusho-1992-poster.jpg", "backdrop": "assets/tv-yu-yu-hakusho-1992-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-19T21:46:01.5733049Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 30669, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.475, "tmdbVotes": 519}}], "resume": [], "nextUp": [{"id": "episode-three-monsters-1992-s1e6", "title": "Three Monsters", "year": 1992, "type": "episode", "runtimeSeconds": 1421, "seasonCount": null, "communityRating": 7.4, "criticRating": null, "genres": ["Animation", "Action", "Adventure"], "overview": "Yusuke receives his first real case as Spirit Detective. Three demon thieves have muscled their way into King Yama's sacred vault, stealing the three Artifacts of Darkness. Yusuke must recover the artifacts and bring\u2026", "poster": "assets/episode-three-monsters-1992-s1e6-poster.jpg", "backdrop": "assets/episode-three-monsters-1992-s1e6-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-19T21:59:21.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "Yu Yu Hakusho", "seasonNumber": 1, "episodeNumber": 6, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}, {"id": "episode-all-hands-on-deck-class-1-a-2021-s5e1", "title": "All Hands on Deck! Class 1-A", "year": 2021, "type": "episode", "runtimeSeconds": 1433, "seasonCount": null, "communityRating": 6.938, "criticRating": null, "genres": ["Animation", "Action", "Adventure"], "overview": "There's an emergency drill at U.A. High School, and Class 1-A is requested to report for duty!", "poster": "assets/episode-all-hands-on-deck-class-1-a-2021-s5e1-poster.jpg", "backdrop": "assets/episode-all-hands-on-deck-class-1-a-2021-s5e1-backdrop.jpg", "played": false, "playCount": 2, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-22T04:04:50.0000000Z", "lastPlayedAt": "2026-10-19T17:47:09.3028025Z", "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "My Hero Academia", "seasonNumber": 5, "episodeNumber": 1, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}, {"id": "episode-erickerhead-2026-s9e6", "title": "Erickerhead", "year": 2026, "type": "episode", "runtimeSeconds": 1357, "seasonCount": null, "communityRating": 8.196, "criticRating": null, "genres": [], "overview": "Rick's stomach is mad, broh. But it's all-you-can-eat-and-drink here, broh!", "poster": "assets/episode-erickerhead-2026-s9e6-poster.jpg", "backdrop": "assets/episode-erickerhead-2026-s9e6-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-28T10:23:23.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "Rick and Morty", "seasonNumber": 9, "episodeNumber": 6, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}, {"id": "episode-girls-interrupted-2007-s1e7", "title": "Girls, Interrupted", "year": 2007, "type": "episode", "runtimeSeconds": 1642, "seasonCount": null, "communityRating": 7.4, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "Hank is disturbed by Becca's negative reaction towards the concept of happy endings, even more so when he finds out that it is partially his fault.\nMarcy comes up with the idea of a threesome with Charlie and Dani,\u2026", "poster": "assets/episode-girls-interrupted-2007-s1e7-poster.jpg", "backdrop": "assets/episode-girls-interrupted-2007-s1e7-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-05T02:46:18.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "Californication", "seasonNumber": 1, "episodeNumber": 7, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}, {"id": "episode-announcement-2022-s1e7", "title": "Announcement", "year": 2022, "type": "episode", "runtimeSeconds": 3012, "seasonCount": null, "communityRating": 7.8, "criticRating": null, "genres": ["Action", "Adventure", "Drama"], "overview": "The repercussions of the Aldhani heist reach all the way to Coruscant, while Cassian returns home.", "poster": "assets/episode-announcement-2022-s1e7-poster.jpg", "backdrop": "assets/episode-announcement-2022-s1e7-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T12:56:24.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "Andor", "seasonNumber": 1, "episodeNumber": 7, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}, {"id": "episode-south-american-biker-gangs-2026-s29e1", "title": "South American Biker Gangs", "year": 2026, "type": "episode", "runtimeSeconds": 1335, "seasonCount": null, "communityRating": 6.4, "criticRating": null, "genres": ["Animation", "Comedy"], "overview": "When e-bikes arrive in South America, the boys take over the streets and the parents of South America can hardly recognize South America.", "poster": "assets/episode-south-american-biker-gangs-2026-s29e1-poster.jpg", "backdrop": "assets/episode-south-american-biker-gangs-2026-s29e1-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-01T06:40:46.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "South Park", "seasonNumber": 29, "episodeNumber": 1, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}], "recentlyAdded": [{"id": "movie-steins-gate-the-movie-load-region-of-deja-vu-2013", "title": "Steins;Gate: The Movie - Load Region of D\u00e9j\u00e0 Vu", "year": 2013, "type": "movie", "runtimeSeconds": 5403, "seasonCount": null, "communityRating": 7.8, "criticRating": null, "genres": ["Animation", "Mystery", "Sci-Fi"], "overview": "After the events of the anime, Rintarou begins to feel the repercussions of extensive time travel, and eventually completely fades from reality. Kurisu, being the only companion to remember him, now must find a way\u2026", "poster": "assets/movie-steins-gate-the-movie-load-region-of-deja-vu-2013-poster.jpg", "backdrop": "assets/movie-steins-gate-the-movie-load-region-of-deja-vu-2013-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-22T14:55:54.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}, {"id": "tv-yu-yu-hakusho-1992", "title": "Yu Yu Hakusho", "year": 1992, "type": "tv", "runtimeSeconds": 1440, "seasonCount": 4, "communityRating": 8.5, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "After dying to save a boy, delinquent tough guy Yusuke Urameshi is granted another chance at life by redeeming himself as a \"Spirit Detective.\"", "poster": "assets/tv-yu-yu-hakusho-1992-poster.jpg", "backdrop": "assets/tv-yu-yu-hakusho-1992-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-19T21:46:01.5733049Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 30669, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.475, "tmdbVotes": 519}}, {"id": "movie-memories-1995", "title": "Memories", "year": 1995, "type": "movie", "runtimeSeconds": 6805, "seasonCount": null, "communityRating": 7.465, "criticRating": null, "genres": ["Fantasy", "Animation", "Science Fiction"], "overview": "Three back-to-back anime films by three different directors make up this sci-fi trilogy three years in the making.", "poster": "assets/movie-memories-1995-poster.jpg", "backdrop": "assets/movie-memories-1995-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-30T21:36:03.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 42994, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": 82, "rtAudienceLabel": "Upright", "imdb": 7.5, "imdbVotes": 26638, "tmdb": 7.459, "tmdbVotes": 622}}, {"id": "tv-firefly-2002", "title": "Firefly", "year": 2002, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 8.347, "criticRating": null, "genres": ["Drama", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "In the year 2517, the universe is a vast frontier where lawlessness reigns and adventure awaits! Join Captain Malcolm Reynolds and his ragtag crew aboard the spaceship Serenity as they navigate the fringes of\u2026", "poster": "assets/tv-firefly-2002-poster.jpg", "backdrop": "assets/tv-firefly-2002-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-20T11:40:08.4202369Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 1437, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 77, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.351, "tmdbVotes": 2550}}, {"id": "tv-love-death-robots-2019", "title": "Love, Death & Robots", "year": 2019, "type": "tv", "runtimeSeconds": null, "seasonCount": 4, "communityRating": 8.205, "criticRating": null, "genres": ["Animation", "Sci-Fi & Fantasy"], "overview": "Terrifying creatures, wicked surprises and dark comedy converge in this NSFW anthology of animated stories presented by Tim Miller and David Fincher.", "poster": "assets/tv-love-death-robots-2019-poster.jpg", "backdrop": "assets/tv-love-death-robots-2019-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-20T11:31:20.8818757Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 86831, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 89, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.203, "tmdbVotes": 4238}}, {"id": "tv-the-legend-of-korra-2012", "title": "The Legend of Korra", "year": 2012, "type": "tv", "runtimeSeconds": 1380, "seasonCount": 4, "communityRating": 8.2, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "Avatar Korra, a headstrong, rebellious, feisty young woman who continually challenges and breaks with tradition, is on her quest to become a fully realized Avatar. In this story, the Avatar struggles to find balance\u2026", "poster": "assets/tv-the-legend-of-korra-2012-poster.jpg", "backdrop": "assets/tv-the-legend-of-korra-2012-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-20T00:19:23.2494945Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 33880, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 88, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.221, "tmdbVotes": 2482}}, {"id": "tv-spy-x-family-2022", "title": "SPY x FAMILY", "year": 2022, "type": "tv", "runtimeSeconds": 1440, "seasonCount": 3, "communityRating": 8.506, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Comedy"], "overview": "A spy, an assassin and a telepath come together to pose as a family, each for their own reasons, while hiding their true identities from each other.", "poster": "assets/tv-spy-x-family-2022-poster.jpg", "backdrop": "assets/tv-spy-x-family-2022-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-22T10:31:16.2670364Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 120089, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.5, "tmdbVotes": 2382}}, {"id": "tv-sentenced-to-be-a-hero-2025", "title": "Sentenced to Be a Hero", "year": 2025, "type": "tv", "runtimeSeconds": 1440, "seasonCount": 1, "communityRating": 8.338, "criticRating": null, "genres": ["Animation", "Sci-Fi & Fantasy", "Action & Adventure"], "overview": "In a world where heroism is a punishment, Xylo Forbartz, a condemned goddess killer, battles endless hordes of monstrous abominations as part of Penal Hero Unit 9004. Death is no escape, only a cycle of resurrection\u2026", "poster": "assets/tv-sentenced-to-be-a-hero-2025-poster.jpg", "backdrop": "assets/tv-sentenced-to-be-a-hero-2025-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-22T10:31:16.2666791Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 249907, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.244, "tmdbVotes": 129}}, {"id": "tv-sakamoto-days-2025", "title": "SAKAMOTO DAYS", "year": 2025, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 8.071, "criticRating": null, "genres": ["Animation", "Comedy", "Action & Adventure"], "overview": "Once the greatest hitman of all, Taro Sakamoto retired in the name of love. But when his past catches up, he must fight to protect his beloved family.", "poster": "assets/tv-sakamoto-days-2025-poster.jpg", "backdrop": "assets/tv-sakamoto-days-2025-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-22T10:31:16.266066Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 207332, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.057, "tmdbVotes": 375}}, {"id": "tv-dan-da-dan-2024", "title": "Dan Da Dan", "year": 2024, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 8.538, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Comedy"], "overview": "In a bet to prove whether ghosts or aliens exist, two high schoolers face terrifying paranormal threats, gain superpowers and maybe even fall in love?!", "poster": "assets/tv-dan-da-dan-2024-poster.jpg", "backdrop": "assets/tv-dan-da-dan-2024-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-22T10:31:16.2652252Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 240411, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.517, "tmdbVotes": 986}}, {"id": "tv-kaiju-no-8-2024", "title": "Kaiju No. 8", "year": 2024, "type": "tv", "runtimeSeconds": 1440, "seasonCount": 2, "communityRating": 8.436, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "In a world plagued by creatures known as Kaiju, Kafka Hibino aspired to enlist in The Defense Force. He makes a promise to enlist with his childhood friend, Mina Ashiro. Soon, life takes them in separate ways. While\u2026", "poster": "assets/tv-kaiju-no-8-2024-poster.jpg", "backdrop": "assets/tv-kaiju-no-8-2024-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-22T10:31:16.2646566Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 207468, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.4, "tmdbVotes": 836}}, {"id": "tv-chainsaw-man-2022", "title": "Chainsaw Man", "year": 2022, "type": "tv", "runtimeSeconds": 1440, "seasonCount": 1, "communityRating": 8.515, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "Denji has a simple dream\u2014to live a happy and peaceful life, spending time with a girl he likes. This is a far cry from reality, however, as Denji is forced by the yakuza into killing devils in order to pay off his\u2026", "poster": "assets/tv-chainsaw-man-2022-poster.jpg", "backdrop": "assets/tv-chainsaw-man-2022-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-20T22:28:13.2095501Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 114410, "artwork": {"posterKind": "center_crop", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 97, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.508, "tmdbVotes": 2364}}], "discover": [{"id": "movie-the-amazing-spider-man-2012", "title": "The Amazing Spider-Man", "year": 2012, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action", "Adventure", "Science Fiction"], "overview": "A teenage Peter Parker grapples with both high school and amazing super-human crises as his alter-ego Spider-Man.", "poster": "assets/movie-the-amazing-spider-man-2012-poster.jpg", "backdrop": "assets/movie-the-amazing-spider-man-2012-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 1930, "ratings": {"rtCritics": 71, "rtCriticsLabel": "Certified Fresh", "rtAudience": 77, "rtAudienceLabel": "Upright", "imdb": 7, "imdbVotes": 791938, "tmdb": 6.768, "tmdbVotes": 19312}}, {"id": "movie-the-amazing-spider-man-2-2014", "title": "The Amazing Spider-Man 2", "year": 2014, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action", "Adventure", "Science Fiction"], "overview": "For Peter Parker, life is busy. Between taking out the bad guys as Spider-Man and spending time with the person he loves, Gwen Stacy, high school graduation cannot come quickly enough. Peter has not forgotten about\u2026", "poster": "assets/movie-the-amazing-spider-man-2-2014-poster.jpg", "backdrop": "assets/movie-the-amazing-spider-man-2-2014-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 102382, "ratings": {"rtCritics": 51, "rtCriticsLabel": "Rotten", "rtAudience": 64, "rtAudienceLabel": "Upright", "imdb": 6.6, "imdbVotes": 611981, "tmdb": 6.567, "tmdbVotes": 14919}}, {"id": "movie-the-animatrix-2003", "title": "The Animatrix", "year": 2003, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Animation", "Science Fiction"], "overview": "Straight from the creators of the groundbreaking Matrix trilogy, this collection of short animated films from the world's leading anime directors fuses computer graphics and Japanese anime to provide the background\u2026", "poster": "assets/movie-the-animatrix-2003-poster.jpg", "backdrop": "assets/movie-the-animatrix-2003-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 55931, "ratings": {"rtCritics": 86, "rtCriticsLabel": "Fresh", "rtAudience": 78, "rtAudienceLabel": "Upright", "imdb": 7.3, "imdbVotes": 91929, "tmdb": 7.221, "tmdbVotes": 1872}}, {"id": "movie-ant-man-and-the-wasp-quantumania-2023", "title": "Ant-Man and the Wasp: Quantumania", "year": 2023, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action", "Adventure", "Science Fiction"], "overview": "Super-Hero partners Scott Lang and Hope van Dyne, along with with Hope's parents Janet van Dyne and Hank Pym, and Scott's daughter Cassie Lang, find themselves exploring the Quantum Realm, interacting with strange\u2026", "poster": "assets/movie-ant-man-and-the-wasp-quantumania-2023-poster.jpg", "backdrop": "assets/movie-ant-man-and-the-wasp-quantumania-2023-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 640146, "ratings": {"rtCritics": 46, "rtCriticsLabel": "Rotten", "rtAudience": 81, "rtAudienceLabel": "Upright", "imdb": 6, "imdbVotes": 281738, "tmdb": 6.197, "tmdbVotes": 6236}}, {"id": "movie-appleseed-alpha-2014", "title": "Appleseed Alpha", "year": 2014, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Animation", "Science Fiction", "Action"], "overview": "The Third World War (2099\u20132126) devastated part of the Earth. Former nations are reforming while new powers emerge, and groups of humans struggle to survive in ruined cities. The story follows Deunan Knute and her\u2026", "poster": "assets/movie-appleseed-alpha-2014-poster.jpg", "backdrop": "assets/movie-appleseed-alpha-2014-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "center_crop", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 269650, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": 59, "rtAudienceLabel": "Spilled", "imdb": 6.5, "imdbVotes": 9689, "tmdb": 6.808, "tmdbVotes": 436}}, {"id": "movie-aquaman-and-the-lost-kingdom-2023", "title": "Aquaman and the Lost Kingdom", "year": 2023, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action", "Adventure", "Fantasy"], "overview": "Black Manta seeks revenge on Aquaman for his father's death. Wielding the Black Trident's power, he becomes a formidable foe. To defend Atlantis, Arthur (Aquaman) forges an alliance with his imprisoned brother. They\u2026", "poster": "assets/movie-aquaman-and-the-lost-kingdom-2023-poster.jpg", "backdrop": "assets/movie-aquaman-and-the-lost-kingdom-2023-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 572802, "ratings": {"rtCritics": 33, "rtCriticsLabel": "Rotten", "rtAudience": 79, "rtAudienceLabel": "Upright", "imdb": 5.6, "imdbVotes": 122422, "tmdb": 6.48, "tmdbVotes": 3748}}, {"id": "movie-the-avengers-2012", "title": "The Avengers", "year": 2012, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Science Fiction", "Action", "Adventure"], "overview": "When an unexpected enemy emerges and threatens global safety and security, Nick Fury, director of the international peacekeeping agency known as S.H.I.E.L.D., finds himself in need of a team to pull the world back\u2026", "poster": "assets/movie-the-avengers-2012-poster.jpg", "backdrop": "assets/movie-the-avengers-2012-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 24428, "ratings": {"rtCritics": 91, "rtCriticsLabel": "Certified Fresh", "rtAudience": 91, "rtAudienceLabel": "Upright", "imdb": 8, "imdbVotes": 1590693, "tmdb": 8.084, "tmdbVotes": 40262}}, {"id": "movie-avengers-confidential-black-widow-punisher-2014", "title": "Avengers Confidential: Black Widow & Punisher", "year": 2014, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Animation", "Science Fiction", "Action"], "overview": "When the Punisher takes out a black-market weapons dealer, he stumbles upon a far-reaching terrorist plot devised by a group known as Leviathan.", "poster": "assets/movie-avengers-confidential-black-widow-punisher-2014-poster.jpg", "backdrop": "assets/movie-avengers-confidential-black-widow-punisher-2014-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 257346, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": 55, "rtAudienceLabel": "Spilled", "imdb": 5.7, "imdbVotes": 5166, "tmdb": 6.368, "tmdbVotes": 303}}, {"id": "movie-avengers-age-of-ultron-2015", "title": "Avengers: Age of Ultron", "year": 2015, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action", "Adventure", "Science Fiction"], "overview": "When Tony Stark tries to jumpstart a dormant peacekeeping program, things go awry and Earth\u2019s Mightiest Heroes are put to the ultimate test as the fate of the planet hangs in the balance. As the villainous Ultron\u2026", "poster": "assets/movie-avengers-age-of-ultron-2015-poster.jpg", "backdrop": "assets/movie-avengers-age-of-ultron-2015-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 99861, "ratings": {"rtCritics": 75, "rtCriticsLabel": "Certified Fresh", "rtAudience": 82, "rtAudienceLabel": "Upright", "imdb": 7.3, "imdbVotes": 1025876, "tmdb": 7.278, "tmdbVotes": 25289}}, {"id": "movie-avengers-infinity-war-2018", "title": "Avengers: Infinity War", "year": 2018, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Adventure", "Action", "Science Fiction"], "overview": "As the Avengers and their allies have continued to protect the world from threats too large for any one hero to handle, a new danger has emerged from the cosmic shadows: Thanos. A despot of intergalactic infamy, his\u2026", "poster": "assets/movie-avengers-infinity-war-2018-poster.jpg", "backdrop": "assets/movie-avengers-infinity-war-2018-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 299536, "ratings": {"rtCritics": 85, "rtCriticsLabel": "Certified Fresh", "rtAudience": 92, "rtAudienceLabel": "Upright", "imdb": 8.4, "imdbVotes": 1421954, "tmdb": 8.246, "tmdbVotes": 33331}}, {"id": "movie-batman-ninja-2018", "title": "Batman Ninja", "year": 2018, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Animation", "Action", "Science Fiction"], "overview": "Batman, along with many of his allies and adversaries, finds himself transported to feudal Japan by Gorilla Grodd's time displacement machine.", "poster": "assets/movie-batman-ninja-2018-poster.jpg", "backdrop": "assets/movie-batman-ninja-2018-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 485942, "ratings": {"rtCritics": 84, "rtCriticsLabel": "Fresh", "rtAudience": 60, "rtAudienceLabel": "Upright", "imdb": 5.6, "imdbVotes": 24579, "tmdb": 5.9, "tmdbVotes": 1106}}, {"id": "movie-batman-v-superman-dawn-of-justice-2016", "title": "Batman v Superman: Dawn of Justice", "year": 2016, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action", "Adventure", "Fantasy"], "overview": "Fearing the actions of a god-like Super Hero left unchecked, Gotham City\u2019s own formidable, forceful vigilante takes on Metropolis\u2019s most revered, modern-day savior, while the world wrestles with what sort of hero it\u2026", "poster": "assets/movie-batman-v-superman-dawn-of-justice-2016-poster.jpg", "backdrop": "assets/movie-batman-v-superman-dawn-of-justice-2016-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 209112, "ratings": {"rtCritics": 28, "rtCriticsLabel": "Rotten", "rtAudience": 63, "rtAudienceLabel": "Upright", "imdb": 6.4, "imdbVotes": 801382, "tmdb": 6.014, "tmdbVotes": 19527}}, {"id": "movie-batman-the-dark-knight-returns-part-1-2012", "title": "Batman: The Dark Knight Returns, Part 1", "year": 2012, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Science Fiction", "Action", "Animation"], "overview": "Batman has not been seen for ten years. A new breed of criminal ravages Gotham City, forcing 55-year-old Bruce Wayne back into the cape and cowl. But, does he still have what it takes to fight crime in a new era?", "poster": "assets/movie-batman-the-dark-knight-returns-part-1-2012-poster.jpg", "backdrop": "assets/movie-batman-the-dark-knight-returns-part-1-2012-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 123025, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": 93, "rtAudienceLabel": "Upright", "imdb": 7.9, "imdbVotes": 68943, "tmdb": 7.742, "tmdbVotes": 1766}}, {"id": "movie-black-adam-2022", "title": "Black Adam", "year": 2022, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action", "Adventure", "Science Fiction"], "overview": "Nearly 5,000 years after he was bestowed with the almighty powers of the Egyptian gods\u2014and imprisoned just as quickly\u2014Black Adam is freed from his earthly tomb, ready to unleash his unique form of justice on the\u2026", "poster": "assets/movie-black-adam-2022-poster.jpg", "backdrop": "assets/movie-black-adam-2022-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 436270, "ratings": {"rtCritics": 39, "rtCriticsLabel": "Rotten", "rtAudience": 87, "rtAudienceLabel": "Upright", "imdb": 6.1, "imdbVotes": 309624, "tmdb": 6.747, "tmdbVotes": 7370}}, {"id": "movie-black-panther-2018", "title": "Black Panther", "year": 2018, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action", "Adventure", "Science Fiction"], "overview": "King T'Challa returns home to the reclusive, technologically advanced African nation of Wakanda to serve as his country's new leader. However, T'Challa soon finds that he is challenged for the throne by factions\u2026", "poster": "assets/movie-black-panther-2018-poster.jpg", "backdrop": "assets/movie-black-panther-2018-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 284054, "ratings": {"rtCritics": 96, "rtCriticsLabel": "Certified Fresh", "rtAudience": null, "rtAudienceLabel": "Spilled", "imdb": 7.3, "imdbVotes": 931120, "tmdb": 7.36, "tmdbVotes": 24190}}, {"id": "movie-black-panther-wakanda-forever-2022", "title": "Black Panther: Wakanda Forever", "year": 2022, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action", "Adventure", "Science Fiction"], "overview": "Queen Ramonda, Shuri, M\u2019Baku, Okoye and the Dora Milaje fight to protect their nation from intervening world powers in the wake of King T\u2019Challa\u2019s death. As the Wakandans strive to embrace their next chapter, the\u2026", "poster": "assets/movie-black-panther-wakanda-forever-2022-poster.jpg", "backdrop": "assets/movie-black-panther-wakanda-forever-2022-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 505642, "ratings": {"rtCritics": 84, "rtCriticsLabel": "Certified Fresh", "rtAudience": 93, "rtAudienceLabel": "Upright", "imdb": 6.6, "imdbVotes": 405088, "tmdb": 6.984, "tmdbVotes": 7920}}, {"id": "movie-blame-2017", "title": "BLAME!", "year": 2017, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action", "Drama", "Science Fiction"], "overview": "In the distant technological future, civilization has reached its ultimate Net-based form. An \"infection\" in the past caused the automated systems to spiral out of order, resulting in a multi-leveled city structure\u2026", "poster": "assets/movie-blame-2017-poster.jpg", "backdrop": "assets/movie-blame-2017-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 409421, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": 61, "rtAudienceLabel": "Upright", "imdb": 6.6, "imdbVotes": 10258, "tmdb": 6.523, "tmdbVotes": 370}}, {"id": "movie-bleach-the-movie-fade-to-black-2008", "title": "Bleach the Movie: Fade to Black", "year": 2008, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action", "Animation", "Fantasy"], "overview": "A strange disturbance in the World of the Living sends Ichigo and Kon to the Soul Society, where the Seireitei has been devastated by an explosion of reishi and Rukia is missing. Stranger still, none of the Soul\u2026", "poster": "assets/movie-bleach-the-movie-fade-to-black-2008-poster.jpg", "backdrop": "assets/movie-bleach-the-movie-fade-to-black-2008-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 17165, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": 67, "rtAudienceLabel": "Upright", "imdb": 7.1, "imdbVotes": 3693, "tmdb": 7.1, "tmdbVotes": 206}}, {"id": "tv-90-day-fiance-before-the-90-days-2017", "title": "90 Day Fianc\u00e9: Before the 90 Days", "year": 2017, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Reality"], "overview": "Follow couples who have an existing relationship online, but haven't met in person. We'll experience their journey as they travel to the other's foreign country for the first time in an attempt to establish an\u2026", "poster": "assets/tv-90-day-fiance-before-the-90-days-2017-poster.jpg", "backdrop": "assets/tv-90-day-fiance-before-the-90-days-2017-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 73319, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.5, "tmdbVotes": 45}}, {"id": "tv-90-day-fiance-the-other-way-2019", "title": "90 Day Fianc\u00e9: The Other Way", "year": 2019, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Reality"], "overview": "Americans move to a foreign country all in the name of love. Will uprooting their lives in the United States pay off, or will they be packing up and moving back to America brokenhearted?", "poster": "assets/tv-90-day-fiance-the-other-way-2019-poster.jpg", "backdrop": "assets/tv-90-day-fiance-the-other-way-2019-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 90046, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.8, "tmdbVotes": 34}}, {"id": "tv-the-100-2014", "title": "The 100", "year": 2014, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Sci-Fi & Fantasy", "Action & Adventure", "Drama"], "overview": "100 years in the future, when the Earth has been abandoned due to radioactivity, the last surviving humans live on an ark orbiting the planet \u2014 but the ark won't last forever. So the repressive regime picks 100\u2026", "poster": "assets/tv-the-100-2014-poster.jpg", "backdrop": "assets/tv-the-100-2014-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 48866, "ratings": {"rtCritics": 93, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.878, "tmdbVotes": 8855}}, {"id": "tv-the-abbott-and-costello-show-1952", "title": "The Abbott and Costello Show", "year": 1952, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Comedy"], "overview": "Bud and Lou are unemployed actors living in Mr. Fields\u2019 boarding house. Lou\u2019s girlfriend Hillary lives across the hall. Many situations arise leading to slapstick and puns.", "poster": "assets/tv-the-abbott-and-costello-show-1952-poster.jpg", "backdrop": "assets/tv-the-abbott-and-costello-show-1952-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 11821, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.2, "tmdbVotes": 22}}, {"id": "tv-accel-world-2012", "title": "Accel World", "year": 2012, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Drama"], "overview": "A short, overweight student uses the Neuro Link, an evolution of the Nerve Gear, to escape himself from the reality. But his skills in the virtual world brings him to the attention of Kuroyukihime, a popular student\u2026", "poster": "assets/tv-accel-world-2012-poster.jpg", "backdrop": "assets/tv-accel-world-2012-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "center_crop", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 43167, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.429, "tmdbVotes": 163}}, {"id": "tv-ahsoka-2023", "title": "Ahsoka", "year": 2023, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Sci-Fi & Fantasy", "Action & Adventure", "Drama"], "overview": "Former Jedi Knight Ahsoka Tano investigates an emerging threat to a vulnerable galaxy.", "poster": "assets/tv-ahsoka-2023-poster.jpg", "backdrop": "assets/tv-ahsoka-2023-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 114461, "ratings": {"rtCritics": 85, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.4, "tmdbVotes": 1351}}, {"id": "tv-american-dad-2005", "title": "American Dad!", "year": 2005, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Animation", "Comedy"], "overview": "The series focuses on an eccentric motley crew that is the Smith family and their three housemates: Father, husband, and breadwinner Stan Smith; his better half housewife, Francine Smith; their college-aged daughter,\u2026", "poster": "assets/tv-american-dad-2005-poster.jpg", "backdrop": "assets/tv-american-dad-2005-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 1433, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.022, "tmdbVotes": 2481}}, {"id": "tv-american-gods-2017", "title": "American Gods", "year": 2017, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Mystery", "Sci-Fi & Fantasy"], "overview": "An ex-con becomes the traveling partner of a conman who turns out to be one of the older gods trying to recruit troops to battle the upstart deities. Based on Neil Gaiman's fantasy novel.", "poster": "assets/tv-american-gods-2017-poster.jpg", "backdrop": "assets/tv-american-gods-2017-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 46639, "ratings": {"rtCritics": 75, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.1, "tmdbVotes": 1852}}, {"id": "tv-andromeda-2000", "title": "Andromeda", "year": 2000, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action & Adventure", "Drama", "Sci-Fi & Fantasy"], "overview": "Captain Dylan Hunt and his crew quest to restore a government that once presided over an extended peace and prosperity.", "poster": "assets/tv-andromeda-2000-poster.jpg", "backdrop": "assets/tv-andromeda-2000-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 2985, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.068, "tmdbVotes": 315}}, {"id": "tv-aqua-teen-hunger-force-2000", "title": "Aqua Teen Hunger Force", "year": 2000, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Animation", "Comedy"], "overview": "The surreal adventures of three anthropomorphic fast food items: Master Shake, Frylock and Meatwad, and their human nextdoor neighbor, Carl Brutananadilewski.", "poster": "assets/tv-aqua-teen-hunger-force-2000-poster.jpg", "backdrop": "assets/tv-aqua-teen-hunger-force-2000-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 251, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.5, "tmdbVotes": 272}}, {"id": "tv-arifureta-from-commonplace-to-world-s-strongest-2019", "title": "Arifureta: From Commonplace to World's Strongest", "year": 2019, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "Hajime Nagumo and his high school class are suddenly summoned to a fantastical land as heroes. But while most of his classmates have powerful stats and abilities, Hajime does not. Underappreciated and unprepared, he\u2026", "poster": "assets/tv-arifureta-from-commonplace-to-world-s-strongest-2019-poster.jpg", "backdrop": "assets/tv-arifureta-from-commonplace-to-world-s-strongest-2019-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 86034, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.382, "tmdbVotes": 662}}, {"id": "tv-arrow-2012", "title": "Arrow", "year": 2012, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Crime", "Drama", "Action & Adventure"], "overview": "Spoiled billionaire playboy Oliver Queen is missing and presumed dead when his yacht is lost at sea. He returns five years later a changed man, determined to clean up the city as a hooded vigilante armed with a bow.", "poster": "assets/tv-arrow-2012-poster.jpg", "backdrop": "assets/tv-arrow-2012-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 1412, "ratings": {"rtCritics": 86, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.834, "tmdbVotes": 6537}}, {"id": "tv-avatar-the-last-airbender-2024", "title": "Avatar: The Last Airbender", "year": 2024, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action & Adventure", "Sci-Fi & Fantasy", "Drama"], "overview": "A young boy known as the Avatar must master the four elemental powers to save a world at war \u2014 and fight a ruthless enemy bent on stopping him.", "poster": "assets/tv-avatar-the-last-airbender-2024-poster.jpg", "backdrop": "assets/tv-avatar-the-last-airbender-2024-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 82452, "ratings": {"rtCritics": 66, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.8, "tmdbVotes": 1406}}, {"id": "tv-avatar-seven-havens-2026", "title": "Avatar: Seven Havens", "year": 2026, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "In a world shattered by a devastating cataclysm, a young Earthbender discovers she's the new Avatar after Korra. But in this dangerous era, that title marks her as humanity's destroyer, not its savior. Hunted by both\u2026", "poster": "assets/tv-avatar-seven-havens-2026-poster.jpg", "backdrop": "assets/tv-avatar-seven-havens-2026-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 284833, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.9, "tmdbVotes": 183}}, {"id": "tv-batman-the-brave-and-the-bold-2008", "title": "Batman: The Brave and the Bold", "year": 2008, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "The Caped Crusader is teamed up with Blue Beetle, Green Arrow, Aquaman and countless others in his quest to uphold justice.", "poster": "assets/tv-batman-the-brave-and-the-bold-2008-poster.jpg", "backdrop": "assets/tv-batman-the-brave-and-the-bold-2008-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 15804, "ratings": {"rtCritics": 96, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.6, "tmdbVotes": 295}}, {"id": "tv-batwoman-2019", "title": "Batwoman", "year": 2019, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Sci-Fi & Fantasy", "Action & Adventure"], "overview": "Kate Kane, armed with a passion for social justice and a flair for speaking her mind, soars onto the streets of Gotham as Batwoman, an out lesbian and highly trained street fighter primed to snuff out the failing\u2026", "poster": "assets/tv-batwoman-2019-poster.jpg", "backdrop": "assets/tv-batwoman-2019-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 89247, "ratings": {"rtCritics": 83, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.8, "tmdbVotes": 1619}}, {"id": "tv-big-mouth-2017", "title": "Big Mouth", "year": 2017, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Comedy", "Animation"], "overview": "Teenage friends find their lives upended by the wonders and horrors of puberty in this edgy comedy from real-life pals Nick Kroll and Andrew Goldberg.", "poster": "assets/tv-big-mouth-2017-poster.jpg", "backdrop": "assets/tv-big-mouth-2017-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 74204, "ratings": {"rtCritics": 95, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.591, "tmdbVotes": 1274}}, {"id": "tv-black-lightning-2018", "title": "Black Lightning", "year": 2018, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action & Adventure", "Sci-Fi & Fantasy", "Drama"], "overview": "Jefferson Pierce is a man wrestling with a secret. As the father of two daughters and principal of a charter high school that also serves as a safe haven for young people in a New Orleans neighborhood overrun by gang\u2026", "poster": "assets/tv-black-lightning-2018-poster.jpg", "backdrop": "assets/tv-black-lightning-2018-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 71663, "ratings": {"rtCritics": 92, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.907, "tmdbVotes": 991}}], "discoverySource": {"state": "materialized_snapshot", "rankKnown": false, "selection": "First 18 alphabetically indexed movie stubs and first 18 series stubs, not ranked feed order", "observedAt": "2026-11-04T20:42:12.030108+00:00"}}, {"key": "mindel", "name": "Mindel", "initial": "M", "color": "#ff9d72", "destinations": {"Home": {"kind": "home"}, "Movies": {"kind": "library", "collection": "movies"}, "Shows": {"kind": "library", "collection": "shows"}, "Discover": {"kind": "discover", "collection": "discover"}}, "movies": [{"id": "movie-chicago-2002", "title": "Chicago", "year": 2002, "type": "movie", "runtimeSeconds": 6808, "seasonCount": null, "communityRating": 7.131, "criticRating": 87, "genres": ["Comedy", "Crime", "Drama"], "overview": "Murderesses Velma Kelly and Roxie Hart find themselves on death row together and fight for the fame that will keep them from the gallows in 1920s Chicago.", "poster": "assets/movie-chicago-2002-poster.jpg", "backdrop": "assets/movie-chicago-2002-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:24:53.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 1574, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 87, "rtCriticsLabel": "Certified Fresh", "rtAudience": 83, "rtAudienceLabel": "Upright", "imdb": 7.2, "imdbVotes": 259272, "tmdb": 7.135, "tmdbVotes": 3025}}, {"id": "movie-coherence-2014", "title": "Coherence", "year": 2014, "type": "movie", "runtimeSeconds": 5286, "seasonCount": null, "communityRating": 7.21, "criticRating": 89, "genres": ["Thriller", "Science Fiction"], "overview": "Four couples gather for dinner the night a mysterious and powerful comet passes overhead.", "poster": "assets/movie-coherence-2014-poster.jpg", "backdrop": "assets/movie-coherence-2014-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2017-08-12T23:49:00.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 220289, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 89, "rtCriticsLabel": "Certified Fresh", "rtAudience": 81, "rtAudienceLabel": "Upright", "imdb": 7.1, "imdbVotes": 180354, "tmdb": 7.208, "tmdbVotes": 3702}}, {"id": "movie-the-killing-of-a-sacred-deer-2017", "title": "The Killing of a Sacred Deer", "year": 2017, "type": "movie", "runtimeSeconds": 7262, "seasonCount": null, "communityRating": 7.003, "criticRating": 79, "genres": ["Drama", "Thriller", "Mystery"], "overview": "Dr. Steven Murphy is a renowned cardiovascular surgeon who presides over a spotless household with his wife and two children. Lurking at the margins of his idyllic suburban existence is Martin, a fatherless teen who\u2026", "poster": "assets/movie-the-killing-of-a-sacred-deer-2017-poster.jpg", "backdrop": "assets/movie-the-killing-of-a-sacred-deer-2017-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-22T21:49:26.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 399057, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 79, "rtCriticsLabel": "Certified Fresh", "rtAudience": 63, "rtAudienceLabel": "Upright", "imdb": 7, "imdbVotes": 219488, "tmdb": 7.001, "tmdbVotes": 4640}}, {"id": "movie-night-is-short-walk-on-girl-2017", "title": "Night Is Short, Walk On Girl", "year": 2017, "type": "movie", "runtimeSeconds": 5548, "seasonCount": null, "communityRating": 7.421, "criticRating": 90, "genres": ["Comedy", "Romance", "Animation"], "overview": "As a group of university students go out for a night on the town, a sophomore known only as \"The Girl with Black Hair\" experiences a series of surreal encounters with the local nightlife \u2013 all the while unaware of\u2026", "poster": "assets/movie-night-is-short-walk-on-girl-2017-poster.jpg", "backdrop": "assets/movie-night-is-short-walk-on-girl-2017-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T17:39:14.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 430214, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 90, "rtCriticsLabel": "Fresh", "rtAudience": 84, "rtAudienceLabel": "Upright", "imdb": 7.5, "imdbVotes": 7640, "tmdb": 7.4, "tmdbVotes": 267}}, {"id": "movie-thelma-louise-1991", "title": "Thelma & Louise", "year": 1991, "type": "movie", "runtimeSeconds": 7786, "seasonCount": null, "communityRating": 7.596, "criticRating": 87, "genres": ["Drama", "Crime", "Adventure"], "overview": "Taking a break from their dreary lives, close friends Thelma and Louise embark on a short weekend trip that ends in unforeseen incriminating circumstances. As fugitives, both women rediscover the strength of their\u2026", "poster": "assets/movie-thelma-louise-1991-poster.jpg", "backdrop": "assets/movie-thelma-louise-1991-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:24:40.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 1541, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 87, "rtCriticsLabel": "Certified Fresh", "rtAudience": 82, "rtAudienceLabel": "Upright", "imdb": 7.6, "imdbVotes": 197947, "tmdb": 7.594, "tmdbVotes": 4063}}, {"id": "movie-vicky-cristina-barcelona-2008", "title": "Vicky Cristina Barcelona", "year": 2008, "type": "movie", "runtimeSeconds": 5804, "seasonCount": null, "communityRating": 6.798, "criticRating": 80, "genres": ["Drama", "Romance"], "overview": "Two girlfriends on a summer holiday in Spain become enamored with the same painter, unaware that his ex-wife, with whom he has a tempestuous relationship, is about to re-enter the picture.", "poster": "assets/movie-vicky-cristina-barcelona-2008-poster.jpg", "backdrop": "assets/movie-vicky-cristina-barcelona-2008-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:25:34.0000000Z", "lastPlayedAt": "2026-08-11T20:12:57.3064089Z", "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 5038, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 80, "rtCriticsLabel": "Certified Fresh", "rtAudience": 74, "rtAudienceLabel": "Upright", "imdb": 7.1, "imdbVotes": 283286, "tmdb": 6.797, "tmdbVotes": 4164}}], "shows": [{"id": "tv-all-creatures-great-small-2020", "title": "All Creatures Great & Small", "year": 2020, "type": "tv", "runtimeSeconds": 3000, "seasonCount": 7, "communityRating": 8.2, "criticRating": null, "genres": ["Drama", "Comedy"], "overview": "The heartwarming and humorous adventures of a young country vet in the Yorkshire Dales in the 1930s. A remake of the 1978 series.", "poster": "assets/tv-all-creatures-great-small-2020-poster.jpg", "backdrop": "assets/tv-all-creatures-great-small-2020-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-11-04T20:13:03.4266156Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 108255, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 99, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.2, "tmdbVotes": 168}}, {"id": "tv-back-to-life-2019", "title": "Back to Life", "year": 2019, "type": "tv", "runtimeSeconds": 1500, "seasonCount": 2, "communityRating": 7.367, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "When Miri Matteson returns home after eighteen years, can she integrate back into her old life? With a terrible event from her past hanging over her, it won\u2019t be easy.", "poster": "assets/tv-back-to-life-2019-poster.jpg", "backdrop": "assets/tv-back-to-life-2019-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0688758Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 88510, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.4, "tmdbVotes": 65}}, {"id": "tv-big-boys-2022", "title": "Big Boys", "year": 2022, "type": "tv", "runtimeSeconds": 1440, "seasonCount": 3, "communityRating": 7.6, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "Two boys from very different ends of the 'spectrum of masculinity' become best friends at Brent University freshers' week; in their first year of uni, they explore, experiment and try to discover themselves, helping\u2026", "poster": "assets/tv-big-boys-2022-poster.jpg", "backdrop": "assets/tv-big-boys-2022-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-11-04T20:25:58.2156837Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 202851, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.6, "tmdbVotes": 49}}, {"id": "tv-call-the-midwife-2012", "title": "Call the Midwife", "year": 2012, "type": "tv", "runtimeSeconds": 3120, "seasonCount": 15, "communityRating": 7.5, "criticRating": null, "genres": ["Drama"], "overview": "Drama following the lives of a group of midwives working in the poverty-stricken East End of London during the 1950s, based on the best-selling memoirs of Jennifer Worth.", "poster": "assets/tv-call-the-midwife-2012-poster.jpg", "backdrop": "assets/tv-call-the-midwife-2012-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0377216Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 39793, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.577, "tmdbVotes": 267}}, {"id": "tv-derry-girls-2018", "title": "Derry Girls", "year": 2018, "type": "tv", "runtimeSeconds": 1380, "seasonCount": 3, "communityRating": 8.144, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "Amidst the political conflict of Northern Ireland in the 1990s, five secondary school students square off with the universal challenges of being a teenager.", "poster": "assets/tv-derry-girls-2018-poster.jpg", "backdrop": "assets/tv-derry-girls-2018-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-02T20:01:55.8955537Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 76148, "artwork": {"posterKind": "center_crop", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 99, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.138, "tmdbVotes": 454}}, {"id": "tv-desperate-housewives-2004", "title": "Desperate Housewives", "year": 2004, "type": "tv", "runtimeSeconds": 2520, "seasonCount": 8, "communityRating": 7.896, "criticRating": null, "genres": ["Mystery", "Drama", "Comedy"], "overview": "Looking down on her friends and family isn't a way of life for Mary Alice Young... it's a way of death. One day, in her perfect house, in the loveliest of suburbs, Mary Alice ended it all. Now she's taking us into\u2026", "poster": "assets/tv-desperate-housewives-2004-poster.jpg", "backdrop": "assets/tv-desperate-housewives-2004-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-29T20:56:40.3505596Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 693, "artwork": {"posterKind": "poster", "backdropKind": "center_crop"}, "ratings": {"rtCritics": 72, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.896, "tmdbVotes": 2171}}, {"id": "tv-the-diplomat-2023", "title": "The Diplomat", "year": 2023, "type": "tv", "runtimeSeconds": null, "seasonCount": 4, "communityRating": 7.569, "criticRating": null, "genres": ["Drama", "War & Politics"], "overview": "Amid an international crisis, a US diplomat contends with her high-profile job as ambassador to the UK and her strained marriage to a political star.", "poster": "assets/tv-the-diplomat-2023-poster.jpg", "backdrop": "assets/tv-the-diplomat-2023-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0640348Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 203857, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 93, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.652, "tmdbVotes": 521}}, {"id": "tv-the-durrells-2016", "title": "The Durrells", "year": 2016, "type": "tv", "runtimeSeconds": 2760, "seasonCount": 4, "communityRating": 7.402, "criticRating": null, "genres": ["Drama", "Comedy", "Family"], "overview": "In 1935, financially strapped widow Louisa Durrell, whose life has fallen apart, decides to move from England, with her four children (three sons, one daughter), to the island of Corfu, Greece. Once there, the family\u2026", "poster": "assets/tv-the-durrells-2016-poster.jpg", "backdrop": "assets/tv-the-durrells-2016-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0619436Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 66134, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 94, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.4, "tmdbVotes": 127}}, {"id": "tv-etoile-2025", "title": "\u00c9toile", "year": 2025, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.197, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "In an ambitious gambit to save their storied institutions, two world-renowned ballet companies in New York City and Paris swap their most talented stars.", "poster": "assets/tv-etoile-2025-poster.jpg", "backdrop": "assets/tv-etoile-2025-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0601383Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 225383, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 86, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.3, "tmdbVotes": 40}}, {"id": "tv-gilmore-girls-2000", "title": "Gilmore Girls", "year": 2000, "type": "tv", "runtimeSeconds": 2640, "seasonCount": 7, "communityRating": 7.893, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "Set in the charming town of Stars Hollow, Connecticut, the series follows the captivating lives of Lorelai and Rory Gilmore, a mother/daughter pair who have a relationship most people only dream of.", "poster": "assets/tv-gilmore-girls-2000-poster.jpg", "backdrop": "assets/tv-gilmore-girls-2000-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0631035Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 4586, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.9, "tmdbVotes": 1339}}, {"id": "tv-ginny-georgia-2021", "title": "Ginny & Georgia", "year": 2021, "type": "tv", "runtimeSeconds": null, "seasonCount": 3, "communityRating": 8.026, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "Free-spirited Georgia and her two kids, Ginny and Austin, move north in search of a fresh start but find that the road to new beginnings can be bumpy.", "poster": "assets/tv-ginny-georgia-2021-poster.jpg", "backdrop": "assets/tv-ginny-georgia-2021-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0694828Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 117581, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 68, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8, "tmdbVotes": 1840}}, {"id": "tv-hellcats-2010", "title": "Hellcats", "year": 2010, "type": "tv", "runtimeSeconds": 2460, "seasonCount": 1, "communityRating": 7.5, "criticRating": null, "genres": ["Drama"], "overview": "Pre-law student Marti Perkins' world is flipped upside down when she loses her scholarship, and realizes the only way she can stay in school is by reigniting her dormant teen gymnastic skills to win a place on Lancer\u2026", "poster": "assets/tv-hellcats-2010-poster.jpg", "backdrop": "assets/tv-hellcats-2010-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-22T20:39:02.7719318Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 32504, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 65, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.5, "tmdbVotes": 116}}, {"id": "tv-high-potential-2024", "title": "High Potential", "year": 2024, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 8.201, "criticRating": null, "genres": ["Drama", "Crime", "Mystery"], "overview": "Morgan is a single mom with an exceptional mind, whose unconventional knack for solving crimes leads to an unusual and unstoppable partnership with a by-the-book seasoned detective.", "poster": "assets/tv-high-potential-2024-poster.jpg", "backdrop": "assets/tv-high-potential-2024-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0686091Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 226637, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 98, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.3, "tmdbVotes": 707}}, {"id": "tv-how-to-get-to-heaven-from-belfast-2026", "title": "How to Get to Heaven from Belfast", "year": 2026, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.027, "criticRating": null, "genres": ["Mystery", "Comedy", "Drama"], "overview": "Three lifelong pals embark on a chaotic quest to solve the mystery of their old friend's suspicious death and keep their own dark secret under wraps.", "poster": "assets/tv-how-to-get-to-heaven-from-belfast-2026-poster.jpg", "backdrop": "assets/tv-how-to-get-to-heaven-from-belfast-2026-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0683192Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 233079, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 95, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.063, "tmdbVotes": 95}}, {"id": "tv-the-hunting-wives-2025", "title": "The Hunting Wives", "year": 2025, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 6.932, "criticRating": null, "genres": ["Drama", "Mystery"], "overview": "Sophie trades New England for East Texas and falls into a wealthy socialite's magnetic orbit \u2014 where a clique of housewives hide deadly secrets.", "poster": "assets/tv-the-hunting-wives-2025-poster.jpg", "backdrop": "assets/tv-the-hunting-wives-2025-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-20T19:42:46.3227892Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 244447, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 81, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.964, "tmdbVotes": 112}}, {"id": "tv-the-lost-flowers-of-alice-hart-2023", "title": "The Lost Flowers of Alice Hart", "year": 2023, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.634, "criticRating": null, "genres": ["Drama", "Mystery"], "overview": "After losing her parents in a mysterious fire, nine-year-old Alice Hart is raised by her grandmother June on a flower farm where she learns there are secrets within secrets. But years on, an unearthed betrayal sees\u2026", "poster": "assets/tv-the-lost-flowers-of-alice-hart-2023-poster.jpg", "backdrop": "assets/tv-the-lost-flowers-of-alice-hart-2023-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0607236Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 125816, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 82, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.64, "tmdbVotes": 161}}, {"id": "tv-love-is-blind-2020", "title": "Love Is Blind", "year": 2020, "type": "tv", "runtimeSeconds": null, "seasonCount": 11, "communityRating": 6.261, "criticRating": null, "genres": ["Reality"], "overview": "Nick and Vanessa Lachey host this social experiment where single men and women look for love and get engaged, all before meeting in person.", "poster": "assets/tv-love-is-blind-2020-poster.jpg", "backdrop": "assets/tv-love-is-blind-2020-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-22T17:11:08.2447226Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 99353, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 66, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.233, "tmdbVotes": 118}}, {"id": "tv-maximum-pleasure-guaranteed-2026", "title": "Maximum Pleasure Guaranteed", "year": 2026, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 6.676, "criticRating": null, "genres": ["Comedy"], "overview": "A newly divorced mom falls down a dangerous rabbit hole of blackmail, murder, and youth soccer.", "poster": "assets/tv-maximum-pleasure-guaranteed-2026-poster.jpg", "backdrop": "assets/tv-maximum-pleasure-guaranteed-2026-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-07T21:04:02.8277793Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 285404, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 93, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.799, "tmdbVotes": 92}}, {"id": "tv-minx-2022", "title": "Minx", "year": 2022, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 6.833, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "An earnest young feminist joins forces with a low-rent publisher to make the world's first erotic magazine for women.", "poster": "assets/tv-minx-2022-poster.jpg", "backdrop": "assets/tv-minx-2022-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0653613Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 118303, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 93, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.9, "tmdbVotes": 123}}, {"id": "tv-offspring-2010", "title": "Offspring", "year": 2010, "type": "tv", "runtimeSeconds": 3600, "seasonCount": 7, "communityRating": 6.9, "criticRating": null, "genres": ["Drama"], "overview": "An exuberant drama set in Melbourne's Fitzroy, centering on Nina Proudman and her struggle to deal with her fabulously messy family, her hunt for a decent love life and her tendency to overthink and fly off into fantasy.", "poster": "assets/tv-offspring-2010-poster.jpg", "backdrop": "assets/tv-offspring-2010-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0664581Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 33155, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.9, "tmdbVotes": 27}}, {"id": "tv-only-murders-in-the-building-2021", "title": "Only Murders in the Building", "year": 2021, "type": "tv", "runtimeSeconds": null, "seasonCount": 5, "communityRating": 8.398, "criticRating": null, "genres": ["Comedy", "Mystery", "Crime"], "overview": "Three strangers share an obsession with true crime and suddenly find themselves wrapped up in one.", "poster": "assets/tv-only-murders-in-the-building-2021-poster.jpg", "backdrop": "assets/tv-only-murders-in-the-building-2021-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-11-04T20:25:58.2163301Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 107113, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 95, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.398, "tmdbVotes": 2333}}, {"id": "tv-outlander-blood-of-my-blood-2025", "title": "Outlander: Blood of My Blood", "year": 2025, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 8.542, "criticRating": null, "genres": ["Drama"], "overview": "From the battlefields of World War I to the rugged Highlands of 18th century Scotland, two fated couples must defy the forces that seek to tear them apart, unfolding in surprising and unforeseen ways in this romantic\u2026", "poster": "assets/tv-outlander-blood-of-my-blood-2025-poster.jpg", "backdrop": "assets/tv-outlander-blood-of-my-blood-2025-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0691373Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 207484, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 94, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.738, "tmdbVotes": 124}}, {"id": "tv-rivals-2024", "title": "Rivals", "year": 2024, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 7.44, "criticRating": null, "genres": ["Drama"], "overview": "It is 1986 and Britain is booming. \"Rivals\" dives headfirst into the cutthroat world of TV where hair-dos are big and ambitions are even bigger. Deals are brokered in boardrooms, as well as bedrooms. Nobody can be\u2026", "poster": "assets/tv-rivals-2024-poster.jpg", "backdrop": "assets/tv-rivals-2024-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0645815Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 208921, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 96, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.4, "tmdbVotes": 93}}, {"id": "tv-rooster-2026", "title": "Rooster", "year": 2026, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.431, "criticRating": null, "genres": ["Comedy"], "overview": "On a college campus, an author navigates a complicated relationship with his daughter.", "poster": "assets/tv-rooster-2026-poster.jpg", "backdrop": "assets/tv-rooster-2026-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.063389Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 254953, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 88, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.423, "tmdbVotes": 144}}, {"id": "tv-sex-and-the-city-1998", "title": "Sex and the City", "year": 1998, "type": "tv", "runtimeSeconds": null, "seasonCount": 6, "communityRating": 7.365, "criticRating": null, "genres": ["Drama", "Comedy"], "overview": "Based on the bestselling book by Candace Bushnell, Sex and the City tells the story of four best friends, all single and in their late thirties, as they pursue their careers and talk about their sex lives, all while\u2026", "poster": "assets/tv-sex-and-the-city-1998-poster.jpg", "backdrop": "assets/tv-sex-and-the-city-1998-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0679324Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 105, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 70, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.351, "tmdbVotes": 2220}}, {"id": "tv-skymed-2022", "title": "SkyMed", "year": 2022, "type": "tv", "runtimeSeconds": 2640, "seasonCount": 4, "communityRating": 6.665, "criticRating": null, "genres": ["Drama"], "overview": "Life, death and drama at 20,000 feet. The series weaves together intense character journeys and high-stakes medical rescues, as we follow the triumphs, heartbreaks and tribulations of budding nurses and pilots flying\u2026", "poster": "assets/tv-skymed-2022-poster.jpg", "backdrop": "assets/tv-skymed-2022-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-22T19:44:29.2431354Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 133908, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.699, "tmdbVotes": 98}}, {"id": "tv-so-you-think-you-can-dance-2008", "title": "So You Think You Can Dance", "year": 2008, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 9.8, "criticRating": null, "genres": ["Family", "Reality"], "overview": "So You Think You Can Dance is a joint Belgian-Dutch dance competition show broadcast on RTL 5 and vtm television stations. The first season was broadcast only in the Netherlands, whereas starting with season 2, the\u2026", "poster": "assets/tv-so-you-think-you-can-dance-2008-poster.jpg", "backdrop": "assets/tv-so-you-think-you-can-dance-2008-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-23T11:11:35.4124418Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 40231, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 9.8, "tmdbVotes": 4}}, {"id": "tv-the-white-lotus-2021", "title": "The White Lotus", "year": 2021, "type": "tv", "runtimeSeconds": null, "seasonCount": 3, "communityRating": 7.597, "criticRating": null, "genres": ["Comedy", "Drama", "Mystery"], "overview": "Follow the exploits of various guests and employees at an exclusive tropical resort over the span of a week as with each passing day, a darker complexity emerges in these picture-perfect travelers, the hotel\u2019s\u2026", "poster": "assets/tv-the-white-lotus-2021-poster.jpg", "backdrop": "assets/tv-the-white-lotus-2021-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-20T02:45:52.8742674Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 111803, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 90, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.599, "tmdbVotes": 1604}}, {"id": "tv-yellowjackets-2021", "title": "Yellowjackets", "year": 2021, "type": "tv", "runtimeSeconds": null, "seasonCount": 3, "communityRating": 7.431, "criticRating": null, "genres": ["Drama", "Mystery"], "overview": "This equal parts survival epic, psychological horror story and coming-of-age drama tells the saga of a team of wildly talented high school girls soccer players who become the (un)lucky survivors of a plane crash deep\u2026", "poster": "assets/tv-yellowjackets-2021-poster.jpg", "backdrop": "assets/tv-yellowjackets-2021-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-11-04T20:31:47.4592756Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 117488, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 92, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.431, "tmdbVotes": 1070}}], "anime": [], "resume": [{"id": "episode-sex-and-the-country-2001-s4e9", "title": "Sex and the Country", "year": 2001, "type": "episode", "runtimeSeconds": 1751, "seasonCount": null, "communityRating": 5.9, "criticRating": null, "genres": ["Comedy", "Drama", "Romance"], "overview": "Carrie is dragged to Aidan's country home in Suffern, New York. Charlotte visits the MacDougal \"compound\" in Connecticut. Miranda yells at Steve when he tells her he has testicular cancer but has no clue about his\u2026", "poster": "assets/episode-sex-and-the-country-2001-s4e9-poster.jpg", "backdrop": "assets/episode-sex-and-the-country-2001-s4e9-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 96.08, "progress": 0.0549, "addedAt": "2026-07-17T10:53:15.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "Sex and the City", "seasonNumber": 4, "episodeNumber": 9, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}], "nextUp": [{"id": "episode-what-more-do-i-need-2008-s5e7", "title": "What More Do I Need?", "year": 2008, "type": "episode", "runtimeSeconds": 2521, "seasonCount": null, "communityRating": 8, "criticRating": null, "genres": ["Comedy", "Drama", "Mystery"], "overview": "Lynette and Tom uncover the unsettling truth about son Porter. Gabrielle suspects Carlos' best client, Virginia, has ulterior motives. Bree's moment of weakness could bring her great embarrassment and shame.\u2026", "poster": "assets/episode-what-more-do-i-need-2008-s5e7-poster.jpg", "backdrop": "assets/episode-what-more-do-i-need-2008-s5e7-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-29T14:37:28.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "Desperate Housewives", "seasonNumber": 5, "episodeNumber": 7, "artwork": {"posterKind": "center_crop", "backdropKind": "backdrop"}}, {"id": "episode-new-day-2021-s1e2", "title": "New Day", "year": 2021, "type": "episode", "runtimeSeconds": 3445, "seasonCount": null, "communityRating": 7.143, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "A cautiously optimistic Belinda walks a fine line with Tanya, while Armond brainstorms ways to deal with Shane. After her husband belittles her work, Rachel approaches Nicole for advice. Paula and Olivia lose track\u2026", "poster": "assets/episode-new-day-2021-s1e2-poster.jpg", "backdrop": "assets/episode-new-day-2021-s1e2-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-19T22:18:57.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "The White Lotus", "seasonNumber": 1, "episodeNumber": 2, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}, {"id": "episode-the-uncomfortability-2010-s1e2", "title": "The Uncomfortability", "year": 2010, "type": "episode", "runtimeSeconds": 2687, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "Nina's insecurities are revealed when a patient poses an awkward request. Meanwhile Geraldine decides to try online dating, and Jimmy is an unexpected saviour to Cherie and Darcy.", "poster": "assets/episode-the-uncomfortability-2010-s1e2-poster.jpg", "backdrop": "assets/episode-the-uncomfortability-2010-s1e2-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T11:47:42.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "Offspring", "seasonNumber": 1, "episodeNumber": 2, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}, {"id": "episode-episode-2-2016-s1e2", "title": "Episode 2", "year": 2016, "type": "episode", "runtimeSeconds": 2766, "seasonCount": null, "communityRating": 8.3, "criticRating": null, "genres": ["Biography", "Comedy", "Drama"], "overview": "Larry falls dangerously ill, and it falls to Theo and his neighbour Sven to put their rudimentary medical skills to the task of saving his life. The family's money worries continue, but Spiros brings them good news\u2026", "poster": "assets/episode-episode-2-2016-s1e2-poster.jpg", "backdrop": "assets/episode-episode-2-2016-s1e2-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-31T07:29:17.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "The Durrells", "seasonNumber": 1, "episodeNumber": 2, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}, {"id": "episode-remembrance-day-2026-s2e1", "title": "Remembrance Day", "year": 2026, "type": "episode", "runtimeSeconds": 3822, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Fantasy", "Romance"], "overview": "The fiery crosses have been lit across the Highlands; lovers must part, as the call to arms brings friends and enemies home and the Jacobite Rebellion begins in earnest.", "poster": "assets/episode-remembrance-day-2026-s2e1-poster.jpg", "backdrop": "assets/episode-remembrance-day-2026-s2e1-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-19T03:50:07.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "Outlander: Blood of My Blood", "seasonNumber": 2, "episodeNumber": 1, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}, {"id": "episode-one-of-us-2024-s1e7", "title": "One of Us", "year": 2024, "type": "episode", "runtimeSeconds": 2555, "seasonCount": null, "communityRating": 7.7, "criticRating": null, "genres": [], "overview": "Morgan agrees to show Ava around the LAPD, but things quickly take a dangerous turn when the precinct is held hostage by the friends of a recently convicted man. Can Morgan and the detectives outsmart their captors\u2026", "poster": "assets/episode-one-of-us-2024-s1e7-poster.jpg", "backdrop": "assets/episode-one-of-us-2024-s1e7-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T13:57:22.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "High Potential", "seasonNumber": 1, "episodeNumber": 7, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}, {"id": "episode-the-breakup-part-2-2001-s1e17", "title": "The Breakup, Part 2", "year": 2001, "type": "episode", "runtimeSeconds": 2669, "seasonCount": null, "communityRating": 7.4, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "After recent events, Rory keeps busy, refusing to give in to self-pity. Meanwhile, Stars Hollow's residents rally around her, much to her dismay.", "poster": "assets/episode-the-breakup-part-2-2001-s1e17-poster.jpg", "backdrop": "assets/episode-the-breakup-part-2-2001-s1e17-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T11:28:05.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "Gilmore Girls", "seasonNumber": 1, "episodeNumber": 17, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}, {"id": "episode-i-heart-ny-2002-s4e18", "title": "I Heart NY", "year": 2002, "type": "episode", "runtimeSeconds": 1905, "seasonCount": null, "communityRating": 6.667, "criticRating": null, "genres": ["Comedy", "Drama", "Romance"], "overview": "Carrie is shocked to find out that Big is moving to Napa, California and plans to give him a New York send-off. Charlotte begins dating another recent divorc\u00e9. Miranda prepares for the new baby as her delivery date\u2026", "poster": "assets/episode-i-heart-ny-2002-s4e18-poster.jpg", "backdrop": "assets/episode-i-heart-ny-2002-s4e18-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T12:35:14.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "Sex and the City", "seasonNumber": 4, "episodeNumber": 18, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}], "recentlyAdded": [{"id": "tv-yellowjackets-2021", "title": "Yellowjackets", "year": 2021, "type": "tv", "runtimeSeconds": null, "seasonCount": 3, "communityRating": 7.431, "criticRating": null, "genres": ["Drama", "Mystery"], "overview": "This equal parts survival epic, psychological horror story and coming-of-age drama tells the saga of a team of wildly talented high school girls soccer players who become the (un)lucky survivors of a plane crash deep\u2026", "poster": "assets/tv-yellowjackets-2021-poster.jpg", "backdrop": "assets/tv-yellowjackets-2021-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-11-04T20:31:47.4592756Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 117488, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 92, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.431, "tmdbVotes": 1070}}, {"id": "tv-only-murders-in-the-building-2021", "title": "Only Murders in the Building", "year": 2021, "type": "tv", "runtimeSeconds": null, "seasonCount": 5, "communityRating": 8.398, "criticRating": null, "genres": ["Comedy", "Mystery", "Crime"], "overview": "Three strangers share an obsession with true crime and suddenly find themselves wrapped up in one.", "poster": "assets/tv-only-murders-in-the-building-2021-poster.jpg", "backdrop": "assets/tv-only-murders-in-the-building-2021-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-11-04T20:25:58.2163301Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 107113, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 95, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.398, "tmdbVotes": 2333}}, {"id": "tv-big-boys-2022", "title": "Big Boys", "year": 2022, "type": "tv", "runtimeSeconds": 1440, "seasonCount": 3, "communityRating": 7.6, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "Two boys from very different ends of the 'spectrum of masculinity' become best friends at Brent University freshers' week; in their first year of uni, they explore, experiment and try to discover themselves, helping\u2026", "poster": "assets/tv-big-boys-2022-poster.jpg", "backdrop": "assets/tv-big-boys-2022-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-11-04T20:25:58.2156837Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 202851, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.6, "tmdbVotes": 49}}, {"id": "tv-all-creatures-great-small-2020", "title": "All Creatures Great & Small", "year": 2020, "type": "tv", "runtimeSeconds": 3000, "seasonCount": 7, "communityRating": 8.2, "criticRating": null, "genres": ["Drama", "Comedy"], "overview": "The heartwarming and humorous adventures of a young country vet in the Yorkshire Dales in the 1930s. A remake of the 1978 series.", "poster": "assets/tv-all-creatures-great-small-2020-poster.jpg", "backdrop": "assets/tv-all-creatures-great-small-2020-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-11-04T20:13:03.4266156Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 108255, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 99, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.2, "tmdbVotes": 168}}, {"id": "movie-the-killing-of-a-sacred-deer-2017", "title": "The Killing of a Sacred Deer", "year": 2017, "type": "movie", "runtimeSeconds": 7262, "seasonCount": null, "communityRating": 7.003, "criticRating": 79, "genres": ["Drama", "Thriller", "Mystery"], "overview": "Dr. Steven Murphy is a renowned cardiovascular surgeon who presides over a spotless household with his wife and two children. Lurking at the margins of his idyllic suburban existence is Martin, a fatherless teen who\u2026", "poster": "assets/movie-the-killing-of-a-sacred-deer-2017-poster.jpg", "backdrop": "assets/movie-the-killing-of-a-sacred-deer-2017-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-22T21:49:26.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 399057, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 79, "rtCriticsLabel": "Certified Fresh", "rtAudience": 63, "rtAudienceLabel": "Upright", "imdb": 7, "imdbVotes": 219488, "tmdb": 7.001, "tmdbVotes": 4640}}, {"id": "tv-derry-girls-2018", "title": "Derry Girls", "year": 2018, "type": "tv", "runtimeSeconds": 1380, "seasonCount": 3, "communityRating": 8.144, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "Amidst the political conflict of Northern Ireland in the 1990s, five secondary school students square off with the universal challenges of being a teenager.", "poster": "assets/tv-derry-girls-2018-poster.jpg", "backdrop": "assets/tv-derry-girls-2018-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-02T20:01:55.8955537Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 76148, "artwork": {"posterKind": "center_crop", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 99, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.138, "tmdbVotes": 454}}, {"id": "tv-so-you-think-you-can-dance-2008", "title": "So You Think You Can Dance", "year": 2008, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 9.8, "criticRating": null, "genres": ["Family", "Reality"], "overview": "So You Think You Can Dance is a joint Belgian-Dutch dance competition show broadcast on RTL 5 and vtm television stations. The first season was broadcast only in the Netherlands, whereas starting with season 2, the\u2026", "poster": "assets/tv-so-you-think-you-can-dance-2008-poster.jpg", "backdrop": "assets/tv-so-you-think-you-can-dance-2008-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-23T11:11:35.4124418Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 40231, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 9.8, "tmdbVotes": 4}}, {"id": "tv-hellcats-2010", "title": "Hellcats", "year": 2010, "type": "tv", "runtimeSeconds": 2460, "seasonCount": 1, "communityRating": 7.5, "criticRating": null, "genres": ["Drama"], "overview": "Pre-law student Marti Perkins' world is flipped upside down when she loses her scholarship, and realizes the only way she can stay in school is by reigniting her dormant teen gymnastic skills to win a place on Lancer\u2026", "poster": "assets/tv-hellcats-2010-poster.jpg", "backdrop": "assets/tv-hellcats-2010-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-22T20:39:02.7719318Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 32504, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 65, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.5, "tmdbVotes": 116}}, {"id": "tv-skymed-2022", "title": "SkyMed", "year": 2022, "type": "tv", "runtimeSeconds": 2640, "seasonCount": 4, "communityRating": 6.665, "criticRating": null, "genres": ["Drama"], "overview": "Life, death and drama at 20,000 feet. The series weaves together intense character journeys and high-stakes medical rescues, as we follow the triumphs, heartbreaks and tribulations of budding nurses and pilots flying\u2026", "poster": "assets/tv-skymed-2022-poster.jpg", "backdrop": "assets/tv-skymed-2022-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-22T19:44:29.2431354Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 133908, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.699, "tmdbVotes": 98}}, {"id": "tv-love-is-blind-2020", "title": "Love Is Blind", "year": 2020, "type": "tv", "runtimeSeconds": null, "seasonCount": 11, "communityRating": 6.261, "criticRating": null, "genres": ["Reality"], "overview": "Nick and Vanessa Lachey host this social experiment where single men and women look for love and get engaged, all before meeting in person.", "poster": "assets/tv-love-is-blind-2020-poster.jpg", "backdrop": "assets/tv-love-is-blind-2020-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-22T17:11:08.2447226Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 99353, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 66, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.233, "tmdbVotes": 118}}, {"id": "tv-the-hunting-wives-2025", "title": "The Hunting Wives", "year": 2025, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 6.932, "criticRating": null, "genres": ["Drama", "Mystery"], "overview": "Sophie trades New England for East Texas and falls into a wealthy socialite's magnetic orbit \u2014 where a clique of housewives hide deadly secrets.", "poster": "assets/tv-the-hunting-wives-2025-poster.jpg", "backdrop": "assets/tv-the-hunting-wives-2025-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-20T19:42:46.3227892Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 244447, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 81, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.964, "tmdbVotes": 112}}, {"id": "tv-the-white-lotus-2021", "title": "The White Lotus", "year": 2021, "type": "tv", "runtimeSeconds": null, "seasonCount": 3, "communityRating": 7.597, "criticRating": null, "genres": ["Comedy", "Drama", "Mystery"], "overview": "Follow the exploits of various guests and employees at an exclusive tropical resort over the span of a week as with each passing day, a darker complexity emerges in these picture-perfect travelers, the hotel\u2019s\u2026", "poster": "assets/tv-the-white-lotus-2021-poster.jpg", "backdrop": "assets/tv-the-white-lotus-2021-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-20T02:45:52.8742674Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 111803, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 90, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.599, "tmdbVotes": 1604}}], "discover": [{"id": "movie-across-the-hall-2009", "title": "Across the Hall", "year": 2009, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Thriller", "Mystery"], "overview": "Convinced that his fiancee is cheating on him, a man follows her to a hotel and calls his best friend to help him avoid a calamity.", "poster": "assets/movie-across-the-hall-2009-poster.jpg", "backdrop": "assets/movie-across-the-hall-2009-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 21469, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": 39, "rtAudienceLabel": "Spilled", "imdb": 5.8, "imdbVotes": 5130, "tmdb": 6, "tmdbVotes": 129}}, {"id": "movie-addicted-2014", "title": "Addicted", "year": 2014, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Thriller"], "overview": "A gallerist risks her family and flourishing career when she enters into an affair with a talented painter and slowly loses control of her life.", "poster": "assets/movie-addicted-2014-poster.jpg", "backdrop": "assets/movie-addicted-2014-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 235271, "ratings": {"rtCritics": 7, "rtCriticsLabel": "Rotten", "rtAudience": 51, "rtAudienceLabel": "Spilled", "imdb": 5, "imdbVotes": 13131, "tmdb": 5.928, "tmdbVotes": 466}}, {"id": "movie-adulterers-2016", "title": "Adulterers", "year": 2016, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Thriller", "Drama"], "overview": "On a steamy New Orleans afternoon, Sam Deuprey decides to surprise his beautiful wife, Ashley, for their anniversary and comes home early. But Ashley is not alone in the bedroom. She and her lover, Damien are about\u2026", "poster": "assets/movie-adulterers-2016-poster.jpg", "backdrop": "assets/movie-adulterers-2016-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 376004, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": 37, "rtAudienceLabel": "Spilled", "imdb": 5.1, "imdbVotes": 2144, "tmdb": 6.2, "tmdbVotes": 116}}, {"id": "movie-alone-with-her-2006", "title": "Alone With Her", "year": 2006, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Crime", "Drama", "Thriller"], "overview": "The harrowing story of a disturbed young man's attempts to win the affections of an unsuspecting young woman. When Doug first sees Amy, he instantly falls for her and begins to watch her every move, going so far as\u2026", "poster": "assets/movie-alone-with-her-2006-poster.jpg", "backdrop": "assets/movie-alone-with-her-2006-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 18206, "ratings": {"rtCritics": 70, "rtCriticsLabel": "Fresh", "rtAudience": 46, "rtAudienceLabel": "Spilled", "imdb": 6, "imdbVotes": 4359, "tmdb": 5.9, "tmdbVotes": 94}}, {"id": "movie-awake-2007", "title": "Awake", "year": 2007, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Thriller", "Crime", "Mystery"], "overview": "While undergoing heart surgery, a man experiences a phenomenon called \u2018anesthetic awareness\u2019, which leaves him awake but paralyzed throughout the operation. As various obstacles present themselves, his wife must make\u2026", "poster": "assets/movie-awake-2007-poster.jpg", "backdrop": "assets/movie-awake-2007-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 13483, "ratings": {"rtCritics": 23, "rtCriticsLabel": "Rotten", "rtAudience": 55, "rtAudienceLabel": "Spilled", "imdb": 6.5, "imdbVotes": 89389, "tmdb": 6.586, "tmdbVotes": 1649}}, {"id": "movie-black-bear-2020", "title": "Black Bear", "year": 2020, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Thriller"], "overview": "At a remote lake house in the Adirondack Mountains, a couple entertains an out-of-town guest looking for inspiration in her filmmaking. The group quickly falls into a calculated game of desire, manipulation, and\u2026", "poster": "assets/movie-black-bear-2020-poster.jpg", "backdrop": "assets/movie-black-bear-2020-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 624788, "ratings": {"rtCritics": 89, "rtCriticsLabel": "Certified Fresh", "rtAudience": 64, "rtAudienceLabel": "Upright", "imdb": 6.5, "imdbVotes": 18408, "tmdb": 6.337, "tmdbVotes": 315}}, {"id": "movie-butterfly-on-a-wheel-2007", "title": "Butterfly on a Wheel", "year": 2007, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Crime", "Drama", "Thriller"], "overview": "A sociopathic kidnapper methodically pushes a desperate pair of parents to their absolute breaking point.", "poster": "assets/movie-butterfly-on-a-wheel-2007-poster.jpg", "backdrop": "assets/movie-butterfly-on-a-wheel-2007-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 13250, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": 61, "rtAudienceLabel": "Upright", "imdb": 6.6, "imdbVotes": 35409, "tmdb": 6.457, "tmdbVotes": 595}}, {"id": "movie-careful-what-you-wish-for-2015", "title": "Careful What You Wish For", "year": 2015, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Thriller"], "overview": "A guy gets more than he bargained for after entering into an affair with the wife of an investment banker. Soon, a suspicious death and substantial life insurance policy embroil him in a scandal.", "poster": "assets/movie-careful-what-you-wish-for-2015-poster.jpg", "backdrop": "assets/movie-careful-what-you-wish-for-2015-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 317744, "ratings": {"rtCritics": 17, "rtCriticsLabel": "Rotten", "rtAudience": 61, "rtAudienceLabel": "Upright", "imdb": 5.6, "imdbVotes": 9452, "tmdb": 6.129, "tmdbVotes": 446}}, {"id": "movie-crime-of-passion-1956", "title": "Crime of Passion", "year": 1956, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Crime", "Thriller"], "overview": "Kathy leaves the newspaper business to marry homicide detective Bill, but is frustrated by his lack of ambition and the banality of life in the suburbs. Her drive to advance Bill's career soon takes her down a\u2026", "poster": "assets/movie-crime-of-passion-1956-poster.jpg", "backdrop": "assets/movie-crime-of-passion-1956-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "center_crop", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 1920, "ratings": {"rtCritics": 80, "rtCriticsLabel": "Fresh", "rtAudience": 34, "rtAudienceLabel": "Spilled", "imdb": 6.4, "imdbVotes": 3750, "tmdb": 6.1, "tmdbVotes": 57}}, {"id": "movie-deep-water-2022", "title": "Deep Water", "year": 2022, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Mystery", "Thriller"], "overview": "A well-to-do husband who allows his wife to have affairs in order to avoid a divorce becomes a prime suspect in the disappearance of her lovers.", "poster": "assets/movie-deep-water-2022-poster.jpg", "backdrop": "assets/movie-deep-water-2022-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 619979, "ratings": {"rtCritics": 35, "rtCriticsLabel": "Rotten", "rtAudience": 25, "rtAudienceLabel": "Spilled", "imdb": 5.5, "imdbVotes": 74098, "tmdb": 5.834, "tmdbVotes": 1755}}, {"id": "movie-derailed-2005", "title": "Derailed", "year": 2005, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Thriller"], "overview": "When two married business executives having an affair are blackmailed by a violent criminal, they are forced to turn the tables on him to save their families.", "poster": "assets/movie-derailed-2005-poster.jpg", "backdrop": "assets/movie-derailed-2005-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 8999, "ratings": {"rtCritics": 20, "rtCriticsLabel": "Rotten", "rtAudience": 58, "rtAudienceLabel": "Spilled", "imdb": 6.6, "imdbVotes": 79563, "tmdb": 6.405, "tmdbVotes": 1193}}, {"id": "movie-die-my-love-2025", "title": "Die My Love", "year": 2025, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama"], "overview": "After inheriting a remote Montana house, Jackson moves there from New York with his partner Grace, and the couple soon welcome a child. As Jackson becomes increasingly absent and rural isolation sets in, Grace\u2026", "poster": "assets/movie-die-my-love-2025-poster.jpg", "backdrop": "assets/movie-die-my-love-2025-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 1033148, "ratings": {"rtCritics": 74, "rtCriticsLabel": "Certified Fresh", "rtAudience": 45, "rtAudienceLabel": "Spilled", "imdb": 6, "imdbVotes": 50664, "tmdb": 6.1, "tmdbVotes": 683}}, {"id": "movie-dream-house-2011", "title": "Dream House", "year": 2011, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Mystery", "Drama", "Thriller"], "overview": "Publisher Will Atenton quits a lucrative job in New York to relocate his wife, Libby, and their daughters to a quaint town in New England. However, as they settle into their home the Atentons discover that a woman\u2026", "poster": "assets/movie-dream-house-2011-poster.jpg", "backdrop": "assets/movie-dream-house-2011-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 69668, "ratings": {"rtCritics": 7, "rtCriticsLabel": "Rotten", "rtAudience": 36, "rtAudienceLabel": "Spilled", "imdb": 6, "imdbVotes": 71386, "tmdb": 6.212, "tmdbVotes": 1480}}, {"id": "movie-dream-lover-1994", "title": "Dream Lover", "year": 1994, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Mystery", "Thriller"], "overview": "Not long after they cross paths at an art gallery, architect Ray Reardon and hypnotically sensual Lena are married with children. But as strange incidents occur, Ray begins to realize he may not really know the woman\u2026", "poster": "assets/movie-dream-lover-1994-poster.jpg", "backdrop": "assets/movie-dream-lover-1994-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 18190, "ratings": {"rtCritics": 57, "rtCriticsLabel": "Rotten", "rtAudience": 38, "rtAudienceLabel": "Spilled", "imdb": 6.2, "imdbVotes": 7865, "tmdb": 6.844, "tmdbVotes": 167}}, {"id": "movie-drop-2025", "title": "Drop", "year": 2025, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Mystery", "Thriller"], "overview": "Violet, a widowed mother on her first date in years, arrives at an upscale restaurant where she is relieved that her date, Henry, is more charming and handsome than she expected. But their chemistry begins to curdle\u2026", "poster": "assets/movie-drop-2025-poster.jpg", "backdrop": "assets/movie-drop-2025-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 1249213, "ratings": {"rtCritics": 83, "rtCriticsLabel": "Certified Fresh", "rtAudience": 79, "rtAudienceLabel": "Upright", "imdb": 6.1, "imdbVotes": 61018, "tmdb": 6.275, "tmdbVotes": 1023}}, {"id": "movie-eastern-promises-2007", "title": "Eastern Promises", "year": 2007, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Thriller", "Crime", "Mystery"], "overview": "A Russian teenager living in London dies during childbirth but leaves clues in her diary that could tie her child to a rape involving a violent Russian mob family.", "poster": "assets/movie-eastern-promises-2007-poster.jpg", "backdrop": "assets/movie-eastern-promises-2007-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 2252, "ratings": {"rtCritics": 89, "rtCriticsLabel": "Certified Fresh", "rtAudience": 83, "rtAudienceLabel": "Upright", "imdb": 7.6, "imdbVotes": 281015, "tmdb": 7.349, "tmdbVotes": 3900}}, {"id": "movie-faces-1968", "title": "Faces", "year": 1968, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama"], "overview": "Middle-aged suburban husband Richard abruptly tells his wife, Maria, that he wants a divorce. As Richard takes up with a younger woman, Maria enjoys a night on the town with her friends and meets a younger man. As\u2026", "poster": "assets/movie-faces-1968-poster.jpg", "backdrop": "assets/movie-faces-1968-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "center_crop", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 753, "ratings": {"rtCritics": 83, "rtCriticsLabel": "Fresh", "rtAudience": 86, "rtAudienceLabel": "Upright", "imdb": 7.4, "imdbVotes": 12950, "tmdb": 7.093, "tmdbVotes": 227}}, {"id": "movie-fatale-2020", "title": "Fatale", "year": 2020, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Thriller"], "overview": "After a wild one-night stand, successful sports agent Derrick Tyler watches his perfect life slowly disappear when he discovers the sexy and mysterious woman he risked everything for is determined police detective\u2026", "poster": "assets/movie-fatale-2020-poster.jpg", "backdrop": "assets/movie-fatale-2020-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 549514, "ratings": {"rtCritics": 46, "rtCriticsLabel": "Rotten", "rtAudience": 87, "rtAudienceLabel": "Upright", "imdb": 5.5, "imdbVotes": 16392, "tmdb": 6, "tmdbVotes": 401}}, {"id": "tv-56-days-2026", "title": "56 Days", "year": 2026, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Crime", "Mystery"], "overview": "When an unidentified body is found in a luxury apartment linked to Oliver Kennedy and his girlfriend Ciara Wyse, Detectives Lee Reardon and Karl Connolly reconstruct the couple's deadly romance across the past 56 days.", "poster": "assets/tv-56-days-2026-poster.jpg", "backdrop": "assets/tv-56-days-2026-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 241372, "ratings": {"rtCritics": 60, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.388, "tmdbVotes": 245}}, {"id": "tv-90-day-fiance-before-the-90-days-2017", "title": "90 Day Fianc\u00e9: Before the 90 Days", "year": 2017, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Reality"], "overview": "Follow couples who have an existing relationship online, but haven't met in person. We'll experience their journey as they travel to the other's foreign country for the first time in an attempt to establish an\u2026", "poster": "assets/tv-90-day-fiance-before-the-90-days-2017-poster.jpg", "backdrop": "assets/tv-90-day-fiance-before-the-90-days-2017-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 73319, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.5, "tmdbVotes": 45}}, {"id": "tv-90-day-fiance-the-other-way-2019", "title": "90 Day Fianc\u00e9: The Other Way", "year": 2019, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Reality"], "overview": "Americans move to a foreign country all in the name of love. Will uprooting their lives in the United States pay off, or will they be packing up and moving back to America brokenhearted?", "poster": "assets/tv-90-day-fiance-the-other-way-2019-poster.jpg", "backdrop": "assets/tv-90-day-fiance-the-other-way-2019-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 90046, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.8, "tmdbVotes": 34}}, {"id": "tv-absolutely-fabulous-1992", "title": "Absolutely Fabulous", "year": 1992, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Comedy"], "overview": "Set in the world of fashion and PR, immature fun-loving mother Edina Monsoon and her best friend Patsy drive Eddie's sensible daughter, Saffron, up the wall with their constant drug abuse and outrageous selfishness.\u2026", "poster": "assets/tv-absolutely-fabulous-1992-poster.jpg", "backdrop": "assets/tv-absolutely-fabulous-1992-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 4493, "ratings": {"rtCritics": 96, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.6, "tmdbVotes": 198}}, {"id": "tv-the-afterparty-2022", "title": "The Afterparty", "year": 2022, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Mystery", "Comedy", "Crime"], "overview": "Nothing is as it seems in this hilarious murder mystery where each suspect's story is told through a different film genre.", "poster": "assets/tv-the-afterparty-2022-poster.jpg", "backdrop": "assets/tv-the-afterparty-2022-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 106454, "ratings": {"rtCritics": 92, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.071, "tmdbVotes": 245}}, {"id": "tv-agatha-christie-s-marple-2004", "title": "Agatha Christie's Marple", "year": 2004, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Crime", "Mystery"], "overview": "The adventures of Miss Jane Marple, an elderly spinster living in the quiet little village of St Mary Mead. During her many visits to friends and relatives in other villages, Miss Marple often stumbles upon\u2026", "poster": "assets/tv-agatha-christie-s-marple-2004-poster.jpg", "backdrop": "assets/tv-agatha-christie-s-marple-2004-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 6127, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.9, "tmdbVotes": 152}}, {"id": "tv-all-american-homecoming-2022", "title": "All American: Homecoming", "year": 2022, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama"], "overview": "Follow the journeys of Simone Hicks, a tennis hopeful from Beverly Hills, and elite baseball player Damon Sims from Chicago, as they navigate life at the prestigious HBCU Bringston University.", "poster": "assets/tv-all-american-homecoming-2022-poster.jpg", "backdrop": "assets/tv-all-american-homecoming-2022-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 153723, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.3, "tmdbVotes": 70}}, {"id": "tv-and-just-like-that-2021", "title": "And Just Like That\u2026", "year": 2021, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "This new chapter of \u201cSex and the City\u201d follows Carrie, Miranda and Charlotte as they navigate the journey from the complicated reality of life and friendship in their 30s to the even more complicated reality of life\u2026", "poster": "assets/tv-and-just-like-that-2021-poster.jpg", "backdrop": "assets/tv-and-just-like-that-2021-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 116450, "ratings": {"rtCritics": 52, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.211, "tmdbVotes": 556}}, {"id": "tv-anne-with-an-e-2017", "title": "Anne with an E", "year": 2017, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Family"], "overview": "A coming-of-age story about an outsider who, against all odds and numerous challenges, fights for love and acceptance and for her place in the world. The series centers on a young orphaned girl in the late 1890s,\u2026", "poster": "assets/tv-anne-with-an-e-2017-poster.jpg", "backdrop": "assets/tv-anne-with-an-e-2017-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 70785, "ratings": {"rtCritics": 63, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.7, "tmdbVotes": 5019}}, {"id": "tv-awkward-2011", "title": "Awkward.", "year": 2011, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "An irreverent look at the conflict, chaos and humor that defines teenage life through the eyes of 15-year-old Jenna Hamilton whose life begins to change when a simple accident becomes an epic misunderstanding and is\u2026", "poster": "assets/tv-awkward-2011-poster.jpg", "backdrop": "assets/tv-awkward-2011-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 39859, "ratings": {"rtCritics": 78, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.4, "tmdbVotes": 427}}, {"id": "tv-the-baby-sitters-club-2020", "title": "The Baby-Sitters Club", "year": 2020, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Kids", "Drama"], "overview": "In this contemporary take on the beloved book series, five best friends launch a baby-sitting business that's big on fun and adventure.", "poster": "assets/tv-the-baby-sitters-club-2020-poster.jpg", "backdrop": "assets/tv-the-baby-sitters-club-2020-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 100412, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.9, "tmdbVotes": 506}}, {"id": "tv-ballers-2015", "title": "Ballers", "year": 2015, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Comedy"], "overview": "Looking at the lives of former and current football players, the show follows former superstar Spencer Strasmore as he gets his life on track in retirement while mentoring other current and former players through the\u2026", "poster": "assets/tv-ballers-2015-poster.jpg", "backdrop": "assets/tv-ballers-2015-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 62704, "ratings": {"rtCritics": 72, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.809, "tmdbVotes": 820}}, {"id": "tv-baretta-1975", "title": "Baretta", "year": 1975, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Crime", "Drama", "Mystery"], "overview": "Baretta is an American detective television series which ran on ABC from 1975 to 1978. The show was a milder version of a successful 1973\u201374 ABC series, Toma, starring Tony Musante as chameleon-like, real-life New\u2026", "poster": "assets/tv-baretta-1975-poster.jpg", "backdrop": "assets/tv-baretta-1975-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 3216, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.5, "tmdbVotes": 43}}, {"id": "tv-based-on-a-true-story-2023", "title": "Based on a True Story", "year": 2023, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "The lives of a realtor, a plumber and a former tennis star unexpectedly collide, exposing America\u2019s obsession with true crime, murder and the slow-close toilet seat.", "poster": "assets/tv-based-on-a-true-story-2023-poster.jpg", "backdrop": "assets/tv-based-on-a-true-story-2023-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 197373, "ratings": {"rtCritics": 79, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7, "tmdbVotes": 160}}, {"id": "tv-the-beast-in-me-2025", "title": "The Beast in Me", "year": 2025, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Mystery"], "overview": "A famous author is pulled into a twisted mind game with her rich, powerful new neighbor \u2014 who might be a murderer.", "poster": "assets/tv-the-beast-in-me-2025-poster.jpg", "backdrop": "assets/tv-the-beast-in-me-2025-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 250504, "ratings": {"rtCritics": 85, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.072, "tmdbVotes": 334}}, {"id": "tv-big-city-greens-2018", "title": "Big City Greens", "year": 2018, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Family", "Animation", "Comedy"], "overview": "The offbeat adventures of 10-year-old Cricket Green, a mischievous and optimistic country boy who moves to the big city with his wildly out of place family \u2013 older sister Tilly, father Bill and Gramma Alice.", "poster": "assets/tv-big-city-greens-2018-poster.jpg", "backdrop": "assets/tv-big-city-greens-2018-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 80587, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.555, "tmdbVotes": 82}}, {"id": "tv-the-bold-type-2017", "title": "The Bold Type", "year": 2017, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Comedy"], "overview": "A glimpse into the outrageous lives of Jane, Kat and Sutton, who are working at the nation's top women's magazine, Scarlet, while navigating their careers, identities and individual voices.", "poster": "assets/tv-the-bold-type-2017-poster.jpg", "backdrop": "assets/tv-the-bold-type-2017-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 69630, "ratings": {"rtCritics": 89, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.7, "tmdbVotes": 204}}, {"id": "tv-brassic-2019", "title": "Brassic", "year": 2019, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Comedy", "Drama", "Crime"], "overview": "A group of working-class friends finding unconventional ways to win at life in suburban northern England. These lads have dealt, scammed, bribed and conned their way through adolescence, but now, their dealing and\u2026", "poster": "assets/tv-brassic-2019-poster.jpg", "backdrop": "assets/tv-brassic-2019-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 92621, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.336, "tmdbVotes": 263}}], "discoverySource": {"state": "materialized_snapshot", "rankKnown": false, "selection": "First 18 alphabetically indexed movie stubs and first 18 series stubs, not ranked feed order", "observedAt": "2026-11-04T20:42:12.030108+00:00"}}, {"key": "shared", "name": "Shared", "initial": "S", "color": "#9be38f", "destinations": {"Home": {"kind": "home"}, "Movies": {"kind": "library", "collection": "movies"}, "Shows": {"kind": "library", "collection": "shows"}, "Discover": {"kind": "discover", "collection": "discover"}}, "movies": [{"id": "movie-american-gangster-2007", "title": "American Gangster", "year": 2007, "type": "movie", "runtimeSeconds": 10546, "seasonCount": null, "communityRating": 7.595, "criticRating": 81, "genres": ["Drama", "Crime"], "overview": "Loosely based on the criminal career of Frank Lucas, a gangster from La Grange, North Carolina, who smuggled heroin into the United States on American service planes returning from the Vietnam War, before being\u2026", "poster": "assets/movie-american-gangster-2007-poster.jpg", "backdrop": "assets/movie-american-gangster-2007-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-08-23T10:22:36.0000000Z", "lastPlayedAt": "2026-08-30T21:05:39.7952451Z", "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 4982, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 81, "rtCriticsLabel": "Certified Fresh", "rtAudience": 90, "rtAudienceLabel": "Upright", "imdb": 7.8, "imdbVotes": 495656, "tmdb": 7.599, "tmdbVotes": 6350}}, {"id": "movie-annie-hall-1977", "title": "Annie Hall", "year": 1977, "type": "movie", "runtimeSeconds": 5604, "seasonCount": null, "communityRating": 7.712, "criticRating": 97, "genres": ["Comedy", "Drama", "Romance"], "overview": "New York comedian Alvy Singer falls in love with the ditsy Annie Hall.", "poster": "assets/movie-annie-hall-1977-poster.jpg", "backdrop": "assets/movie-annie-hall-1977-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:24:23.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 703, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 97, "rtCriticsLabel": "Certified Fresh", "rtAudience": 92, "rtAudienceLabel": "Upright", "imdb": 7.9, "imdbVotes": 293349, "tmdb": 7.71, "tmdbVotes": 4391}}, {"id": "movie-apocalypse-now-1979", "title": "Apocalypse Now", "year": 1979, "type": "movie", "runtimeSeconds": 8835, "seasonCount": null, "communityRating": 8.261, "criticRating": 91, "genres": ["Drama", "War"], "overview": "At the height of the Vietnam war, Captain Benjamin Willard is sent on a dangerous mission that, officially, \"does not exist, nor will it ever exist.\" His goal is to locate - and eliminate - a mysterious Green Beret\u2026", "poster": "assets/movie-apocalypse-now-1979-poster.jpg", "backdrop": "assets/movie-apocalypse-now-1979-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:22:25.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 28, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 91, "rtCriticsLabel": "Certified Fresh", "rtAudience": 94, "rtAudienceLabel": "Upright", "imdb": 8.4, "imdbVotes": 781424, "tmdb": 8.3, "tmdbVotes": 9526}}, {"id": "movie-arrival-2016", "title": "Arrival", "year": 2016, "type": "movie", "runtimeSeconds": 6967, "seasonCount": null, "communityRating": 7.636, "criticRating": 94, "genres": ["Drama", "Science Fiction", "Mystery"], "overview": "Taking place after alien crafts land around the world, an expert linguist is recruited by the military to determine whether they come in peace or are a threat.", "poster": "assets/movie-arrival-2016-poster.jpg", "backdrop": "assets/movie-arrival-2016-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-14T19:54:12.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 329865, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 94, "rtCriticsLabel": "Certified Fresh", "rtAudience": 83, "rtAudienceLabel": "Upright", "imdb": 7.9, "imdbVotes": 883621, "tmdb": 7.638, "tmdbVotes": 20125}}, {"id": "movie-avatar-aang-the-last-airbender-2026", "title": "Avatar Aang: The Last Airbender", "year": 2026, "type": "movie", "runtimeSeconds": 5930, "seasonCount": null, "communityRating": 9.147, "criticRating": 90, "genres": ["Animation", "Adventure", "Fantasy"], "overview": "Avatar Aang, the world's last Airbender, learns of an ancient power that could save his culture from extinction. With the help of his friends, he embarks on a global quest to find it before it falls into the wrong\u2026", "poster": "assets/movie-avatar-aang-the-last-airbender-2026-poster.jpg", "backdrop": "assets/movie-avatar-aang-the-last-airbender-2026-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-25T09:53:09.0000000Z", "lastPlayedAt": "2026-08-02T19:22:33.6155383Z", "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 980431, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 90, "rtCriticsLabel": "Certified Fresh", "rtAudience": 99, "rtAudienceLabel": "Upright", "imdb": 7.7, "imdbVotes": 30792, "tmdb": 9, "tmdbVotes": 1417}}, {"id": "movie-bohemian-rhapsody-2018", "title": "Bohemian Rhapsody", "year": 2018, "type": "movie", "runtimeSeconds": 8077, "seasonCount": null, "communityRating": 7.95, "criticRating": 60, "genres": ["Music", "Drama"], "overview": "Singer Freddie Mercury, guitarist Brian May, drummer Roger Taylor and bass guitarist John Deacon take the music world by storm when they form the rock 'n' roll band Queen in 1970. Hit songs become instant classics.\u2026", "poster": "assets/movie-bohemian-rhapsody-2018-poster.jpg", "backdrop": "assets/movie-bohemian-rhapsody-2018-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:28:20.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 424694, "artwork": {"posterKind": "center_crop", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 60, "rtCriticsLabel": "Fresh", "rtAudience": 85, "rtAudienceLabel": "Upright", "imdb": 7.9, "imdbVotes": 655894, "tmdb": 7.947, "tmdbVotes": 18196}}, {"id": "movie-the-boy-and-the-heron-2023", "title": "The Boy and the Heron", "year": 2023, "type": "movie", "runtimeSeconds": 7437, "seasonCount": null, "communityRating": 7.4, "criticRating": 96, "genres": ["Animation", "Fantasy", "Drama"], "overview": "While the Second World War rages, the teenage Mahito, haunted by his mother's tragic death, is relocated from Tokyo to the serene rural home of his new stepmother Natsuko, a woman who bears a striking resemblance to\u2026", "poster": "assets/movie-the-boy-and-the-heron-2023-poster.jpg", "backdrop": "assets/movie-the-boy-and-the-heron-2023-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:25:15.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 508883, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 96, "rtCriticsLabel": "Certified Fresh", "rtAudience": 88, "rtAudienceLabel": "Upright", "imdb": 7.3, "imdbVotes": 152169, "tmdb": 7.387, "tmdbVotes": 2893}}, {"id": "movie-braveheart-1995", "title": "Braveheart", "year": 1995, "type": "movie", "runtimeSeconds": 10665, "seasonCount": null, "communityRating": 7.945, "criticRating": 74, "genres": ["Drama", "History", "War"], "overview": "Enraged at the slaughter of Murron, his new bride and childhood love, Scottish warrior William Wallace slays a platoon of the local English lord's soldiers. This leads the village to revolt and, eventually, the\u2026", "poster": "assets/movie-braveheart-1995-poster.jpg", "backdrop": "assets/movie-braveheart-1995-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-10T21:24:28.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 197, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 74, "rtCriticsLabel": "Certified Fresh", "rtAudience": 85, "rtAudienceLabel": "Upright", "imdb": 8.3, "imdbVotes": 1174990, "tmdb": 7.947, "tmdbVotes": 11584}}, {"id": "movie-the-breakfast-club-1985", "title": "The Breakfast Club", "year": 1985, "type": "movie", "runtimeSeconds": 5833, "seasonCount": null, "communityRating": 7.7, "criticRating": 87, "genres": ["Comedy", "Drama"], "overview": "Five high school students from different walks of life endure a Saturday detention under a power-hungry principal. The disparate group includes rebel John, princess Claire, outcast Allison, brainy Brian and Andrew,\u2026", "poster": "assets/movie-the-breakfast-club-1985-poster.jpg", "backdrop": "assets/movie-the-breakfast-club-1985-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:25:03.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 2108, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 87, "rtCriticsLabel": "Certified Fresh", "rtAudience": 92, "rtAudienceLabel": "Upright", "imdb": 7.8, "imdbVotes": 478743, "tmdb": 7.713, "tmdbVotes": 8815}}, {"id": "movie-castle-in-the-sky-1986", "title": "Castle in the Sky", "year": 1986, "type": "movie", "runtimeSeconds": 7474, "seasonCount": null, "communityRating": 8, "criticRating": 97, "genres": ["Adventure", "Fantasy", "Animation"], "overview": "A young boy and a girl with a magic crystal must race against pirates and foreign agents in a search for a legendary floating castle.", "poster": "assets/movie-castle-in-the-sky-1986-poster.jpg", "backdrop": "assets/movie-castle-in-the-sky-1986-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:23:09.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 10515, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 96, "rtCriticsLabel": "Fresh", "rtAudience": 91, "rtAudienceLabel": "Upright", "imdb": 8, "imdbVotes": 201545, "tmdb": 7.972, "tmdbVotes": 4868}}, {"id": "movie-citizen-kane-1941", "title": "Citizen Kane", "year": 1941, "type": "movie", "runtimeSeconds": 7173, "seasonCount": null, "communityRating": 7.966, "criticRating": 99, "genres": ["Mystery", "Drama"], "overview": "Newspaper magnate Charles Foster Kane is taken from his mother as a boy and made the ward of a rich industrialist. As a result, every well-meaning, tyrannical or self-destructive move he makes for the rest of his\u2026", "poster": "assets/movie-citizen-kane-1941-poster.jpg", "backdrop": "assets/movie-citizen-kane-1941-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:22:16.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 15, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 99, "rtCriticsLabel": "Certified Fresh", "rtAudience": 98, "rtAudienceLabel": "Upright", "imdb": 8.2, "imdbVotes": 498321, "tmdb": 7.962, "tmdbVotes": 6324}}, {"id": "movie-conclave-2024", "title": "Conclave", "year": 2024, "type": "movie", "runtimeSeconds": 7230, "seasonCount": null, "communityRating": 7.19, "criticRating": 93, "genres": ["Drama", "Thriller"], "overview": "After the unexpected death of the Pope, Cardinal Lawrence is tasked with managing the covert and ancient ritual of electing a new one. Sequestered in the Vatican with the Catholic Church\u2019s most powerful leaders until\u2026", "poster": "assets/movie-conclave-2024-poster.jpg", "backdrop": "assets/movie-conclave-2024-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:30:41.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 974576, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 93, "rtCriticsLabel": "Certified Fresh", "rtAudience": 86, "rtAudienceLabel": "Upright", "imdb": 7.4, "imdbVotes": 290498, "tmdb": 7.19, "tmdbVotes": 3744}}, {"id": "movie-the-dry-2021", "title": "The Dry", "year": 2021, "type": "movie", "runtimeSeconds": 7037, "seasonCount": null, "communityRating": 6.779, "criticRating": null, "genres": ["Crime", "Thriller", "Mystery"], "overview": "Aaron Falk returns to his drought-stricken hometown to attend a tragic funeral. But his return opens a decades-old wound - the unsolved death of a teenage girl.", "poster": "assets/movie-the-dry-2021-poster.jpg", "backdrop": "assets/movie-the-dry-2021-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:29:20.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 567797, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 90, "rtCriticsLabel": "Certified Fresh", "rtAudience": 89, "rtAudienceLabel": "Upright", "imdb": 6.8, "imdbVotes": 41935, "tmdb": 6.8, "tmdbVotes": 892}}, {"id": "movie-easy-a-2010", "title": "Easy A", "year": 2010, "type": "movie", "runtimeSeconds": 5545, "seasonCount": null, "communityRating": 6.8, "criticRating": 85, "genres": ["Comedy"], "overview": "Olive, an average high school student, sees her below-the-radar existence turn around overnight once she decides to use the school's gossip grapevine to advance her social standing. Now her classmates are turning\u2026", "poster": "assets/movie-easy-a-2010-poster.jpg", "backdrop": "assets/movie-easy-a-2010-backdrop.jpg", "played": true, "playCount": 1, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-17T19:59:04.0000000Z", "lastPlayedAt": "2026-10-17T20:02:51.1083337Z", "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 37735, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 85, "rtCriticsLabel": "Certified Fresh", "rtAudience": 77, "rtAudienceLabel": "Upright", "imdb": 7, "imdbVotes": 448780, "tmdb": 6.8, "tmdbVotes": 7619}}, {"id": "movie-el-camino-a-breaking-bad-movie-2019", "title": "El Camino: A Breaking Bad Movie", "year": 2019, "type": "movie", "runtimeSeconds": 7362, "seasonCount": null, "communityRating": 7.055, "criticRating": 92, "genres": ["Crime", "Drama", "Thriller"], "overview": "In the wake of his dramatic escape from captivity, Jesse Pinkman must come to terms with his past in order to forge some kind of future.", "poster": "assets/movie-el-camino-a-breaking-bad-movie-2019-poster.jpg", "backdrop": "assets/movie-el-camino-a-breaking-bad-movie-2019-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-21T23:31:11.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 559969, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 92, "rtCriticsLabel": "Certified Fresh", "rtAudience": 81, "rtAudienceLabel": "Upright", "imdb": 7.3, "imdbVotes": 354488, "tmdb": 7.056, "tmdbVotes": 5950}}, {"id": "movie-emancipation-2022", "title": "Emancipation", "year": 2022, "type": "movie", "runtimeSeconds": 7949, "seasonCount": null, "communityRating": 7.7, "criticRating": 45, "genres": ["Drama", "War", "History"], "overview": "Inspired by the gripping true story of a man who would do anything for his family\u2014and for freedom. When Peter, an enslaved man, risks his life to escape and return to his family, he embarks on a perilous journey of\u2026", "poster": "assets/movie-emancipation-2022-poster.jpg", "backdrop": "assets/movie-emancipation-2022-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-10T20:37:34.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 715931, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 45, "rtCriticsLabel": "Rotten", "rtAudience": 58, "rtAudienceLabel": "Spilled", "imdb": 6.3, "imdbVotes": 32079, "tmdb": 7.744, "tmdbVotes": 1319}}, {"id": "movie-fighting-with-my-family-2019", "title": "Fighting with My Family", "year": 2019, "type": "movie", "runtimeSeconds": 6509, "seasonCount": null, "communityRating": 6.84, "criticRating": 93, "genres": ["Comedy"], "overview": "Born into a tight-knit wrestling family, Paige and her brother Zak are ecstatic when they get the once-in-a-lifetime opportunity to try out for the WWE. But when only Paige earns a spot in the competitive training\u2026", "poster": "assets/movie-fighting-with-my-family-2019-poster.jpg", "backdrop": "assets/movie-fighting-with-my-family-2019-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-22T22:10:59.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 445629, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 93, "rtCriticsLabel": "Certified Fresh", "rtAudience": 86, "rtAudienceLabel": "Upright", "imdb": 7, "imdbVotes": 94576, "tmdb": 6.837, "tmdbVotes": 1952}}, {"id": "movie-force-of-nature-the-dry-2-2024", "title": "Force of Nature: The Dry 2", "year": 2024, "type": "movie", "runtimeSeconds": 6753, "seasonCount": null, "communityRating": 6.3, "criticRating": 66, "genres": ["Mystery", "Thriller"], "overview": "When five women take part in a corporate hiking retreat and only four come out on the other side, Federal Agents Aaron Falk and Carmen Cooper head deep into the Victorian mountain ranges to investigate in the hopes\u2026", "poster": "assets/movie-force-of-nature-the-dry-2-2024-poster.jpg", "backdrop": "assets/movie-force-of-nature-the-dry-2-2024-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:29:49.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 832262, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 66, "rtCriticsLabel": "Fresh", "rtAudience": 43, "rtAudienceLabel": "Spilled", "imdb": 5.9, "imdbVotes": 10343, "tmdb": 6.269, "tmdbVotes": 305}}, {"id": "movie-free-state-of-jones-2016", "title": "Free State of Jones", "year": 2016, "type": "movie", "runtimeSeconds": 8376, "seasonCount": null, "communityRating": 6.79, "criticRating": 48, "genres": ["Action", "Drama", "History"], "overview": "In 1863, Mississippi farmer Newt Knight serves as a medic for the Confederate Army. Opposed to slavery, Knight would rather help the wounded than fight the Union. After his nephew dies in battle, Newt returns home to\u2026", "poster": "assets/movie-free-state-of-jones-2016-poster.jpg", "backdrop": "assets/movie-free-state-of-jones-2016-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-11T17:56:53.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 316152, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 48, "rtCriticsLabel": "Rotten", "rtAudience": 64, "rtAudienceLabel": "Upright", "imdb": 6.9, "imdbVotes": 68931, "tmdb": 6.788, "tmdbVotes": 1730}}, {"id": "movie-from-up-on-poppy-hill-2011", "title": "From Up on Poppy Hill", "year": 2011, "type": "movie", "runtimeSeconds": 5482, "seasonCount": null, "communityRating": 7.5, "criticRating": 87, "genres": ["Animation", "Drama"], "overview": "Yokohama, 1963. Japan is picking itself up from the devastation of World War II and preparing to host the 1964 Olympics\u2014and the mood is one of both optimism and conflict as the young generation struggles to throw off\u2026", "poster": "assets/movie-from-up-on-poppy-hill-2011-poster.jpg", "backdrop": "assets/movie-from-up-on-poppy-hill-2011-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-07T14:41:03.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 83389, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 87, "rtCriticsLabel": "Certified Fresh", "rtAudience": 80, "rtAudienceLabel": "Upright", "imdb": 7.4, "imdbVotes": 60769, "tmdb": 7.509, "tmdbVotes": 2026}}, {"id": "movie-ghost-in-the-shell-1995", "title": "Ghost in the Shell", "year": 1995, "type": "movie", "runtimeSeconds": 4959, "seasonCount": null, "communityRating": 7.929, "criticRating": 95, "genres": ["Action", "Animation", "Science Fiction"], "overview": "In the year 2029, the barriers of our world have been broken down by the net and by cybernetics, but this brings new vulnerability to humans in the form of brain-hacking. When a highly-wanted hacker known as 'The\u2026", "poster": "assets/movie-ghost-in-the-shell-1995-poster.jpg", "backdrop": "assets/movie-ghost-in-the-shell-1995-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:22:57.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 9323, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 97, "rtCriticsLabel": "Certified Fresh", "rtAudience": 90, "rtAudienceLabel": "Upright", "imdb": 7.9, "imdbVotes": 178061, "tmdb": 7.928, "tmdbVotes": 4130}}, {"id": "movie-ghost-in-the-shell-2-innocence-2004", "title": "Ghost in the Shell 2: Innocence", "year": 2004, "type": "movie", "runtimeSeconds": 5950, "seasonCount": null, "communityRating": 7.352, "criticRating": 65, "genres": ["Animation", "Drama", "Science Fiction"], "overview": "Cyborg detective Batou is assigned to investigate a series of murders committed by gynoids\u2014doll-like cyborgs, which all malfunctioned, killed, then self-destructed afterwards. The brains of the gynoids initialize in\u2026", "poster": "assets/movie-ghost-in-the-shell-2-innocence-2004-poster.jpg", "backdrop": "assets/movie-ghost-in-the-shell-2-innocence-2004-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:23:38.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 12140, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 65, "rtCriticsLabel": "Fresh", "rtAudience": 80, "rtAudienceLabel": "Upright", "imdb": 7.4, "imdbVotes": 43280, "tmdb": 7.356, "tmdbVotes": 1049}}, {"id": "movie-the-godfather-1972", "title": "The Godfather", "year": 1972, "type": "movie", "runtimeSeconds": 10603, "seasonCount": null, "communityRating": 8.687, "criticRating": 97, "genres": ["Drama", "Crime"], "overview": "Spanning the years 1945 to 1955, a chronicle of the fictional Italian-American Corleone crime family. When organized crime family patriarch, Vito Corleone barely survives an attempt on his life, his youngest son,\u2026", "poster": "assets/movie-the-godfather-1972-poster.jpg", "backdrop": "assets/movie-the-godfather-1972-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:24:12.0000000Z", "lastPlayedAt": "2026-09-18T19:24:44.9855867Z", "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 238, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 97, "rtCriticsLabel": "Certified Fresh", "rtAudience": 98, "rtAudienceLabel": "Upright", "imdb": 9.2, "imdbVotes": 2262024, "tmdb": 8.688, "tmdbVotes": 23907}}, {"id": "movie-the-godfather-part-ii-1974", "title": "The Godfather Part II", "year": 1974, "type": "movie", "runtimeSeconds": 12031, "seasonCount": null, "communityRating": 8.573, "criticRating": 96, "genres": ["Drama", "Crime"], "overview": "In the continuing saga of the Corleone crime family, a young Vito Corleone grows up in Sicily and in 1910s New York. In the 1950s, Michael Corleone attempts to expand the family business into Las Vegas, Hollywood and\u2026", "poster": "assets/movie-the-godfather-part-ii-1974-poster.jpg", "backdrop": "assets/movie-the-godfather-part-ii-1974-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:24:18.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 240, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 96, "rtCriticsLabel": "Certified Fresh", "rtAudience": 97, "rtAudienceLabel": "Upright", "imdb": 9, "imdbVotes": 1521308, "tmdb": 8.571, "tmdbVotes": 14559}}, {"id": "movie-the-godfather-part-iii-1990", "title": "The Godfather Part III", "year": 1990, "type": "movie", "runtimeSeconds": 9476, "seasonCount": null, "communityRating": 7.416, "criticRating": 67, "genres": ["Crime", "Drama", "Thriller"], "overview": "In the midst of trying to legitimize his business dealings in 1979 New York and Italy, aging mafia don, Michael Corleone seeks forgiveness for his sins while taking a young protege under his wing.", "poster": "assets/movie-the-godfather-part-iii-1990-poster.jpg", "backdrop": "assets/movie-the-godfather-part-iii-1990-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:26:29.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 242, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 68, "rtCriticsLabel": "Fresh", "rtAudience": 68, "rtAudienceLabel": "Upright", "imdb": 7.5, "imdbVotes": 462448, "tmdb": 7.413, "tmdbVotes": 7159}}, {"id": "movie-gosford-park-2001", "title": "Gosford Park", "year": 2001, "type": "movie", "runtimeSeconds": 8247, "seasonCount": null, "communityRating": 6.815, "criticRating": 87, "genres": ["Drama", "Mystery", "Thriller"], "overview": "In 1930s England, a group of pretentious rich and famous gather together for a weekend of relaxation at a hunting resort. But when a murder occurs, each one of these interesting characters becomes a suspect.", "poster": "assets/movie-gosford-park-2001-poster.jpg", "backdrop": "assets/movie-gosford-park-2001-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:25:49.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 5279, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 87, "rtCriticsLabel": "Certified Fresh", "rtAudience": 78, "rtAudienceLabel": "Upright", "imdb": 7.2, "imdbVotes": 103883, "tmdb": 6.822, "tmdbVotes": 1317}}, {"id": "movie-grave-of-the-fireflies-1988", "title": "Grave of the Fireflies", "year": 1988, "type": "movie", "runtimeSeconds": 5313, "seasonCount": null, "communityRating": 8.45, "criticRating": 100, "genres": ["Animation", "Drama", "War"], "overview": "In the final months of World War II, 14-year-old Seita and his sister Setsuko are orphaned when their mother is killed during an air raid in Kobe, Japan. After a falling out with their aunt, they move into an\u2026", "poster": "assets/movie-grave-of-the-fireflies-1988-poster.jpg", "backdrop": "assets/movie-grave-of-the-fireflies-1988-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:24:14.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 12477, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Certified Fresh", "rtAudience": 95, "rtAudienceLabel": "Upright", "imdb": 8.5, "imdbVotes": 399802, "tmdb": 8.45, "tmdbVotes": 6938}}, {"id": "movie-the-great-gatsby-2013", "title": "The Great Gatsby", "year": 2013, "type": "movie", "runtimeSeconds": 8525, "seasonCount": null, "communityRating": 7.346, "criticRating": 49, "genres": ["Drama", "Romance"], "overview": "Nick Carraway arrives in New York in 1922, an era of loose morals, glittering jazz and bootleg kings. Chasing his own American Dream, Nick encounters the mysterious millionaire Gatsby and his bewitching cousin Daisy.\u2026", "poster": "assets/movie-the-great-gatsby-2013-poster.jpg", "backdrop": "assets/movie-the-great-gatsby-2013-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:26:50.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 64682, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 48, "rtCriticsLabel": "Rotten", "rtAudience": 67, "rtAudienceLabel": "Upright", "imdb": 7.2, "imdbVotes": 651882, "tmdb": 7.346, "tmdbVotes": 13290}}, {"id": "movie-the-hours-2002", "title": "The Hours", "year": 2002, "type": "movie", "runtimeSeconds": 6887, "seasonCount": null, "communityRating": 7.25, "criticRating": 79, "genres": ["Drama"], "overview": "The story of three women searching for more potent, meaningful lives. Each is alive at a different time and place, all are linked by their yearnings and their fears. Their stories intertwine, and finally come\u2026", "poster": "assets/movie-the-hours-2002-poster.jpg", "backdrop": "assets/movie-the-hours-2002-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:23:27.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 590, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 79, "rtCriticsLabel": "Certified Fresh", "rtAudience": 84, "rtAudienceLabel": "Upright", "imdb": 7.5, "imdbVotes": 148367, "tmdb": 7.249, "tmdbVotes": 1931}}, {"id": "movie-howl-s-moving-castle-2004", "title": "Howl's Moving Castle", "year": 2004, "type": "movie", "runtimeSeconds": 7149, "seasonCount": null, "communityRating": 8.4, "criticRating": 88, "genres": ["Fantasy", "Animation", "Adventure"], "overview": "Sophie, a young milliner, is turned into an elderly woman by a witch who enters her shop and curses her. She encounters a wizard named Howl and gets caught up in his resistance to fighting for the king.", "poster": "assets/movie-howl-s-moving-castle-2004-poster.jpg", "backdrop": "assets/movie-howl-s-moving-castle-2004-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:22:47.0000000Z", "lastPlayedAt": "2026-05-21T18:46:08.0000000Z", "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 4935, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 87, "rtCriticsLabel": "Certified Fresh", "rtAudience": 93, "rtAudienceLabel": "Upright", "imdb": 8.2, "imdbVotes": 524520, "tmdb": 8.391, "tmdbVotes": 11642}}, {"id": "movie-in-the-heights-2021", "title": "In the Heights", "year": 2021, "type": "movie", "runtimeSeconds": 8579, "seasonCount": null, "communityRating": 7.111, "criticRating": null, "genres": ["Drama", "Romance"], "overview": "The story of Usnavi, a bodega owner who has mixed feelings about closing his store and retiring to the Dominican Republic or staying in Washington Heights.", "poster": "assets/movie-in-the-heights-2021-poster.jpg", "backdrop": "assets/movie-in-the-heights-2021-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:29:11.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 467909, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 94, "rtCriticsLabel": "Certified Fresh", "rtAudience": 94, "rtAudienceLabel": "Upright", "imdb": 7.2, "imdbVotes": 56513, "tmdb": 7.104, "tmdbVotes": 826}}, {"id": "movie-jennifer-s-body-2009", "title": "Jennifer's Body", "year": 2009, "type": "movie", "runtimeSeconds": 6450, "seasonCount": null, "communityRating": 6.012, "criticRating": 47, "genres": ["Horror", "Comedy"], "overview": "Jennifer, a gorgeous, seductive cheerleader takes evil to a whole new level after she's possessed by a sinister demon. Now it's up to her best friend to stop Jennifer's reign of terror before it's too late.", "poster": "assets/movie-jennifer-s-body-2009-poster.jpg", "backdrop": "assets/movie-jennifer-s-body-2009-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-30T03:37:04.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 19994, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 47, "rtCriticsLabel": "Rotten", "rtAudience": 36, "rtAudienceLabel": "Spilled", "imdb": 5.6, "imdbVotes": 179710, "tmdb": 6.013, "tmdbVotes": 4481}}, {"id": "movie-kiki-s-delivery-service-1989", "title": "Kiki's Delivery Service", "year": 1989, "type": "movie", "runtimeSeconds": 6183, "seasonCount": null, "communityRating": 7.839, "criticRating": null, "genres": ["Animation", "Family", "Fantasy"], "overview": "A young witch, on her mandatory year of independent life, finds fitting into a new community difficult while she supports herself by running an air courier service.", "poster": "assets/movie-kiki-s-delivery-service-1989-poster.jpg", "backdrop": "assets/movie-kiki-s-delivery-service-1989-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:24:20.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 16859, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 98, "rtCriticsLabel": "Certified Fresh", "rtAudience": 89, "rtAudienceLabel": "Upright", "imdb": 7.8, "imdbVotes": 192477, "tmdb": 7.839, "tmdbVotes": 4811}}, {"id": "movie-the-last-of-the-mohicans-1992", "title": "The Last of the Mohicans", "year": 1992, "type": "movie", "runtimeSeconds": 6874, "seasonCount": null, "communityRating": 7.388, "criticRating": 88, "genres": ["History", "War", "Drama"], "overview": "In war-torn colonial America, in the midst of a bloody battle between British, the French and Native American allies, the aristocratic daughter of a British Colonel and her party are captured by a group of Huron\u2026", "poster": "assets/movie-the-last-of-the-mohicans-1992-poster.jpg", "backdrop": "assets/movie-the-last-of-the-mohicans-1992-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-10T20:59:22.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 9361, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 88, "rtCriticsLabel": "Certified Fresh", "rtAudience": 88, "rtAudienceLabel": "Upright", "imdb": 7.6, "imdbVotes": 210791, "tmdb": 7.39, "tmdbVotes": 3593}}, {"id": "movie-the-last-samurai-2003", "title": "The Last Samurai", "year": 2003, "type": "movie", "runtimeSeconds": 9251, "seasonCount": null, "communityRating": 7.61, "criticRating": 65, "genres": ["Drama", "Action", "War"], "overview": "Nathan Algren is an American hired to instruct the Japanese army in the ways of modern warfare, which finds him learning to respect the samurai and the honorable principles that rule them. Pressed to destroy the\u2026", "poster": "assets/movie-the-last-samurai-2003-poster.jpg", "backdrop": "assets/movie-the-last-samurai-2003-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-26T05:25:10.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 616, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 66, "rtCriticsLabel": "Fresh", "rtAudience": 83, "rtAudienceLabel": "Upright", "imdb": 7.8, "imdbVotes": 512982, "tmdb": 7.614, "tmdbVotes": 7887}}, {"id": "movie-lemony-snicket-s-a-series-of-unfortunate-events-2004", "title": "Lemony Snicket's A Series of Unfortunate Events", "year": 2004, "type": "movie", "runtimeSeconds": 6479, "seasonCount": null, "communityRating": 6.8, "criticRating": 72, "genres": ["Adventure", "Comedy", "Family"], "overview": "Three wealthy children's parents are killed in a fire. When they are sent to a distant relative, they find out that he is plotting to kill them and seize their fortune.", "poster": "assets/movie-lemony-snicket-s-a-series-of-unfortunate-events-2004-poster.jpg", "backdrop": "assets/movie-lemony-snicket-s-a-series-of-unfortunate-events-2004-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:26:09.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 11774, "artwork": {"posterKind": "center_crop", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 72, "rtCriticsLabel": "Fresh", "rtAudience": 63, "rtAudienceLabel": "Upright", "imdb": 6.8, "imdbVotes": 233636, "tmdb": 6.82, "tmdbVotes": 5447}}, {"id": "movie-the-lighthouse-2019", "title": "The Lighthouse", "year": 2019, "type": "movie", "runtimeSeconds": 6549, "seasonCount": null, "communityRating": 7.463, "criticRating": 90, "genres": ["Drama", "Fantasy", "Thriller"], "overview": "Two lighthouse keepers try to maintain their sanity while living on a remote and mysterious New England island in the 1890s.", "poster": "assets/movie-the-lighthouse-2019-poster.jpg", "backdrop": "assets/movie-the-lighthouse-2019-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:29:01.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 503919, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 90, "rtCriticsLabel": "Certified Fresh", "rtAudience": 72, "rtAudienceLabel": "Upright", "imdb": 7.3, "imdbVotes": 312344, "tmdb": 7.46, "tmdbVotes": 5895}}, {"id": "movie-locke-2014", "title": "Locke", "year": 2014, "type": "movie", "runtimeSeconds": 5090, "seasonCount": null, "communityRating": 6.888, "criticRating": 91, "genres": ["Drama", "Thriller"], "overview": "Ivan Locke has worked hard to craft a good life for himself. Tonight, that life will collapse around him. On the eve of the biggest challenge of his career, Ivan receives a phone call that sets in motion a series of\u2026", "poster": "assets/movie-locke-2014-poster.jpg", "backdrop": "assets/movie-locke-2014-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T17:38:48.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 210479, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 90, "rtCriticsLabel": "Certified Fresh", "rtAudience": 72, "rtAudienceLabel": "Upright", "imdb": 7.1, "imdbVotes": 171265, "tmdb": 6.889, "tmdbVotes": 3088}}, {"id": "movie-the-matrix-1999", "title": "The Matrix", "year": 1999, "type": "movie", "runtimeSeconds": 8179, "seasonCount": null, "communityRating": 8.259, "criticRating": 83, "genres": ["Action", "Science Fiction"], "overview": "Set in the 22nd century, The Matrix tells the story of a computer hacker who joins a group of underground insurgents fighting the vast and powerful computers who now rule the earth.", "poster": "assets/movie-the-matrix-1999-poster.jpg", "backdrop": "assets/movie-the-matrix-1999-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:18:12.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 603, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 83, "rtCriticsLabel": "Certified Fresh", "rtAudience": 85, "rtAudienceLabel": "Upright", "imdb": 8.7, "imdbVotes": 2289808, "tmdb": 8.262, "tmdbVotes": 29153}}, {"id": "movie-the-matrix-reloaded-2003", "title": "The Matrix Reloaded", "year": 2003, "type": "movie", "runtimeSeconds": 8298, "seasonCount": null, "communityRating": 7.085, "criticRating": 74, "genres": ["Adventure", "Action", "Thriller"], "overview": "The Resistance builds in numbers as humans are freed from the Matrix and brought to the city of Zion. Neo discovers his superpowers, including the ability to see the code inside the Matrix. With machine sentinels\u2026", "poster": "assets/movie-the-matrix-reloaded-2003-poster.jpg", "backdrop": "assets/movie-the-matrix-reloaded-2003-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:24:03.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 604, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 73, "rtCriticsLabel": "Certified Fresh", "rtAudience": 72, "rtAudienceLabel": "Upright", "imdb": 7.2, "imdbVotes": 678013, "tmdb": 7.087, "tmdbVotes": 12504}}, {"id": "movie-the-matrix-resurrections-2021", "title": "The Matrix Resurrections", "year": 2021, "type": "movie", "runtimeSeconds": 8875, "seasonCount": null, "communityRating": 6.303, "criticRating": 63, "genres": ["Science Fiction", "Action", "Adventure"], "overview": "Plagued by strange memories, Neo's life takes an unexpected turn when he finds himself back inside the Matrix.", "poster": "assets/movie-the-matrix-resurrections-2021-poster.jpg", "backdrop": "assets/movie-the-matrix-resurrections-2021-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:31:22.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 624860, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 63, "rtCriticsLabel": "Fresh", "rtAudience": 63, "rtAudienceLabel": "Upright", "imdb": 5.6, "imdbVotes": 307780, "tmdb": 6.294, "tmdbVotes": 6842}}, {"id": "movie-the-matrix-revolutions-2003", "title": "The Matrix Revolutions", "year": 2003, "type": "movie", "runtimeSeconds": 7756, "seasonCount": null, "communityRating": 6.758, "criticRating": 33, "genres": ["Adventure", "Action", "Thriller"], "overview": "The human city of Zion defends itself against the massive invasion of the machines as Neo fights to end the war at another front while also opposing the rogue Agent Smith.", "poster": "assets/movie-the-matrix-revolutions-2003-poster.jpg", "backdrop": "assets/movie-the-matrix-revolutions-2003-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:25:47.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 605, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 34, "rtCriticsLabel": "Rotten", "rtAudience": 60, "rtAudienceLabel": "Upright", "imdb": 6.8, "imdbVotes": 581553, "tmdb": 6.762, "tmdbVotes": 11292}}, {"id": "movie-mercy-2026", "title": "Mercy", "year": 2026, "type": "movie", "runtimeSeconds": 5968, "seasonCount": null, "communityRating": 7.077, "criticRating": null, "genres": ["Science Fiction", "Thriller", "Crime"], "overview": "In the near future, a detective stands on trial accused of murdering his wife. He has ninety minutes to prove his innocence to the advanced AI Judge he once championed, before it determines his fate.", "poster": "assets/movie-mercy-2026-poster.jpg", "backdrop": "assets/movie-mercy-2026-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:31:40.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 1236153, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 24, "rtCriticsLabel": "Rotten", "rtAudience": 81, "rtAudienceLabel": "Upright", "imdb": 6.2, "imdbVotes": 83878, "tmdb": 7.054, "tmdbVotes": 1812}}, {"id": "movie-normal-2026", "title": "Normal", "year": 2026, "type": "movie", "runtimeSeconds": 5514, "seasonCount": null, "communityRating": 7.267, "criticRating": 77, "genres": ["Action", "Crime", "Thriller"], "overview": "An unassuming substitute sheriff with a troubled past responds to a bank robbery in a small, sleepy town and unknowingly uncovers something far more explosive.", "poster": "assets/movie-normal-2026-poster.jpg", "backdrop": "assets/movie-normal-2026-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-08-21T08:33:18.0000000Z", "lastPlayedAt": "2026-09-24T23:07:52.1161581Z", "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 1242332, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 78, "rtCriticsLabel": "Certified Fresh", "rtAudience": 75, "rtAudienceLabel": "Upright", "imdb": 6.3, "imdbVotes": 37501, "tmdb": 7.241, "tmdbVotes": 786}}, {"id": "movie-outlaw-king-2018", "title": "Outlaw King", "year": 2018, "type": "movie", "runtimeSeconds": 7297, "seasonCount": null, "communityRating": 6.829, "criticRating": 63, "genres": ["Action", "History", "War"], "overview": "Forced into exile by the English after being crowned King of Scotland, legendary warrior Robert the Bruce fights to reclaim the throne.", "poster": "assets/movie-outlaw-king-2018-poster.jpg", "backdrop": "assets/movie-outlaw-king-2018-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:28:32.0000000Z", "lastPlayedAt": "2026-07-26T22:35:35.0000000Z", "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 454227, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 63, "rtCriticsLabel": "Fresh", "rtAudience": 69, "rtAudienceLabel": "Upright", "imdb": 6.9, "imdbVotes": 89876, "tmdb": 6.844, "tmdbVotes": 1780}}, {"id": "movie-panic-room-2002", "title": "Panic Room", "year": 2002, "type": "movie", "runtimeSeconds": 6717, "seasonCount": null, "communityRating": 6.794, "criticRating": 76, "genres": ["Crime", "Drama", "Thriller"], "overview": "Trapped in their New York brownstone's panic room, a hidden chamber built as a sanctuary in the event of break-ins, newly divorced Meg Altman and her young daughter Sarah play a deadly game of cat-and-mouse with\u2026", "poster": "assets/movie-panic-room-2002-poster.jpg", "backdrop": "assets/movie-panic-room-2002-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-19T20:50:01.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 4547, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 76, "rtCriticsLabel": "Certified Fresh", "rtAudience": 64, "rtAudienceLabel": "Upright", "imdb": 6.8, "imdbVotes": 317468, "tmdb": 6.796, "tmdbVotes": 5653}}, {"id": "movie-the-patriot-2000", "title": "The Patriot", "year": 2000, "type": "movie", "runtimeSeconds": 9887, "seasonCount": null, "communityRating": 7.214, "criticRating": 61, "genres": ["Drama", "History", "War"], "overview": "After proving himself on the field of battle in the French and Indian War, Benjamin Martin wants nothing more to do with such things, preferring the simple life of a farmer. But when his son Gabriel enlists in the\u2026", "poster": "assets/movie-the-patriot-2000-poster.jpg", "backdrop": "assets/movie-the-patriot-2000-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-10T20:50:00.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 2024, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 61, "rtCriticsLabel": "Fresh", "rtAudience": 81, "rtAudienceLabel": "Upright", "imdb": 7.2, "imdbVotes": 317639, "tmdb": 7.215, "tmdbVotes": 4535}}, {"id": "movie-peaky-blinders-the-immortal-man-2026", "title": "Peaky Blinders: The Immortal Man", "year": 2026, "type": "movie", "runtimeSeconds": 6844, "seasonCount": null, "communityRating": 7.187, "criticRating": 90, "genres": ["Crime", "Drama"], "overview": "After his estranged son gets embroiled in a Nazi plot, self-exiled gangster Tommy Shelby must return to Birmingham to save his family \u2014 and his nation.", "poster": "assets/movie-peaky-blinders-the-immortal-man-2026-poster.jpg", "backdrop": "assets/movie-peaky-blinders-the-immortal-man-2026-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:30:01.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 875828, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 90, "rtCriticsLabel": "Certified Fresh", "rtAudience": 87, "rtAudienceLabel": "Upright", "imdb": 6.5, "imdbVotes": 92130, "tmdb": 7.189, "tmdbVotes": 1304}}, {"id": "movie-ponyo-2008", "title": "Ponyo", "year": 2008, "type": "movie", "runtimeSeconds": 6530, "seasonCount": null, "communityRating": 7.763, "criticRating": 91, "genres": ["Animation", "Fantasy", "Family"], "overview": "When Sosuke, a young boy who lives on a clifftop overlooking the sea, rescues a stranded goldfish named Ponyo, he discovers more than he bargained for. Ponyo is a curious, energetic young creature who yearns to be\u2026", "poster": "assets/movie-ponyo-2008-poster.jpg", "backdrop": "assets/movie-ponyo-2008-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:23:53.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 12429, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 91, "rtCriticsLabel": "Certified Fresh", "rtAudience": 84, "rtAudienceLabel": "Upright", "imdb": 7.6, "imdbVotes": 190294, "tmdb": 7.759, "tmdbVotes": 5050}}, {"id": "movie-porco-rosso-1992", "title": "Porco Rosso", "year": 1992, "type": "movie", "runtimeSeconds": 5600, "seasonCount": null, "communityRating": 7.794, "criticRating": 96, "genres": ["Animation", "Adventure", "Fantasy"], "overview": "In Italy in the 1930s, sky pirates in biplanes terrorize wealthy cruise ships as they sail the Adriatic Sea. The only pilot brave enough to stop the scourge is the mysterious Porco Rosso, a former World War I flying\u2026", "poster": "assets/movie-porco-rosso-1992-poster.jpg", "backdrop": "assets/movie-porco-rosso-1992-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:23:22.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 11621, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 96, "rtCriticsLabel": "Fresh", "rtAudience": 87, "rtAudienceLabel": "Upright", "imdb": 7.7, "imdbVotes": 119396, "tmdb": 7.789, "tmdbVotes": 3879}}, {"id": "movie-princess-mononoke-1997", "title": "Princess Mononoke", "year": 1997, "type": "movie", "runtimeSeconds": 8003, "seasonCount": null, "communityRating": 8.321, "criticRating": 93, "genres": ["Adventure", "Fantasy", "Animation"], "overview": "Ashitaka, a prince of the disappearing Emishi people, is cursed by a demonized boar god and must journey to the west to find a cure. Along the way, he encounters San, a young human woman fighting to protect the\u2026", "poster": "assets/movie-princess-mononoke-1997-poster.jpg", "backdrop": "assets/movie-princess-mononoke-1997-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:22:28.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 128, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 94, "rtCriticsLabel": "Certified Fresh", "rtAudience": 99, "rtAudienceLabel": "Upright", "imdb": 8.3, "imdbVotes": 493735, "tmdb": 8.321, "tmdbVotes": 9438}}, {"id": "movie-prisoners-2013", "title": "Prisoners", "year": 2013, "type": "movie", "runtimeSeconds": 9192, "seasonCount": null, "communityRating": 8.106, "criticRating": 81, "genres": ["Drama", "Thriller", "Crime"], "overview": "After his six-year-old daughter is abducted, a desperate father takes justice into his own hands when he loses faith in the detective leading the investigation, setting both men on a collision course as the search\u2026", "poster": "assets/movie-prisoners-2013-poster.jpg", "backdrop": "assets/movie-prisoners-2013-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:27:33.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 146233, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 82, "rtCriticsLabel": "Certified Fresh", "rtAudience": 87, "rtAudienceLabel": "Upright", "imdb": 8.2, "imdbVotes": 963062, "tmdb": 8.105, "tmdbVotes": 13722}}, {"id": "movie-racing-stripes-2005", "title": "Racing Stripes", "year": 2005, "type": "movie", "runtimeSeconds": 6117, "seasonCount": null, "communityRating": 5.945, "criticRating": 35, "genres": ["Comedy", "Family"], "overview": "Shattered illusions are hard to repair -- especially for a good-hearted zebra named Stripes who's spent his life on a Kentucky farm amidst the sorely mistaken notion that he's a debonair thoroughbred. Once he faces\u2026", "poster": "assets/movie-racing-stripes-2005-poster.jpg", "backdrop": "assets/movie-racing-stripes-2005-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:26:02.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 6439, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 35, "rtCriticsLabel": "Rotten", "rtAudience": 42, "rtAudienceLabel": "Spilled", "imdb": 5.3, "imdbVotes": 19569, "tmdb": 5.962, "tmdbVotes": 705}}, {"id": "movie-requiem-for-a-dream-2000", "title": "Requiem for a Dream", "year": 2000, "type": "movie", "runtimeSeconds": 6086, "seasonCount": null, "communityRating": 8.005, "criticRating": 80, "genres": ["Crime", "Drama"], "overview": "The drug-induced utopias of four Coney Island residents are shattered when their addictions run deep.", "poster": "assets/movie-requiem-for-a-dream-2000-poster.jpg", "backdrop": "assets/movie-requiem-for-a-dream-2000-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:24:15.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 641, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 81, "rtCriticsLabel": "Certified Fresh", "rtAudience": 93, "rtAudienceLabel": "Upright", "imdb": 8.3, "imdbVotes": 989090, "tmdb": 8, "tmdbVotes": 11454}}, {"id": "movie-rogue-one-a-star-wars-story-2016", "title": "Rogue One: A Star Wars Story", "year": 2016, "type": "movie", "runtimeSeconds": 8038, "seasonCount": null, "communityRating": 7.51, "criticRating": 84, "genres": ["Action", "Adventure", "Science Fiction"], "overview": "A rogue band of resistance fighters unite for a mission to steal the Death Star plans and bring a new hope to the galaxy.", "poster": "assets/movie-rogue-one-a-star-wars-story-2016-poster.jpg", "backdrop": "assets/movie-rogue-one-a-star-wars-story-2016-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:28:00.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 330459, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 84, "rtCriticsLabel": "Certified Fresh", "rtAudience": 87, "rtAudienceLabel": "Upright", "imdb": 7.8, "imdbVotes": 768365, "tmdb": 7.512, "tmdbVotes": 16937}}, {"id": "movie-secondhand-lions-2003", "title": "Secondhand Lions", "year": 2003, "type": "movie", "runtimeSeconds": 6547, "seasonCount": null, "communityRating": 7.237, "criticRating": 60, "genres": ["Family", "Comedy", "Drama"], "overview": "The comedic adventures of an introverted boy left on the doorstep of a pair of reluctant, eccentric great-uncles, whose exotic remembrances stir the boy's spirit and re-ignite the men's lives.", "poster": "assets/movie-secondhand-lions-2003-poster.jpg", "backdrop": "assets/movie-secondhand-lions-2003-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-12T07:16:13.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 13156, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 59, "rtCriticsLabel": "Rotten", "rtAudience": 84, "rtAudienceLabel": "Upright", "imdb": 7.5, "imdbVotes": 66911, "tmdb": 7.242, "tmdbVotes": 872}}, {"id": "movie-the-secret-life-of-pets-2-2019", "title": "The Secret Life of Pets 2", "year": 2019, "type": "movie", "runtimeSeconds": 5164, "seasonCount": null, "communityRating": 6.95, "criticRating": 60, "genres": ["Animation", "Comedy", "Family"], "overview": "Max the terrier must cope with some major life changes when his owner gets married and has a baby. When the family takes a trip to the countryside, nervous Max has numerous run-ins with canine-intolerant cows,\u2026", "poster": "assets/movie-the-secret-life-of-pets-2-2019-poster.jpg", "backdrop": "assets/movie-the-secret-life-of-pets-2-2019-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-05T07:00:53.0000000Z", "lastPlayedAt": "2026-09-17T18:07:00.7024231Z", "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 412117, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 60, "rtCriticsLabel": "Fresh", "rtAudience": 90, "rtAudienceLabel": "Upright", "imdb": 6.4, "imdbVotes": 80464, "tmdb": 6.948, "tmdbVotes": 3450}}, {"id": "movie-self-reliance-2024", "title": "Self Reliance", "year": 2024, "type": "movie", "runtimeSeconds": 5461, "seasonCount": null, "communityRating": 5.888, "criticRating": 73, "genres": ["Comedy", "Thriller"], "overview": "When a man is offered a million dollars to play a game in which hunters try to kill him, he thinks he has found the perfect loophole: they can only attack when he\u2019s alone. His only problem is that none of his friends\u2026", "poster": "assets/movie-self-reliance-2024-poster.jpg", "backdrop": "assets/movie-self-reliance-2024-backdrop.jpg", "played": false, "playCount": 1, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:31:00.0000000Z", "lastPlayedAt": "2026-10-02T19:59:16.9286868Z", "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 1072876, "artwork": {"posterKind": "center_crop", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 73, "rtCriticsLabel": "Certified Fresh", "rtAudience": 56, "rtAudienceLabel": "Spilled", "imdb": 6, "imdbVotes": 23771, "tmdb": 5.866, "tmdbVotes": 346}}, {"id": "movie-serpico-1973", "title": "Serpico", "year": 1973, "type": "movie", "runtimeSeconds": 7805, "seasonCount": null, "communityRating": 7.5, "criticRating": 93, "genres": ["Crime", "Drama", "History"], "overview": "New York cop Frank Serpico blows the whistle on the rampant corruption in the force only to have his comrades turn against him.", "poster": "assets/movie-serpico-1973-poster.jpg", "backdrop": "assets/movie-serpico-1973-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-10T21:45:02.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 9040, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 93, "rtCriticsLabel": "Certified Fresh", "rtAudience": 88, "rtAudienceLabel": "Upright", "imdb": 7.7, "imdbVotes": 149750, "tmdb": 7.525, "tmdbVotes": 2323}}, {"id": "movie-shaft-2000", "title": "Shaft", "year": 2000, "type": "movie", "runtimeSeconds": 5960, "seasonCount": null, "communityRating": 6.026, "criticRating": 67, "genres": ["Action", "Adventure", "Crime"], "overview": "New York police detective John Shaft arrests Walter Wade Jr. for a racially motivated slaying. But the only eyewitness disappears, and Wade jumps bail for Switzerland. Two years later Wade returns to face trial,\u2026", "poster": "assets/movie-shaft-2000-poster.jpg", "backdrop": "assets/movie-shaft-2000-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-10T21:30:40.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 479, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 68, "rtCriticsLabel": "Fresh", "rtAudience": 40, "rtAudienceLabel": "Spilled", "imdb": 6, "imdbVotes": 86257, "tmdb": 6.024, "tmdbVotes": 1531}}, {"id": "movie-a-silent-voice-the-movie-2016", "title": "A Silent Voice: The Movie", "year": 2016, "type": "movie", "runtimeSeconds": 7804, "seasonCount": null, "communityRating": 8.398, "criticRating": null, "genres": ["Animation", "Drama", "Romance"], "overview": "Shouya Ishida starts bullying the new girl in class, Shouko Nishimiya, because she is deaf. But as the teasing continues, the rest of the class starts to turn on Shouya for his lack of compassion. When they leave\u2026", "poster": "assets/movie-a-silent-voice-the-movie-2016-poster.jpg", "backdrop": "assets/movie-a-silent-voice-the-movie-2016-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T17:39:46.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 378064, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 95, "rtCriticsLabel": "Fresh", "rtAudience": 94, "rtAudienceLabel": "Upright", "imdb": 8.2, "imdbVotes": 151926, "tmdb": 8.396, "tmdbVotes": 4764}}, {"id": "movie-sinbad-legend-of-the-seven-seas-2003", "title": "Sinbad: Legend of the Seven Seas", "year": 2003, "type": "movie", "runtimeSeconds": 5143, "seasonCount": null, "communityRating": 7.067, "criticRating": 44, "genres": ["Action", "Adventure", "Animation"], "overview": "The sailor of legend is framed by the goddess Eris for the theft of the Book of Peace, and must travel to her realm at the end of the world to retrieve it and save the life of his childhood friend Prince Proteus.", "poster": "assets/movie-sinbad-legend-of-the-seven-seas-2003-poster.jpg", "backdrop": "assets/movie-sinbad-legend-of-the-seven-seas-2003-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:26:25.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 14411, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 46, "rtCriticsLabel": "Rotten", "rtAudience": 57, "rtAudienceLabel": "Spilled", "imdb": 6.8, "imdbVotes": 65298, "tmdb": 7.071, "tmdbVotes": 2323}}, {"id": "movie-sleeping-with-other-people-2015", "title": "Sleeping with Other People", "year": 2015, "type": "movie", "runtimeSeconds": 6076, "seasonCount": null, "communityRating": 6.274, "criticRating": 64, "genres": ["Comedy", "Romance"], "overview": "Can two serial cheaters get a second chance at love? After a one-night stand in college, New Yorkers Lainey and Jake meet by chance twelve years later and discover they each have the same problem: because of their\u2026", "poster": "assets/movie-sleeping-with-other-people-2015-poster.jpg", "backdrop": "assets/movie-sleeping-with-other-people-2015-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:27:42.0000000Z", "lastPlayedAt": "2026-07-17T17:50:44.0000000Z", "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 288036, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 64, "rtCriticsLabel": "Fresh", "rtAudience": 56, "rtAudienceLabel": "Spilled", "imdb": 6.5, "imdbVotes": 52275, "tmdb": 6.275, "tmdbVotes": 1020}}, {"id": "movie-snowpiercer-2013", "title": "Snowpiercer", "year": 2013, "type": "movie", "runtimeSeconds": 7573, "seasonCount": null, "communityRating": 6.909, "criticRating": 94, "genres": ["Action", "Science Fiction", "Drama"], "overview": "In a future where a failed global-warming experiment kills off most life on the planet, a class system evolves aboard the Snowpiercer; a train that travels around the globe via a perpetual-motion engine.", "poster": "assets/movie-snowpiercer-2013-poster.jpg", "backdrop": "assets/movie-snowpiercer-2013-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:27:07.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 110415, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 94, "rtCriticsLabel": "Certified Fresh", "rtAudience": 72, "rtAudienceLabel": "Upright", "imdb": 7.1, "imdbVotes": 426976, "tmdb": 6.9, "tmdbVotes": 10807}}, {"id": "movie-spider-man-brand-new-day-2026", "title": "Spider-Man: Brand New Day", "year": 2026, "type": "movie", "runtimeSeconds": 8701, "seasonCount": null, "communityRating": 8.374, "criticRating": 90, "genres": ["Science Fiction", "Action", "Adventure"], "overview": "Fighting crime full-time as Spider-Man in a world that doesn't remember him\u2014and the pressure of seeing his old friends move on without him\u2014sparks a change in Peter Parker he may not have the power to control. But\u2026", "poster": "assets/movie-spider-man-brand-new-day-2026-poster.jpg", "backdrop": "assets/movie-spider-man-brand-new-day-2026-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-10T14:14:27.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 969681, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 90, "rtCriticsLabel": "Certified Fresh", "rtAudience": 97, "rtAudienceLabel": "Upright", "imdb": 7.9, "imdbVotes": 366886, "tmdb": 8.5, "tmdbVotes": 6537}}, {"id": "movie-spider-man-far-from-home-2019", "title": "Spider-Man: Far From Home", "year": 2019, "type": "movie", "runtimeSeconds": 7762, "seasonCount": null, "communityRating": 7.389, "criticRating": 91, "genres": ["Action", "Adventure", "Science Fiction"], "overview": "Peter Parker and his friends go on a summer trip to Europe. However, they will hardly be able to rest - Peter will have to agree to help Nick Fury uncover the mystery of creatures that cause natural disasters and\u2026", "poster": "assets/movie-spider-man-far-from-home-2019-poster.jpg", "backdrop": "assets/movie-spider-man-far-from-home-2019-backdrop.jpg", "played": true, "playCount": 1, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-10T14:25:47.0000000Z", "lastPlayedAt": "2026-10-10T17:50:35.6193119Z", "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 429617, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 91, "rtCriticsLabel": "Certified Fresh", "rtAudience": 95, "rtAudienceLabel": "Upright", "imdb": 7.3, "imdbVotes": 682887, "tmdb": 7.387, "tmdbVotes": 17847}}, {"id": "movie-spider-man-homecoming-2017", "title": "Spider-Man: Homecoming", "year": 2017, "type": "movie", "runtimeSeconds": 8008, "seasonCount": null, "communityRating": 7.333, "criticRating": 92, "genres": ["Action", "Adventure", "Science Fiction"], "overview": "Following the events of Captain America: Civil War, Peter Parker, with the help of his mentor Tony Stark, tries to balance his life as an ordinary high school student in Queens, New York City, with fighting crime as\u2026", "poster": "assets/movie-spider-man-homecoming-2017-poster.jpg", "backdrop": "assets/movie-spider-man-homecoming-2017-backdrop.jpg", "played": true, "playCount": 1, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-10T14:33:13.0000000Z", "lastPlayedAt": "2026-10-10T20:31:23.4444213Z", "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 315635, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 92, "rtCriticsLabel": "Certified Fresh", "rtAudience": 87, "rtAudienceLabel": "Upright", "imdb": 7.4, "imdbVotes": 840974, "tmdb": 7.332, "tmdbVotes": 24183}}, {"id": "movie-spider-man-no-way-home-2021", "title": "Spider-Man: No Way Home", "year": 2021, "type": "movie", "runtimeSeconds": 8890, "seasonCount": null, "communityRating": 7.947, "criticRating": 93, "genres": ["Action", "Adventure", "Science Fiction"], "overview": "Peter Parker is unmasked and no longer able to separate his normal life from the high-stakes of being a super-hero. When he asks for help from Doctor Strange the stakes become even more dangerous, forcing him to\u2026", "poster": "assets/movie-spider-man-no-way-home-2021-poster.jpg", "backdrop": "assets/movie-spider-man-no-way-home-2021-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-10T14:21:05.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 634649, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 93, "rtCriticsLabel": "Certified Fresh", "rtAudience": 97, "rtAudienceLabel": "Upright", "imdb": 8.1, "imdbVotes": 1082660, "tmdb": 7.947, "tmdbVotes": 23505}}, {"id": "movie-spirited-away-2001", "title": "Spirited Away", "year": 2001, "type": "movie", "runtimeSeconds": 7472, "seasonCount": null, "communityRating": 8.535, "criticRating": 96, "genres": ["Animation", "Family", "Fantasy"], "overview": "A young girl, Chihiro, becomes trapped in a strange new world of spirits. When her parents undergo a mysterious transformation, she must call upon the courage she never knew she had to free her family.", "poster": "assets/movie-spirited-away-2001-poster.jpg", "backdrop": "assets/movie-spirited-away-2001-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:22:42.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 129, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 96, "rtCriticsLabel": "Certified Fresh", "rtAudience": 99, "rtAudienceLabel": "Upright", "imdb": 8.6, "imdbVotes": 987658, "tmdb": 8.536, "tmdbVotes": 19176}}, {"id": "movie-the-substance-2024", "title": "The Substance", "year": 2024, "type": "movie", "runtimeSeconds": 8531, "seasonCount": null, "communityRating": 7.135, "criticRating": 89, "genres": ["Horror", "Science Fiction"], "overview": "A fading celebrity decides to use a black market drug, a cell-replicating substance that temporarily creates a younger, better version of herself.", "poster": "assets/movie-the-substance-2024-poster.jpg", "backdrop": "assets/movie-the-substance-2024-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:30:22.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 933260, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 89, "rtCriticsLabel": "Certified Fresh", "rtAudience": 76, "rtAudienceLabel": "Upright", "imdb": 7.2, "imdbVotes": 466542, "tmdb": 7.13, "tmdbVotes": 6746}}, {"id": "movie-the-tale-of-the-princess-kaguya-2013", "title": "The Tale of The Princess Kaguya", "year": 2013, "type": "movie", "runtimeSeconds": 8218, "seasonCount": null, "communityRating": 8.1, "criticRating": 100, "genres": ["Animation", "Drama", "Fantasy"], "overview": "Found inside a shining stalk of bamboo by an old bamboo cutter and his wife, a tiny girl grows rapidly into an exquisite young lady. The mysterious young princess enthrals all who encounter her. But, ultimately, she\u2026", "poster": "assets/movie-the-tale-of-the-princess-kaguya-2013-poster.jpg", "backdrop": "assets/movie-the-tale-of-the-princess-kaguya-2013-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-07T13:40:15.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 149871, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Certified Fresh", "rtAudience": 90, "rtAudienceLabel": "Upright", "imdb": 8, "imdbVotes": 63574, "tmdb": 8.083, "tmdbVotes": 2079}}, {"id": "movie-taxi-driver-1976", "title": "Taxi Driver", "year": 1976, "type": "movie", "runtimeSeconds": 6831, "seasonCount": null, "communityRating": 8.121, "criticRating": 89, "genres": ["Crime", "Drama"], "overview": "Suffering from insomnia, disturbed loner Travis Bickle takes a job as a New York City cabbie, haunting the streets nightly, growing increasingly detached from reality as he dreams of cleaning up the filthy city.", "poster": "assets/movie-taxi-driver-1976-poster.jpg", "backdrop": "assets/movie-taxi-driver-1976-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:23:04.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 103, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 89, "rtCriticsLabel": "Certified Fresh", "rtAudience": 93, "rtAudienceLabel": "Upright", "imdb": 8.2, "imdbVotes": 1046700, "tmdb": 8.116, "tmdbVotes": 13973}}, {"id": "movie-triangle-of-sadness-2022", "title": "Triangle of Sadness", "year": 2022, "type": "movie", "runtimeSeconds": 8833, "seasonCount": null, "communityRating": 7.005, "criticRating": 71, "genres": ["Comedy", "Drama"], "overview": "A celebrity model couple are invited on a luxury cruise for the uber-rich, helmed by an unhinged, alcoholic captain. What first appears Instagrammable ends catastrophically, leaving the survivors stranded on a desert\u2026", "poster": "assets/movie-triangle-of-sadness-2022-poster.jpg", "backdrop": "assets/movie-triangle-of-sadness-2022-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:29:00.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 497828, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 72, "rtCriticsLabel": "Fresh", "rtAudience": 80, "rtAudienceLabel": "Upright", "imdb": 7.2, "imdbVotes": 221069, "tmdb": 7, "tmdbVotes": 3104}}, {"id": "movie-tsotsi-2005", "title": "Tsotsi", "year": 2005, "type": "movie", "runtimeSeconds": 5663, "seasonCount": null, "communityRating": 6.937, "criticRating": 82, "genres": ["Crime", "Drama"], "overview": "A young South African boy from the Johannesburg ghetto named Tsotsi, meaning Gangster, leaves home as a child to get away from his helpless parents. Now a teenage thug, Tsotsi finds a baby in the back seat of a car\u2026", "poster": "assets/movie-tsotsi-2005-poster.jpg", "backdrop": "assets/movie-tsotsi-2005-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:24:58.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 868, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 82, "rtCriticsLabel": "Certified Fresh", "rtAudience": 86, "rtAudienceLabel": "Upright", "imdb": 7.2, "imdbVotes": 32526, "tmdb": 6.941, "tmdbVotes": 372}}, {"id": "movie-unknown-number-the-high-school-catfish-2025", "title": "Unknown Number: The High School Catfish", "year": 2025, "type": "movie", "runtimeSeconds": 5691, "seasonCount": null, "communityRating": 6.746, "criticRating": 85, "genres": ["Documentary"], "overview": "Vulgar, taunting texts blow up the phones of a teen and her boyfriend. Who's sending them \u2014 and why? This twisty documentary reveals the shocking answer.", "poster": "assets/movie-unknown-number-the-high-school-catfish-2025-poster.jpg", "backdrop": "assets/movie-unknown-number-the-high-school-catfish-2025-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:32:10.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 1517772, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 85, "rtCriticsLabel": "Fresh", "rtAudience": 69, "rtAudienceLabel": "Upright", "imdb": 6.7, "imdbVotes": 23039, "tmdb": 6.737, "tmdbVotes": 257}}, {"id": "movie-the-uprising-2026", "title": "The Uprising", "year": 2026, "type": "movie", "runtimeSeconds": 7684, "seasonCount": null, "communityRating": 7.846, "criticRating": 55, "genres": ["Action", "Drama", "History"], "overview": "As war and plague devastate 14th-century England, a humble peasant ignites a rebellion, uniting an army of commoners to defy the King\u2019s might in a desperate fight for justice and survival.", "poster": "assets/movie-the-uprising-2026-poster.jpg", "backdrop": "assets/movie-the-uprising-2026-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-11-02T16:37:03.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 977942, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 57, "rtCriticsLabel": "Rotten", "rtAudience": 65, "rtAudienceLabel": "Upright", "imdb": 6.2, "imdbVotes": 6622, "tmdb": 7.8, "tmdbVotes": 404}}, {"id": "movie-vice-2018", "title": "Vice", "year": 2018, "type": "movie", "runtimeSeconds": 7948, "seasonCount": null, "communityRating": 7.013, "criticRating": 64, "genres": ["Drama", "Comedy", "History"], "overview": "George W. Bush picks Dick Cheney, the CEO of Halliburton Co., to be his Republican running mate in the 2000 presidential election. No stranger to politics, Cheney's impressive r\u00e9sum\u00e9 includes stints as White House\u2026", "poster": "assets/movie-vice-2018-poster.jpg", "backdrop": "assets/movie-vice-2018-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:28:30.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 429197, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 64, "rtCriticsLabel": "Fresh", "rtAudience": 61, "rtAudienceLabel": "Upright", "imdb": 7.2, "imdbVotes": 177299, "tmdb": 7.014, "tmdbVotes": 3723}}, {"id": "movie-warriors-of-the-wind-1984", "title": "Warriors of the Wind", "year": 1984, "type": "movie", "runtimeSeconds": 7022, "seasonCount": null, "communityRating": 7.941, "criticRating": 87, "genres": ["Adventure", "Animation", "Fantasy"], "overview": "After a global war, the seaside kingdom known as the Valley of the Wind remains one of the last strongholds on Earth untouched by a poisonous jungle and the powerful insects that guard it. Led by the courageous\u2026", "poster": "assets/movie-warriors-of-the-wind-1984-poster.jpg", "backdrop": "assets/movie-warriors-of-the-wind-1984-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:22:20.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 81, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 87, "rtCriticsLabel": "Fresh", "rtAudience": 91, "rtAudienceLabel": "Upright", "imdb": 8, "imdbVotes": 200154, "tmdb": 7.94, "tmdbVotes": 4260}}, {"id": "movie-we-bury-the-dead-2026", "title": "We Bury the Dead", "year": 2026, "type": "movie", "runtimeSeconds": 5693, "seasonCount": null, "communityRating": 6.153, "criticRating": 87, "genres": ["Horror", "Thriller"], "overview": "After a catastrophic military disaster reanimates the dead, Ava searches for her missing husband amidst an increasingly hostile world.", "poster": "assets/movie-we-bury-the-dead-2026-poster.jpg", "backdrop": "assets/movie-we-bury-the-dead-2026-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-08-26T05:36:00.4272328Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 1198984, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 87, "rtCriticsLabel": "Certified Fresh", "rtAudience": 45, "rtAudienceLabel": "Spilled", "imdb": 5.6, "imdbVotes": 20693, "tmdb": 6.137, "tmdbVotes": 433}}, {"id": "movie-white-hot-the-rise-fall-of-abercrombie-fitch-2022", "title": "White Hot: The Rise & Fall of Abercrombie & Fitch", "year": 2022, "type": "movie", "runtimeSeconds": 5187, "seasonCount": null, "communityRating": 5.663, "criticRating": 66, "genres": ["Documentary"], "overview": "All the cool kids were wearing it. This documentary explores A&F's pop culture reign in the late '90s and early 2000s and how it thrived on exclusion.", "poster": "assets/movie-white-hot-the-rise-fall-of-abercrombie-fitch-2022-poster.jpg", "backdrop": "assets/movie-white-hot-the-rise-fall-of-abercrombie-fitch-2022-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:30:34.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 953371, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 66, "rtCriticsLabel": "Fresh", "rtAudience": 29, "rtAudienceLabel": "Spilled", "imdb": 5.8, "imdbVotes": 5655, "tmdb": 5.7, "tmdbVotes": 102}}, {"id": "movie-the-wild-robot-2024", "title": "The Wild Robot", "year": 2024, "type": "movie", "runtimeSeconds": 6101, "seasonCount": null, "communityRating": 8.308, "criticRating": 97, "genres": ["Family", "Animation", "Science Fiction"], "overview": "After a shipwreck, an intelligent robot called Roz is stranded on an uninhabited island. To survive the harsh environment, Roz bonds with the island's animals and cares for an orphaned baby goose.", "poster": "assets/movie-the-wild-robot-2024-poster.jpg", "backdrop": "assets/movie-the-wild-robot-2024-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:31:49.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 1184918, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 97, "rtCriticsLabel": "Certified Fresh", "rtAudience": 98, "rtAudienceLabel": "Upright", "imdb": 8.1, "imdbVotes": 241134, "tmdb": 8.309, "tmdbVotes": 6819}}, {"id": "movie-the-wind-rises-2013", "title": "The Wind Rises", "year": 2013, "type": "movie", "runtimeSeconds": 8031, "seasonCount": null, "communityRating": 7.784, "criticRating": 88, "genres": ["Animation", "Drama", "History"], "overview": "A lifelong love of flight inspires Japanese aviation engineer Jiro Horikoshi, whose storied career includes the creation of the A-6M World War II fighter plane.", "poster": "assets/movie-the-wind-rises-2013-poster.jpg", "backdrop": "assets/movie-the-wind-rises-2013-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:24:38.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 149870, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 89, "rtCriticsLabel": "Certified Fresh", "rtAudience": 85, "rtAudienceLabel": "Upright", "imdb": 7.8, "imdbVotes": 115756, "tmdb": 7.783, "tmdbVotes": 3536}}, {"id": "movie-the-witcher-nightmare-of-the-wolf-2021", "title": "The Witcher: Nightmare of the Wolf", "year": 2021, "type": "movie", "runtimeSeconds": 5015, "seasonCount": null, "communityRating": 7.422, "criticRating": 100, "genres": ["Animation", "Action", "Fantasy"], "overview": "Escaping from poverty to become a witcher, Vesemir slays monsters for coin and glory, but when a new menace rises, he must face the demons of his past.", "poster": "assets/movie-the-witcher-nightmare-of-the-wolf-2021-poster.jpg", "backdrop": "assets/movie-the-witcher-nightmare-of-the-wolf-2021-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-26T04:42:03.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 666243, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": 83, "rtAudienceLabel": "Upright", "imdb": 7.2, "imdbVotes": 55759, "tmdb": 7.407, "tmdbVotes": 1159}}, {"id": "movie-the-witcher-sirens-of-the-deep-2025", "title": "The Witcher: Sirens of the Deep", "year": 2025, "type": "movie", "runtimeSeconds": 5517, "seasonCount": null, "communityRating": 6.8, "criticRating": 60, "genres": ["Animation", "Fantasy", "Action"], "overview": "When human sailors are attacked by mysterious creatures of the deep, only one person can stop the war between land and sea: the Witcher, Geralt of Rivia.", "poster": "assets/movie-the-witcher-sirens-of-the-deep-2025-poster.jpg", "backdrop": "assets/movie-the-witcher-sirens-of-the-deep-2025-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-26T05:03:26.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 1203329, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 60, "rtCriticsLabel": "Fresh", "rtAudience": 37, "rtAudienceLabel": "Spilled", "imdb": 6.1, "imdbVotes": 11799, "tmdb": 6.741, "tmdbVotes": 303}}], "shows": [{"id": "tv-adults-2025", "title": "Adults", "year": 2025, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 6.495, "criticRating": null, "genres": ["Comedy"], "overview": "A group of twenty-somethings in New York trying to be good people, despite being neither \"good\" nor \"people\" yet.", "poster": "assets/tv-adults-2025-poster.jpg", "backdrop": "assets/tv-adults-2025-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-23T21:01:41.1814765Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 260458, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 88, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.5, "tmdbVotes": 102}}, {"id": "tv-american-crime-story-2016", "title": "American Crime Story", "year": 2016, "type": "tv", "runtimeSeconds": null, "seasonCount": 3, "communityRating": 7.573, "criticRating": null, "genres": ["Crime", "Drama"], "overview": "An anthology series centered around some of history's most famous criminal investigations.", "poster": "assets/tv-american-crime-story-2016-poster.jpg", "backdrop": "assets/tv-american-crime-story-2016-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0490488Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 64513, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 84, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.585, "tmdbVotes": 1094}}, {"id": "tv-american-primeval-2025", "title": "American Primeval", "year": 2025, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.691, "criticRating": null, "genres": ["Western", "Drama", "Action & Adventure"], "overview": "A mother and son fleeing from their past form a found family while confronting a harsh landscape of freedom and cruelty in the American West.", "poster": "assets/tv-american-primeval-2025-poster.jpg", "backdrop": "assets/tv-american-primeval-2025-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0573221Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 215866, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 71, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.741, "tmdbVotes": 538}}, {"id": "tv-arrested-development-2003", "title": "Arrested Development", "year": 2003, "type": "tv", "runtimeSeconds": null, "seasonCount": 5, "communityRating": 7.925, "criticRating": null, "genres": ["Comedy"], "overview": "The story of a wealthy family that lost everything, and the one son who had no choice but to keep them all together.", "poster": "assets/tv-arrested-development-2003-poster.jpg", "backdrop": "assets/tv-arrested-development-2003-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0513048Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 4589, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 75, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.906, "tmdbVotes": 1793}}, {"id": "tv-avatar-the-last-airbender-2005", "title": "Avatar: The Last Airbender", "year": 2005, "type": "tv", "runtimeSeconds": 1440, "seasonCount": 3, "communityRating": 8.78, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "In a war-torn world of elemental magic, a young boy reawakens to undertake a dangerous mystic quest to fulfill his destiny as the Avatar, and bring peace to the world.", "poster": "assets/tv-avatar-the-last-airbender-2005-poster.jpg", "backdrop": "assets/tv-avatar-the-last-airbender-2005-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0504536Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 246, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.787, "tmdbVotes": 5215}}, {"id": "tv-b-b-vol-liefde-2021", "title": "B&B Vol Liefde", "year": 2021, "type": "tv", "runtimeSeconds": 3720, "seasonCount": 1, "communityRating": 7.2, "criticRating": null, "genres": ["Reality"], "overview": "B&B Vol Liefde is a heartwarming adventure, full of romance, excitement, and unforgettable moments. Adventurous Dutch B&B owners abroad throw their doors wide open and let their hearts speak, determined to find that\u2026", "poster": "assets/tv-b-b-vol-liefde-2021-poster.jpg", "backdrop": "assets/tv-b-b-vol-liefde-2021-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-31T22:30:11.129657Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 124428, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.2, "tmdbVotes": 10}}, {"id": "tv-the-bear-2022", "title": "The Bear", "year": 2022, "type": "tv", "runtimeSeconds": null, "seasonCount": 5, "communityRating": 8.139, "criticRating": null, "genres": ["Drama", "Comedy"], "overview": "Carmy, a young fine-dining chef, comes home to Chicago to run his family sandwich shop. As he fights to transform the shop and himself, he works alongside a rough-around-the-edges crew that ultimately reveal\u2026", "poster": "assets/tv-the-bear-2022-poster.jpg", "backdrop": "assets/tv-the-bear-2022-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0467371Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 136315, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 93, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.158, "tmdbVotes": 2025}}, {"id": "tv-blue-planet-ii-2017", "title": "Blue Planet II", "year": 2017, "type": "tv", "runtimeSeconds": 3600, "seasonCount": 1, "communityRating": 8.64, "criticRating": null, "genres": ["Documentary", "Family"], "overview": "There is nowhere more powerful and unforgiving yet more beautiful and compelling than the ocean. Join us and explore the greatest yet least known parts of our planet.", "poster": "assets/tv-blue-planet-ii-2017-poster.jpg", "backdrop": "assets/tv-blue-planet-ii-2017-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0634849Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 74313, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 97, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.6, "tmdbVotes": 380}}, {"id": "tv-breeders-2020", "title": "Breeders", "year": 2020, "type": "tv", "runtimeSeconds": 1500, "seasonCount": 4, "communityRating": 6.8, "criticRating": null, "genres": ["Comedy"], "overview": "Exposing the parental-paradox that it is possible, in the very same moment, to love your child to the horizon of the universe, while being apoplectically angry enough to want to send them there.", "poster": "assets/tv-breeders-2020-poster.jpg", "backdrop": "assets/tv-breeders-2020-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-28T18:54:21.8885435Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 93290, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 92, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.8, "tmdbVotes": 104}}, {"id": "tv-chernobyl-2019", "title": "Chernobyl", "year": 2019, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 8.718, "criticRating": null, "genres": ["Drama"], "overview": "The true story of one of the worst man-made catastrophes in history: the catastrophic nuclear accident at Chernobyl. A tale of the brave men and women who sacrificed to save Europe from unimaginable disaster.", "poster": "assets/tv-chernobyl-2019-poster.jpg", "backdrop": "assets/tv-chernobyl-2019-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0469903Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 87108, "artwork": {"posterKind": "poster", "backdropKind": "center_crop"}, "ratings": {"rtCritics": 95, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.731, "tmdbVotes": 8496}}, {"id": "tv-community-2009", "title": "Community", "year": 2009, "type": "tv", "runtimeSeconds": null, "seasonCount": 6, "communityRating": 7.997, "criticRating": null, "genres": ["Comedy"], "overview": "Follow the lives of a group of students at what is possibly the world\u2019s worst community college in the fictional locale of Greendale, Colorado.", "poster": "assets/tv-community-2009-poster.jpg", "backdrop": "assets/tv-community-2009-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0531416Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 18347, "artwork": {"posterKind": "center_crop", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 88, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.994, "tmdbVotes": 2226}}, {"id": "tv-dead-end-job-2026", "title": "Dead-End Job", "year": 2026, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.7, "criticRating": null, "genres": ["Mystery"], "overview": "Drowning in debt, a young man takes lucrative part-time jobs from a mysterious agency \u2014 only to find his hustle for more money turning nightmarish.", "poster": "assets/tv-dead-end-job-2026-poster.jpg", "backdrop": "assets/tv-dead-end-job-2026-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-11-04T18:58:01.8352857Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 289517, "artwork": {"posterKind": "center_crop", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.7, "tmdbVotes": 38}}, {"id": "tv-dopesick-2021", "title": "Dopesick", "year": 2021, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 8.015, "criticRating": null, "genres": ["Crime", "Drama"], "overview": "The story of how one company triggered the worst drug epidemic in American history. Look into the epicenter of America's struggle with opioid addiction, from a distressed Virginia mining community, to the hallways of\u2026", "poster": "assets/tv-dopesick-2021-poster.jpg", "backdrop": "assets/tv-dopesick-2021-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0580168Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 110695, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 89, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.035, "tmdbVotes": 565}}, {"id": "tv-dune-prophecy-2024", "title": "Dune: Prophecy", "year": 2024, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.213, "criticRating": null, "genres": ["Sci-Fi & Fantasy", "Drama", "Action & Adventure"], "overview": "Ten thousand years before the ascension of Paul Atreides, sisters Valya and Tula Harkonnen establish the fabled sect and female order that would become known as the Bene Gesserit to control the future of humankind.", "poster": "assets/tv-dune-prophecy-2024-poster.jpg", "backdrop": "assets/tv-dune-prophecy-2024-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-11-04T18:23:01.2908568Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 90228, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 64, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.213, "tmdbVotes": 677}}, {"id": "tv-east-of-eden-2026", "title": "East of Eden", "year": 2026, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.931, "criticRating": null, "genres": ["Drama", "Crime"], "overview": "In the early 1900s, a fiercely independent woman drives a rift between two brothers, igniting a saga that unfolds across two generations.", "poster": "assets/tv-east-of-eden-2026-poster.jpg", "backdrop": "assets/tv-east-of-eden-2026-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-23T18:07:11.3965096Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 258165, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 88, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.982, "tmdbVotes": 139}}, {"id": "tv-fallout-2024", "title": "Fallout", "year": 2024, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 8.124, "criticRating": null, "genres": ["Action & Adventure", "Sci-Fi & Fantasy", "Drama"], "overview": "The story of haves and have-nots in a world in which there's almost nothing left to have. 200 years after the apocalypse, the gentle denizens of luxury fallout shelters are forced to return to the irradiated\u2026", "poster": "assets/tv-fallout-2024-poster.jpg", "backdrop": "assets/tv-fallout-2024-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0669262Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 106379, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 94, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.106, "tmdbVotes": 3233}}, {"id": "tv-fawlty-towers-1975", "title": "Fawlty Towers", "year": 1975, "type": "tv", "runtimeSeconds": 1800, "seasonCount": 2, "communityRating": 8.295, "criticRating": null, "genres": ["Comedy"], "overview": "Owner Basil Fawlty, his wife Sybil, a chambermaid Polly, and Spanish waiter Manuel attempt to run their hotel amidst farcical situations and an array of demanding guests.", "poster": "assets/tv-fawlty-towers-1975-poster.jpg", "backdrop": "assets/tv-fawlty-towers-1975-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-19T23:26:39.7658344Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 2207, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.296, "tmdbVotes": 867}}, {"id": "tv-the-final-problem-2026", "title": "The Final Problem", "year": 2026, "type": "tv", "runtimeSeconds": 3420, "seasonCount": 1, "communityRating": 7.041, "criticRating": null, "genres": ["Crime", "Mystery"], "overview": "In the spring of 1959, a retired actor, who previously played Sherlock Holmes, must investigate a murder at a small hotel on a tiny island near Mallorca.", "poster": "assets/tv-the-final-problem-2026-poster.jpg", "backdrop": "assets/tv-the-final-problem-2026-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-11-04T19:16:12.4822791Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 290720, "artwork": {"posterKind": "center_crop", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.041, "tmdbVotes": 49}}, {"id": "tv-the-four-seasons-2025", "title": "The Four Seasons", "year": 2025, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 6.879, "criticRating": null, "genres": ["Comedy"], "overview": "The decades-long friendship between three married couples is tested when one divorces, complicating their tradition of quarterly weekend getaways.", "poster": "assets/tv-the-four-seasons-2025-poster.jpg", "backdrop": "assets/tv-the-four-seasons-2025-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-28T18:36:42.5326384Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 243316, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 81, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.892, "tmdbVotes": 204}}, {"id": "tv-the-get-down-2016", "title": "The Get Down", "year": 2016, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.3, "criticRating": null, "genres": ["Drama"], "overview": "In 1977 New York City, the talented and soulful youth of the South Bronx chase dreams and breakneck beats to transform music history.", "poster": "assets/tv-the-get-down-2016-poster.jpg", "backdrop": "assets/tv-the-get-down-2016-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0497737Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 65345, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 81, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.3, "tmdbVotes": 196}}, {"id": "tv-how-to-change-your-mind-2022", "title": "How to Change Your Mind", "year": 2022, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.76, "criticRating": null, "genres": ["Documentary", "Mystery"], "overview": "Author Michael Pollan leads the way in this docuseries exploring the history and uses of psychedelics, including LSD, psilocybin, MDMA and mescaline.", "poster": "assets/tv-how-to-change-your-mind-2022-poster.jpg", "backdrop": "assets/tv-how-to-change-your-mind-2022-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0601399Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 204304, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.8, "tmdbVotes": 53}}, {"id": "tv-interrogation-2020", "title": "Interrogation", "year": 2020, "type": "tv", "runtimeSeconds": 2700, "seasonCount": 1, "communityRating": 6.788, "criticRating": null, "genres": ["Drama", "Crime"], "overview": "Based on a true story that spanned more than 30 years in which a young man was charged and convicted of brutally murdering his mother. Each episode is structured around an interrogation taken directly from the real\u2026", "poster": "assets/tv-interrogation-2020-poster.jpg", "backdrop": "assets/tv-interrogation-2020-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-26T05:52:06.1068207Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 96488, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 57, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.9, "tmdbVotes": 54}}, {"id": "tv-it-s-always-sunny-in-philadelphia-2005", "title": "It's Always Sunny in Philadelphia", "year": 2005, "type": "tv", "runtimeSeconds": null, "seasonCount": 18, "communityRating": 8.2, "criticRating": null, "genres": ["Comedy"], "overview": "Four egocentric friends run a neighborhood Irish pub in Philadelphia and try to find their way through the adult world of work and relationships. Unfortunately, their warped views and precarious judgments often lead\u2026", "poster": "assets/tv-it-s-always-sunny-in-philadelphia-2005-poster.jpg", "backdrop": "assets/tv-it-s-always-sunny-in-philadelphia-2005-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0485774Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 2710, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 94, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.253, "tmdbVotes": 1457}}, {"id": "tv-a-knight-of-the-seven-kingdoms-2026", "title": "A Knight of the Seven Kingdoms", "year": 2026, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 8.431, "criticRating": null, "genres": ["Drama", "Sci-Fi & Fantasy", "Action & Adventure"], "overview": "A century before the events of Game of Thrones, two unlikely heroes wandered Westeros: a young, naive but courageous knight, Ser Duncan the Tall, and his diminutive squire, Egg. Set in an age when the Targaryen line\u2026", "poster": "assets/tv-a-knight-of-the-seven-kingdoms-2026-poster.jpg", "backdrop": "assets/tv-a-knight-of-the-seven-kingdoms-2026-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0493344Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 224372, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 94, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.4, "tmdbVotes": 1266}}, {"id": "tv-landman-2024", "title": "Landman", "year": 2024, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 8.194, "criticRating": null, "genres": ["Drama"], "overview": "Set in the proverbial boomtowns of West-Texas and a modern-day tale of fortune-seeking in the world of oil rigs, the series is an upstairs/downstairs story of roughnecks and wildcat billionaires that are fueling a\u2026", "poster": "assets/tv-landman-2024-poster.jpg", "backdrop": "assets/tv-landman-2024-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-22T21:38:18.0973875Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 157741, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 80, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.209, "tmdbVotes": 668}}, {"id": "tv-the-last-of-us-2023", "title": "The Last of Us", "year": 2023, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 8.419, "criticRating": null, "genres": ["Drama"], "overview": "Twenty years after modern civilization has been destroyed, Joel, a hardened survivor, is hired to smuggle Ellie, a 14-year-old girl, out of an oppressive quarantine zone. What starts as a small job soon becomes a\u2026", "poster": "assets/tv-the-last-of-us-2023-poster.jpg", "backdrop": "assets/tv-the-last-of-us-2023-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0640955Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 100088, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 94, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.4, "tmdbVotes": 7485}}, {"id": "tv-last-samurai-standing-2025", "title": "Last Samurai Standing", "year": 2025, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.805, "criticRating": null, "genres": ["Action & Adventure", "Drama"], "overview": "In the early Meiji era, Shujiro, once known as an undefeated samurai, decides to participate in a deadly survival game to save his family and villagers.", "poster": "assets/tv-last-samurai-standing-2025-poster.jpg", "backdrop": "assets/tv-last-samurai-standing-2025-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0622526Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 252193, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.812, "tmdbVotes": 271}}, {"id": "tv-lord-of-the-flies-2026", "title": "Lord of the Flies", "year": 2026, "type": "tv", "runtimeSeconds": 3480, "seasonCount": 1, "communityRating": 7.571, "criticRating": null, "genres": ["Drama", "Action & Adventure"], "overview": "After a plane crash, a group of schoolboys find themselves stranded on a tropical island without adults. Ralph is elected leader and, with the help of the intelligent Piggy, strives to maintain order and\u2026", "poster": "assets/tv-lord-of-the-flies-2026-poster.jpg", "backdrop": "assets/tv-lord-of-the-flies-2026-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0645648Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 270572, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 91, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.58, "tmdbVotes": 138}}, {"id": "tv-the-lord-of-the-rings-the-rings-of-power-2022", "title": "The Lord of the Rings: The Rings of Power", "year": 2022, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 7.233, "criticRating": null, "genres": ["Action & Adventure", "Sci-Fi & Fantasy", "Drama"], "overview": "Beginning in a time of relative peace, we follow an ensemble cast of characters as they confront the re-emergence of evil to Middle-earth. From the darkest depths of the Misty Mountains, to the majestic forests of\u2026", "poster": "assets/tv-the-lord-of-the-rings-the-rings-of-power-2022-poster.jpg", "backdrop": "assets/tv-the-lord-of-the-rings-the-rings-of-power-2022-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0618904Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 84773, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 84, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.211, "tmdbVotes": 4003}}, {"id": "tv-love-death-robots-2019", "title": "Love, Death & Robots", "year": 2019, "type": "tv", "runtimeSeconds": null, "seasonCount": 4, "communityRating": 8.21, "criticRating": null, "genres": ["Animation", "Sci-Fi & Fantasy"], "overview": "Terrifying creatures, wicked surprises and dark comedy converge in this NSFW anthology of animated stories presented by Tim Miller and David Fincher.", "poster": "assets/tv-love-death-robots-2019-poster.jpg", "backdrop": "assets/tv-love-death-robots-2019-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0460964Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 86831, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 89, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.203, "tmdbVotes": 4238}}, {"id": "tv-maniac-2018", "title": "Maniac", "year": 2018, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.338, "criticRating": null, "genres": ["Comedy", "Drama", "Sci-Fi & Fantasy"], "overview": "Two strangers are drawn to a mysterious pharmaceutical trial that will, they're assured, with no complications or side-effects whatsoever, solve all of their problems, permanently. Things do not go as planned.", "poster": "assets/tv-maniac-2018-poster.jpg", "backdrop": "assets/tv-maniac-2018-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-20T19:42:30.955548Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 73411, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 84, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.323, "tmdbVotes": 1073}}, {"id": "tv-mussolini-son-of-the-century-2024", "title": "Mussolini: Son of the Century", "year": 2024, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 8.135, "criticRating": null, "genres": ["Drama", "War & Politics"], "overview": "The rise of Benito Mussolini and the birth of fascism in Italy, chronicling a country\u2019s surrender to dictatorship and the relentless ascent of a man who rose from his ashes time and again.", "poster": "assets/tv-mussolini-son-of-the-century-2024-poster.jpg", "backdrop": "assets/tv-mussolini-son-of-the-century-2024-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0586588Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 212333, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 96, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.1, "tmdbVotes": 179}}, {"id": "tv-the-night-manager-2016", "title": "The Night Manager", "year": 2016, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 7.74, "criticRating": null, "genres": ["Drama", "Mystery", "Crime"], "overview": "Former British soldier Jonathan Pine navigates the shadowy recesses of Whitehall and Washington where an unholy alliance operates between the intelligence community and the secret arms trade. To infiltrate the inner\u2026", "poster": "assets/tv-the-night-manager-2016-poster.jpg", "backdrop": "assets/tv-the-night-manager-2016-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0663672Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 61859, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 88, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.7, "tmdbVotes": 1422}}, {"id": "tv-one-piece-2023", "title": "ONE PIECE", "year": 2023, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 8.118, "criticRating": null, "genres": ["Action & Adventure", "Sci-Fi & Fantasy"], "overview": "With his straw hat and ragtag crew, young pirate Monkey D. Luffy goes on an epic voyage for treasure.", "poster": "assets/tv-one-piece-2023-poster.jpg", "backdrop": "assets/tv-one-piece-2023-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0439378Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 111110, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 93, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.104, "tmdbVotes": 1988}}, {"id": "tv-only-murders-in-the-building-2021", "title": "Only Murders in the Building", "year": 2021, "type": "tv", "runtimeSeconds": null, "seasonCount": 5, "communityRating": 8.438, "criticRating": null, "genres": ["Comedy", "Mystery", "Crime"], "overview": "Three strangers share an obsession with true crime and suddenly find themselves wrapped up in one.", "poster": "assets/tv-only-murders-in-the-building-2021-poster.jpg", "backdrop": "assets/tv-only-murders-in-the-building-2021-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0594614Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 107113, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 95, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.398, "tmdbVotes": 2333}}, {"id": "tv-over-the-garden-wall-2014", "title": "Over the Garden Wall", "year": 2014, "type": "tv", "runtimeSeconds": 720, "seasonCount": 1, "communityRating": 8.6, "criticRating": null, "genres": ["Mystery", "Sci-Fi & Fantasy", "Animation"], "overview": "Two brothers, Wirt and Greg, find themselves lost in the Unknown; a strange forest adrift in time. With the help of a wise old Woodsman and a foul-tempered bluebird named Beatrice, Wirt and Greg must travel across\u2026", "poster": "assets/tv-over-the-garden-wall-2014-poster.jpg", "backdrop": "assets/tv-over-the-garden-wall-2014-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0455757Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 61617, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.6, "tmdbVotes": 1854}}, {"id": "tv-peaky-blinders-2013", "title": "Peaky Blinders", "year": 2013, "type": "tv", "runtimeSeconds": null, "seasonCount": 6, "communityRating": 8.5, "criticRating": null, "genres": ["Drama", "Crime"], "overview": "A gangster family epic set in 1919 Birmingham, England and centered on a gang who sew razor blades in the peaks of their caps, and their fierce boss Tommy Shelby, who means to move up in the world.", "poster": "assets/tv-peaky-blinders-2013-poster.jpg", "backdrop": "assets/tv-peaky-blinders-2013-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0539185Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 60574, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 93, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.5, "tmdbVotes": 11506}}, {"id": "tv-the-pitt-2025", "title": "The Pitt", "year": 2025, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 8.729, "criticRating": null, "genres": ["Drama"], "overview": "The staff of Pittsburgh's Trauma Medical Center work around the clock to save lives in an overcrowded and underfunded emergency department.", "poster": "assets/tv-the-pitt-2025-poster.jpg", "backdrop": "assets/tv-the-pitt-2025-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0582942Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 250307, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 96, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.731, "tmdbVotes": 1046}}, {"id": "tv-pluribus-2025", "title": "Pluribus", "year": 2025, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.936, "criticRating": null, "genres": ["Drama", "Sci-Fi & Fantasy"], "overview": "The most miserable person on Earth must save the world from happiness.", "poster": "assets/tv-pluribus-2025-poster.jpg", "backdrop": "assets/tv-pluribus-2025-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0674462Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 225171, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 99, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.921, "tmdbVotes": 1191}}, {"id": "tv-ripley-2024", "title": "RIPLEY", "year": 2024, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.911, "criticRating": null, "genres": ["Drama"], "overview": "A grifter in 1960s New York is hired to convince a wealthy man's son to return home from Italy and begins a life of deceit, fraud and murder.", "poster": "assets/tv-ripley-2024-poster.jpg", "backdrop": "assets/tv-ripley-2024-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0658942Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 94028, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 86, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.909, "tmdbVotes": 453}}, {"id": "tv-say-nothing-2024", "title": "Say Nothing", "year": 2024, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.462, "criticRating": null, "genres": ["Drama", "Crime"], "overview": "Through the eyes of various Irish Republican Army (IRA) members, explore the extremes some people will go to in the name of their beliefs, the way a deeply divided society can suddenly tip over into armed conflict,\u2026", "poster": "assets/tv-say-nothing-2024-poster.jpg", "backdrop": "assets/tv-say-nothing-2024-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0499752Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 245256, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 94, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.475, "tmdbVotes": 122}}, {"id": "tv-severance-2022", "title": "Severance", "year": 2022, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 8.396, "criticRating": null, "genres": ["Drama", "Mystery", "Sci-Fi & Fantasy"], "overview": "Mark leads a team of office workers whose memories have been surgically divided between their work and personal lives. When a mysterious colleague appears outside of work, it begins a journey to discover the truth\u2026", "poster": "assets/tv-severance-2022-poster.jpg", "backdrop": "assets/tv-severance-2022-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0598478Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 95396, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 95, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.389, "tmdbVotes": 3095}}, {"id": "tv-six-feet-under-2001", "title": "Six Feet Under", "year": 2001, "type": "tv", "runtimeSeconds": null, "seasonCount": 5, "communityRating": 8.115, "criticRating": null, "genres": ["Drama"], "overview": "When death is your business, what is your life? For the Fisher family, the world outside of their family-owned funeral home continues to be at least as challenging as\u2014and far less predictable than\u2014the one inside.", "poster": "assets/tv-six-feet-under-2001-poster.jpg", "backdrop": "assets/tv-six-feet-under-2001-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-26T04:04:05.108787Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 1274, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 81, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.1, "tmdbVotes": 1192}}, {"id": "tv-undercover-2019", "title": "Undercover", "year": 2019, "type": "tv", "runtimeSeconds": 3000, "seasonCount": 3, "communityRating": 7.5, "criticRating": null, "genres": ["Crime", "Drama"], "overview": "Undercover agents infiltrate a drug kingpin's operation by posing as a couple at the campground where he spends his weekends. Inspired by real events.", "poster": "assets/tv-undercover-2019-poster.jpg", "backdrop": "assets/tv-undercover-2019-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0570153Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 86942, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.5, "tmdbVotes": 186}}, {"id": "tv-upload-2020", "title": "Upload", "year": 2020, "type": "tv", "runtimeSeconds": null, "seasonCount": 4, "communityRating": 7.781, "criticRating": null, "genres": ["Comedy", "Sci-Fi & Fantasy", "Drama"], "overview": "In 2033, people who are near death can be \u201cuploaded\u201d into virtual reality hotels run by 6 tech firms. Cash-strapped Nora lives in Brooklyn and works customer service for the luxurious \u201cLakeview\u201d digital afterlife.\u2026", "poster": "assets/tv-upload-2020-poster.jpg", "backdrop": "assets/tv-upload-2020-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0566967Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 86248, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 87, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.757, "tmdbVotes": 1511}}, {"id": "tv-the-walk-in-2022", "title": "The Walk-In", "year": 2022, "type": "tv", "runtimeSeconds": 2760, "seasonCount": 1, "communityRating": 6.9, "criticRating": null, "genres": ["Drama", "Crime"], "overview": "Forced to flee the UK and go into hiding in the 1990s, when he became a mole from within the BNP, Matthew Collins returned to Britain to make a new life for himself, working with young white men in the fight against\u2026", "poster": "assets/tv-the-walk-in-2022-poster.jpg", "backdrop": "assets/tv-the-walk-in-2022-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0654569Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 210664, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 80, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7, "tmdbVotes": 50}}, {"id": "tv-the-white-lotus-2021", "title": "The White Lotus", "year": 2021, "type": "tv", "runtimeSeconds": null, "seasonCount": 3, "communityRating": 7.596, "criticRating": null, "genres": ["Comedy", "Drama", "Mystery"], "overview": "Follow the exploits of various guests and employees at an exclusive tropical resort over the span of a week as with each passing day, a darker complexity emerges in these picture-perfect travelers, the hotel\u2019s\u2026", "poster": "assets/tv-the-white-lotus-2021-poster.jpg", "backdrop": "assets/tv-the-white-lotus-2021-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0546438Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 111803, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 90, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.599, "tmdbVotes": 1604}}, {"id": "tv-widow-s-bay-2026", "title": "Widow's Bay", "year": 2026, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 8.172, "criticRating": null, "genres": ["Drama", "Comedy", "Mystery"], "overview": "The mayor of a New England town resolves to turn it into the next tourist hot spot, despite local warnings that it's cursed.", "poster": "assets/tv-widow-s-bay-2026-poster.jpg", "backdrop": "assets/tv-widow-s-bay-2026-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-20T10:27:12.7003979Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 270476, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 98, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8, "tmdbVotes": 585}}, {"id": "tv-the-witcher-2019", "title": "The Witcher", "year": 2019, "type": "tv", "runtimeSeconds": null, "seasonCount": 4, "communityRating": 7.905, "criticRating": null, "genres": ["Drama", "Action & Adventure"], "overview": "Geralt of Rivia, a mutated monster-hunter for hire, journeys toward his destiny in a turbulent world where people often prove more wicked than beasts.", "poster": "assets/tv-the-witcher-2019-poster.jpg", "backdrop": "assets/tv-the-witcher-2019-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0552369Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 71912, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 75, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.88, "tmdbVotes": 6997}}, {"id": "tv-yellowjackets-2021", "title": "Yellowjackets", "year": 2021, "type": "tv", "runtimeSeconds": null, "seasonCount": 3, "communityRating": 7.449, "criticRating": null, "genres": ["Drama", "Mystery"], "overview": "This equal parts survival epic, psychological horror story and coming-of-age drama tells the saga of a team of wildly talented high school girls soccer players who become the (un)lucky survivors of a plane crash deep\u2026", "poster": "assets/tv-yellowjackets-2021-poster.jpg", "backdrop": "assets/tv-yellowjackets-2021-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0577612Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 117488, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 92, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.431, "tmdbVotes": 1070}}], "anime": [], "resume": [{"id": "episode-episode-1-2025-s1e1", "title": "Episode 1", "year": 2025, "type": "episode", "runtimeSeconds": 3618, "seasonCount": null, "communityRating": 7.357, "criticRating": null, "genres": ["Biography", "Drama", "History"], "overview": "Mussolini had just founded the Fasci di Combattimento when D'Annunzio took Fiume. Mussolini hoped to capitalize on the poet's achievement in the electoral arena.", "poster": "assets/episode-episode-1-2025-s1e1-poster.jpg", "backdrop": "assets/episode-episode-1-2025-s1e1-backdrop.jpg", "played": false, "playCount": 1, "resumeSeconds": 489.55, "progress": 0.1353, "addedAt": "2026-07-17T13:52:48.0000000Z", "lastPlayedAt": "2026-11-04T19:01:49.9731435Z", "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "Mussolini: Son of the Century", "seasonNumber": 1, "episodeNumber": 1, "artwork": {"posterKind": "center_crop", "backdropKind": "backdrop"}}], "nextUp": [{"id": "episode-no-honeymoon-2020-s1e8", "title": "No Honeymoon", "year": 2020, "type": "episode", "runtimeSeconds": 1499, "seasonCount": null, "communityRating": 6.7, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "Paul attempts to focus on his upcoming wedding but is constantly thwarted by his family; Ally is distracted by work, Luke is misbehaving at school and Leah (Stella Gonet) doesn\u2019t understand why they are even\u2026", "poster": "assets/episode-no-honeymoon-2020-s1e8-poster.jpg", "backdrop": "assets/episode-no-honeymoon-2020-s1e8-backdrop.jpg", "played": false, "playCount": 1, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-28T19:00:50.0000000Z", "lastPlayedAt": "2026-11-03T20:57:58.3314947Z", "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "Breeders", "seasonNumber": 1, "episodeNumber": 8, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}, {"id": "episode-notapusy-2005-s3e4", "title": "Notapusy", "year": 2005, "type": "episode", "runtimeSeconds": 1334, "seasonCount": null, "communityRating": 8.125, "criticRating": null, "genres": ["Comedy"], "overview": "To prove he's a man to Rita, Michael and his nephew Steve Holt compete in the Church And State Fair's annual triathlon. George Sr. tries to scare some at-risk youth, and Tobias tries to help George-Michael's\u2026", "poster": "assets/episode-notapusy-2005-s3e4-poster.jpg", "backdrop": "assets/episode-notapusy-2005-s3e4-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T12:17:58.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "Arrested Development", "seasonNumber": 3, "episodeNumber": 4, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}, {"id": "episode-the-man-who-would-be-vogue-2018-s2e1", "title": "The Man Who Would Be Vogue", "year": 2018, "type": "episode", "runtimeSeconds": 3203, "seasonCount": null, "communityRating": 7.459, "criticRating": null, "genres": ["Biography", "Crime", "Drama"], "overview": "The murder of Gianni Versace turns the eyes of the world onto Miami Beach.", "poster": "assets/episode-the-man-who-would-be-vogue-2018-s2e1-poster.jpg", "backdrop": "assets/episode-the-man-who-would-be-vogue-2018-s2e1-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T13:29:35.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "American Crime Story", "seasonNumber": 2, "episodeNumber": 1, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}, {"id": "episode-tomorrow-2024-s3e1", "title": "Tomorrow", "year": 2024, "type": "episode", "runtimeSeconds": 2207, "seasonCount": null, "communityRating": 7.6, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "The next day and the days that led to it.", "poster": "assets/episode-tomorrow-2024-s3e1-poster.jpg", "backdrop": "assets/episode-tomorrow-2024-s3e1-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T13:46:39.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "The Bear", "seasonNumber": 3, "episodeNumber": 1, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}, {"id": "episode-episode-1-2025-s1e1", "title": "Episode 1", "year": 2025, "type": "episode", "runtimeSeconds": 3618, "seasonCount": null, "communityRating": 7.357, "criticRating": null, "genres": ["Biography", "Drama", "History"], "overview": "Mussolini had just founded the Fasci di Combattimento when D'Annunzio took Fiume. Mussolini hoped to capitalize on the poet's achievement in the electoral arena.", "poster": "assets/episode-episode-1-2025-s1e1-poster.jpg", "backdrop": "assets/episode-episode-1-2025-s1e1-backdrop.jpg", "played": false, "playCount": 1, "resumeSeconds": 489.55, "progress": 0.1353, "addedAt": "2026-07-17T13:52:48.0000000Z", "lastPlayedAt": "2026-11-04T19:01:49.9731435Z", "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "Mussolini: Son of the Century", "seasonNumber": 1, "episodeNumber": 1, "artwork": {"posterKind": "center_crop", "backdropKind": "backdrop"}}], "recentlyAdded": [{"id": "tv-the-final-problem-2026", "title": "The Final Problem", "year": 2026, "type": "tv", "runtimeSeconds": 3420, "seasonCount": 1, "communityRating": 7.041, "criticRating": null, "genres": ["Crime", "Mystery"], "overview": "In the spring of 1959, a retired actor, who previously played Sherlock Holmes, must investigate a murder at a small hotel on a tiny island near Mallorca.", "poster": "assets/tv-the-final-problem-2026-poster.jpg", "backdrop": "assets/tv-the-final-problem-2026-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-11-04T19:16:12.4822791Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 290720, "artwork": {"posterKind": "center_crop", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.041, "tmdbVotes": 49}}, {"id": "tv-dead-end-job-2026", "title": "Dead-End Job", "year": 2026, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.7, "criticRating": null, "genres": ["Mystery"], "overview": "Drowning in debt, a young man takes lucrative part-time jobs from a mysterious agency \u2014 only to find his hustle for more money turning nightmarish.", "poster": "assets/tv-dead-end-job-2026-poster.jpg", "backdrop": "assets/tv-dead-end-job-2026-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-11-04T18:58:01.8352857Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 289517, "artwork": {"posterKind": "center_crop", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.7, "tmdbVotes": 38}}, {"id": "tv-dune-prophecy-2024", "title": "Dune: Prophecy", "year": 2024, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.213, "criticRating": null, "genres": ["Sci-Fi & Fantasy", "Drama", "Action & Adventure"], "overview": "Ten thousand years before the ascension of Paul Atreides, sisters Valya and Tula Harkonnen establish the fabled sect and female order that would become known as the Bene Gesserit to control the future of humankind.", "poster": "assets/tv-dune-prophecy-2024-poster.jpg", "backdrop": "assets/tv-dune-prophecy-2024-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-11-04T18:23:01.2908568Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 90228, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 64, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.213, "tmdbVotes": 677}}, {"id": "movie-the-uprising-2026", "title": "The Uprising", "year": 2026, "type": "movie", "runtimeSeconds": 7684, "seasonCount": null, "communityRating": 7.846, "criticRating": 55, "genres": ["Action", "Drama", "History"], "overview": "As war and plague devastate 14th-century England, a humble peasant ignites a rebellion, uniting an army of commoners to defy the King\u2019s might in a desperate fight for justice and survival.", "poster": "assets/movie-the-uprising-2026-poster.jpg", "backdrop": "assets/movie-the-uprising-2026-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-11-02T16:37:03.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 977942, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 57, "rtCriticsLabel": "Rotten", "rtAudience": 65, "rtAudienceLabel": "Upright", "imdb": 6.2, "imdbVotes": 6622, "tmdb": 7.8, "tmdbVotes": 404}}, {"id": "movie-jennifer-s-body-2009", "title": "Jennifer's Body", "year": 2009, "type": "movie", "runtimeSeconds": 6450, "seasonCount": null, "communityRating": 6.012, "criticRating": 47, "genres": ["Horror", "Comedy"], "overview": "Jennifer, a gorgeous, seductive cheerleader takes evil to a whole new level after she's possessed by a sinister demon. Now it's up to her best friend to stop Jennifer's reign of terror before it's too late.", "poster": "assets/movie-jennifer-s-body-2009-poster.jpg", "backdrop": "assets/movie-jennifer-s-body-2009-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-30T03:37:04.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 19994, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 47, "rtCriticsLabel": "Rotten", "rtAudience": 36, "rtAudienceLabel": "Spilled", "imdb": 5.6, "imdbVotes": 179710, "tmdb": 6.013, "tmdbVotes": 4481}}, {"id": "tv-breeders-2020", "title": "Breeders", "year": 2020, "type": "tv", "runtimeSeconds": 1500, "seasonCount": 4, "communityRating": 6.8, "criticRating": null, "genres": ["Comedy"], "overview": "Exposing the parental-paradox that it is possible, in the very same moment, to love your child to the horizon of the universe, while being apoplectically angry enough to want to send them there.", "poster": "assets/tv-breeders-2020-poster.jpg", "backdrop": "assets/tv-breeders-2020-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-28T18:54:21.8885435Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 93290, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 92, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.8, "tmdbVotes": 104}}, {"id": "tv-the-four-seasons-2025", "title": "The Four Seasons", "year": 2025, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 6.879, "criticRating": null, "genres": ["Comedy"], "overview": "The decades-long friendship between three married couples is tested when one divorces, complicating their tradition of quarterly weekend getaways.", "poster": "assets/tv-the-four-seasons-2025-poster.jpg", "backdrop": "assets/tv-the-four-seasons-2025-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-28T18:36:42.5326384Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 243316, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 81, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.892, "tmdbVotes": 204}}, {"id": "tv-adults-2025", "title": "Adults", "year": 2025, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 6.495, "criticRating": null, "genres": ["Comedy"], "overview": "A group of twenty-somethings in New York trying to be good people, despite being neither \"good\" nor \"people\" yet.", "poster": "assets/tv-adults-2025-poster.jpg", "backdrop": "assets/tv-adults-2025-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-23T21:01:41.1814765Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 260458, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 88, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.5, "tmdbVotes": 102}}, {"id": "tv-east-of-eden-2026", "title": "East of Eden", "year": 2026, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.931, "criticRating": null, "genres": ["Drama", "Crime"], "overview": "In the early 1900s, a fiercely independent woman drives a rift between two brothers, igniting a saga that unfolds across two generations.", "poster": "assets/tv-east-of-eden-2026-poster.jpg", "backdrop": "assets/tv-east-of-eden-2026-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-23T18:07:11.3965096Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 258165, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 88, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.982, "tmdbVotes": 139}}, {"id": "movie-fighting-with-my-family-2019", "title": "Fighting with My Family", "year": 2019, "type": "movie", "runtimeSeconds": 6509, "seasonCount": null, "communityRating": 6.84, "criticRating": 93, "genres": ["Comedy"], "overview": "Born into a tight-knit wrestling family, Paige and her brother Zak are ecstatic when they get the once-in-a-lifetime opportunity to try out for the WWE. But when only Paige earns a spot in the competitive training\u2026", "poster": "assets/movie-fighting-with-my-family-2019-poster.jpg", "backdrop": "assets/movie-fighting-with-my-family-2019-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-22T22:10:59.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 445629, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 93, "rtCriticsLabel": "Certified Fresh", "rtAudience": 86, "rtAudienceLabel": "Upright", "imdb": 7, "imdbVotes": 94576, "tmdb": 6.837, "tmdbVotes": 1952}}, {"id": "tv-landman-2024", "title": "Landman", "year": 2024, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 8.194, "criticRating": null, "genres": ["Drama"], "overview": "Set in the proverbial boomtowns of West-Texas and a modern-day tale of fortune-seeking in the world of oil rigs, the series is an upstairs/downstairs story of roughnecks and wildcat billionaires that are fueling a\u2026", "poster": "assets/tv-landman-2024-poster.jpg", "backdrop": "assets/tv-landman-2024-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-22T21:38:18.0973875Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 157741, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 80, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.209, "tmdbVotes": 668}}, {"id": "tv-fawlty-towers-1975", "title": "Fawlty Towers", "year": 1975, "type": "tv", "runtimeSeconds": 1800, "seasonCount": 2, "communityRating": 8.295, "criticRating": null, "genres": ["Comedy"], "overview": "Owner Basil Fawlty, his wife Sybil, a chambermaid Polly, and Spanish waiter Manuel attempt to run their hotel amidst farcical situations and an array of demanding guests.", "poster": "assets/tv-fawlty-towers-1975-poster.jpg", "backdrop": "assets/tv-fawlty-towers-1975-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-19T23:26:39.7658344Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 2207, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.296, "tmdbVotes": 867}}], "discover": [{"id": "movie-12-years-a-slave-2013", "title": "12 Years a Slave", "year": 2013, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "History"], "overview": "In the pre-Civil War United States, Solomon Northup, a free black man from upstate New York, is abducted and sold into slavery. Facing cruelty as well as unexpected kindnesses Solomon struggles not only to stay\u2026", "poster": "assets/movie-12-years-a-slave-2013-poster.jpg", "backdrop": "assets/movie-12-years-a-slave-2013-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 76203, "ratings": {"rtCritics": 95, "rtCriticsLabel": "Certified Fresh", "rtAudience": 90, "rtAudienceLabel": "Upright", "imdb": 8.1, "imdbVotes": 796313, "tmdb": 7.927, "tmdbVotes": 12335}}, {"id": "movie-101-dalmatians-ii-patch-s-london-adventure-2003", "title": "101 Dalmatians II: Patch's London Adventure", "year": 2003, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Family", "Animation", "Adventure"], "overview": "Being one of 101 takes its toll on Patch, who doesn't feel unique. When he's accidentally left behind on moving day, he meets his idol, Thunderbolt, who enlists him on a publicity campaign.", "poster": "assets/movie-101-dalmatians-ii-patch-s-london-adventure-2003-poster.jpg", "backdrop": "assets/movie-101-dalmatians-ii-patch-s-london-adventure-2003-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 13654, "ratings": {"rtCritics": 67, "rtCriticsLabel": "Fresh", "rtAudience": 41, "rtAudienceLabel": "Spilled", "imdb": 5.7, "imdbVotes": 12343, "tmdb": 6.025, "tmdbVotes": 1274}}, {"id": "movie-absolution-2024", "title": "Absolution", "year": 2024, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action", "Crime", "Thriller"], "overview": "An aging ex-boxer gangster working as muscle for a Boston crime boss receives an upsetting diagnosis. Despite a faltering memory, he attempts to rectify the sins of his past and reconnect with his estranged\u2026", "poster": "assets/movie-absolution-2024-poster.jpg", "backdrop": "assets/movie-absolution-2024-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 974453, "ratings": {"rtCritics": 56, "rtCriticsLabel": "Rotten", "rtAudience": 32, "rtAudienceLabel": "Spilled", "imdb": 5.2, "imdbVotes": 11413, "tmdb": 5.906, "tmdbVotes": 564}}, {"id": "movie-addicted-2014", "title": "Addicted", "year": 2014, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Thriller"], "overview": "A gallerist risks her family and flourishing career when she enters into an affair with a talented painter and slowly loses control of her life.", "poster": "assets/movie-addicted-2014-poster.jpg", "backdrop": "assets/movie-addicted-2014-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 235271, "ratings": {"rtCritics": 7, "rtCriticsLabel": "Rotten", "rtAudience": 51, "rtAudienceLabel": "Spilled", "imdb": 5, "imdbVotes": 13131, "tmdb": 5.928, "tmdbVotes": 466}}, {"id": "movie-all-the-money-in-the-world-2017", "title": "All the Money in the World", "year": 2017, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Crime", "History", "Thriller"], "overview": "The story of the kidnapping of 16-year-old John Paul Getty III and the desperate attempt by his devoted mother to convince his billionaire grandfather Jean Paul Getty to pay the ransom.", "poster": "assets/movie-all-the-money-in-the-world-2017-poster.jpg", "backdrop": "assets/movie-all-the-money-in-the-world-2017-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 446791, "ratings": {"rtCritics": 79, "rtCriticsLabel": "Certified Fresh", "rtAudience": 66, "rtAudienceLabel": "Upright", "imdb": 6.8, "imdbVotes": 97448, "tmdb": 6.493, "tmdbVotes": 2493}}, {"id": "movie-the-alto-knights-2025", "title": "The Alto Knights", "year": 2025, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Crime", "Drama"], "overview": "Two of New York's most notorious organized crime bosses, Frank Costello and Vito Genovese, vie for control of the city's streets. Once the best of friends, petty jealousies and a series of betrayals place them on a\u2026", "poster": "assets/movie-the-alto-knights-2025-poster.jpg", "backdrop": "assets/movie-the-alto-knights-2025-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 1013601, "ratings": {"rtCritics": 39, "rtCriticsLabel": "Rotten", "rtAudience": 71, "rtAudienceLabel": "Upright", "imdb": 5.9, "imdbVotes": 23017, "tmdb": 6.223, "tmdbVotes": 485}}, {"id": "movie-the-amazing-spider-man-2-2014", "title": "The Amazing Spider-Man 2", "year": 2014, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action", "Adventure", "Science Fiction"], "overview": "For Peter Parker, life is busy. Between taking out the bad guys as Spider-Man and spending time with the person he loves, Gwen Stacy, high school graduation cannot come quickly enough. Peter has not forgotten about\u2026", "poster": "assets/movie-the-amazing-spider-man-2-2014-poster.jpg", "backdrop": "assets/movie-the-amazing-spider-man-2-2014-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 102382, "ratings": {"rtCritics": 51, "rtCriticsLabel": "Rotten", "rtAudience": 64, "rtAudienceLabel": "Upright", "imdb": 6.6, "imdbVotes": 611981, "tmdb": 6.567, "tmdbVotes": 14919}}, {"id": "movie-ant-man-and-the-wasp-quantumania-2023", "title": "Ant-Man and the Wasp: Quantumania", "year": 2023, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action", "Adventure", "Science Fiction"], "overview": "Super-Hero partners Scott Lang and Hope van Dyne, along with with Hope's parents Janet van Dyne and Hank Pym, and Scott's daughter Cassie Lang, find themselves exploring the Quantum Realm, interacting with strange\u2026", "poster": "assets/movie-ant-man-and-the-wasp-quantumania-2023-poster.jpg", "backdrop": "assets/movie-ant-man-and-the-wasp-quantumania-2023-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 640146, "ratings": {"rtCritics": 46, "rtCriticsLabel": "Rotten", "rtAudience": 81, "rtAudienceLabel": "Upright", "imdb": 6, "imdbVotes": 281738, "tmdb": 6.197, "tmdbVotes": 6236}}, {"id": "movie-arctic-dogs-2019", "title": "Arctic Dogs", "year": 2019, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Animation", "Adventure", "Comedy"], "overview": "Animals band together to save the day when the evil Otto Von Walrus hatches a sinister scheme to accelerate global warming and melt the Arctic Circle.", "poster": "assets/movie-arctic-dogs-2019-poster.jpg", "backdrop": "assets/movie-arctic-dogs-2019-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 416153, "ratings": {"rtCritics": 13, "rtCriticsLabel": "Rotten", "rtAudience": 60, "rtAudienceLabel": "Upright", "imdb": 4.9, "imdbVotes": 2580, "tmdb": 5.9, "tmdbVotes": 148}}, {"id": "movie-the-avengers-2012", "title": "The Avengers", "year": 2012, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Science Fiction", "Action", "Adventure"], "overview": "When an unexpected enemy emerges and threatens global safety and security, Nick Fury, director of the international peacekeeping agency known as S.H.I.E.L.D., finds himself in need of a team to pull the world back\u2026", "poster": "assets/movie-the-avengers-2012-poster.jpg", "backdrop": "assets/movie-the-avengers-2012-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 24428, "ratings": {"rtCritics": 91, "rtCriticsLabel": "Certified Fresh", "rtAudience": 91, "rtAudienceLabel": "Upright", "imdb": 8, "imdbVotes": 1590693, "tmdb": 8.084, "tmdbVotes": 40262}}, {"id": "movie-black-bear-2020", "title": "Black Bear", "year": 2020, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Thriller"], "overview": "At a remote lake house in the Adirondack Mountains, a couple entertains an out-of-town guest looking for inspiration in her filmmaking. The group quickly falls into a calculated game of desire, manipulation, and\u2026", "poster": "assets/movie-black-bear-2020-poster.jpg", "backdrop": "assets/movie-black-bear-2020-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 624788, "ratings": {"rtCritics": 89, "rtCriticsLabel": "Certified Fresh", "rtAudience": 64, "rtAudienceLabel": "Upright", "imdb": 6.5, "imdbVotes": 18408, "tmdb": 6.337, "tmdbVotes": 315}}, {"id": "movie-black-panther-2018", "title": "Black Panther", "year": 2018, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action", "Adventure", "Science Fiction"], "overview": "King T'Challa returns home to the reclusive, technologically advanced African nation of Wakanda to serve as his country's new leader. However, T'Challa soon finds that he is challenged for the throne by factions\u2026", "poster": "assets/movie-black-panther-2018-poster.jpg", "backdrop": "assets/movie-black-panther-2018-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 284054, "ratings": {"rtCritics": 96, "rtCriticsLabel": "Certified Fresh", "rtAudience": null, "rtAudienceLabel": "Spilled", "imdb": 7.3, "imdbVotes": 931120, "tmdb": 7.36, "tmdbVotes": 24190}}, {"id": "movie-a-bronx-tale-1993", "title": "A Bronx Tale", "year": 1993, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Crime"], "overview": "Set in the Bronx during the tumultuous 1960s, an adolescent boy is torn between his honest, working-class father and a violent yet charismatic crime boss. Complicating matters is the youngster's growing attraction -\u2026", "poster": "assets/movie-a-bronx-tale-1993-poster.jpg", "backdrop": "assets/movie-a-bronx-tale-1993-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 1607, "ratings": {"rtCritics": 97, "rtCriticsLabel": "Fresh", "rtAudience": 92, "rtAudienceLabel": "Upright", "imdb": 7.8, "imdbVotes": 191930, "tmdb": 7.913, "tmdbVotes": 3075}}, {"id": "movie-by-any-means-2026", "title": "By Any Means", "year": 2026, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Thriller", "History", "Crime"], "overview": "In 1960s Mississippi, a young Black FBI agent is forced to partner with a notorious mafia hitman to investigate a wave of brutal civil rights murders.", "poster": "assets/movie-by-any-means-2026-poster.jpg", "backdrop": "assets/movie-by-any-means-2026-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 1380417, "ratings": {"rtCritics": 49, "rtCriticsLabel": "Rotten", "rtAudience": 88, "rtAudienceLabel": "Upright", "imdb": 6.8, "imdbVotes": 3534, "tmdb": 6.6, "tmdbVotes": 92}}, {"id": "movie-captain-america-civil-war-2016", "title": "Captain America: Civil War", "year": 2016, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Adventure", "Action", "Science Fiction"], "overview": "Following the events of Age of Ultron, the collective governments of the world pass an act designed to regulate all superhuman activity. This polarizes opinion amongst the Avengers, causing two factions to side with\u2026", "poster": "assets/movie-captain-america-civil-war-2016-poster.jpg", "backdrop": "assets/movie-captain-america-civil-war-2016-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 271110, "ratings": {"rtCritics": 90, "rtCriticsLabel": "Certified Fresh", "rtAudience": 89, "rtAudienceLabel": "Upright", "imdb": 7.8, "imdbVotes": 954943, "tmdb": 7.455, "tmdbVotes": 24808}}, {"id": "movie-captain-america-the-first-avenger-2011", "title": "Captain America: The First Avenger", "year": 2011, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action", "Adventure", "Science Fiction"], "overview": "During World War II, Steve Rogers is a sickly man from Brooklyn who's transformed into super-soldier Captain America to aid in the war effort. Rogers must stop the Red Skull \u2013 Adolf Hitler's ruthless head of\u2026", "poster": "assets/movie-captain-america-the-first-avenger-2011-poster.jpg", "backdrop": "assets/movie-captain-america-the-first-avenger-2011-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 1771, "ratings": {"rtCritics": 80, "rtCriticsLabel": "Certified Fresh", "rtAudience": 75, "rtAudienceLabel": "Upright", "imdb": 6.9, "imdbVotes": 993453, "tmdb": 7.012, "tmdbVotes": 23473}}, {"id": "movie-captain-america-the-winter-soldier-2014", "title": "Captain America: The Winter Soldier", "year": 2014, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action", "Adventure", "Science Fiction"], "overview": "After the cataclysmic events in New York with The Avengers, Steve Rogers, aka Captain America is living quietly in Washington, D.C. and trying to adjust to the modern world. But when a S.H.I.E.L.D. colleague comes\u2026", "poster": "assets/movie-captain-america-the-winter-soldier-2014-poster.jpg", "backdrop": "assets/movie-captain-america-the-winter-soldier-2014-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 100402, "ratings": {"rtCritics": 90, "rtCriticsLabel": "Certified Fresh", "rtAudience": 92, "rtAudienceLabel": "Upright", "imdb": 7.7, "imdbVotes": 995514, "tmdb": 7.654, "tmdbVotes": 20688}}, {"id": "movie-careful-what-you-wish-for-2015", "title": "Careful What You Wish For", "year": 2015, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Thriller"], "overview": "A guy gets more than he bargained for after entering into an affair with the wife of an investment banker. Soon, a suspicious death and substantial life insurance policy embroil him in a scandal.", "poster": "assets/movie-careful-what-you-wish-for-2015-poster.jpg", "backdrop": "assets/movie-careful-what-you-wish-for-2015-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 317744, "ratings": {"rtCritics": 17, "rtCriticsLabel": "Rotten", "rtAudience": 61, "rtAudienceLabel": "Upright", "imdb": 5.6, "imdbVotes": 9452, "tmdb": 6.129, "tmdbVotes": 446}}, {"id": "tv-12-monkeys-2015", "title": "12 Monkeys", "year": 2015, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Sci-Fi & Fantasy", "Drama"], "overview": "The provocative story of Cole, a time traveler from a decimated future in a high-stakes race against the clock. Utilizing a dangerous and untested method of time travel, he journeys from 2043 to the present day on a\u2026", "poster": "assets/tv-12-monkeys-2015-poster.jpg", "backdrop": "assets/tv-12-monkeys-2015-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 60948, "ratings": {"rtCritics": 88, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.441, "tmdbVotes": 1245}}, {"id": "tv-90-day-fiance-before-the-90-days-2017", "title": "90 Day Fianc\u00e9: Before the 90 Days", "year": 2017, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Reality"], "overview": "Follow couples who have an existing relationship online, but haven't met in person. We'll experience their journey as they travel to the other's foreign country for the first time in an attempt to establish an\u2026", "poster": "assets/tv-90-day-fiance-before-the-90-days-2017-poster.jpg", "backdrop": "assets/tv-90-day-fiance-before-the-90-days-2017-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 73319, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.5, "tmdbVotes": 45}}, {"id": "tv-90-day-fiance-the-other-way-2019", "title": "90 Day Fianc\u00e9: The Other Way", "year": 2019, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Reality"], "overview": "Americans move to a foreign country all in the name of love. Will uprooting their lives in the United States pay off, or will they be packing up and moving back to America brokenhearted?", "poster": "assets/tv-90-day-fiance-the-other-way-2019-poster.jpg", "backdrop": "assets/tv-90-day-fiance-the-other-way-2019-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 90046, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.8, "tmdbVotes": 34}}, {"id": "tv-the-100-2014", "title": "The 100", "year": 2014, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Sci-Fi & Fantasy", "Action & Adventure", "Drama"], "overview": "100 years in the future, when the Earth has been abandoned due to radioactivity, the last surviving humans live on an ark orbiting the planet \u2014 but the ark won't last forever. So the repressive regime picks 100\u2026", "poster": "assets/tv-the-100-2014-poster.jpg", "backdrop": "assets/tv-the-100-2014-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 48866, "ratings": {"rtCritics": 93, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.878, "tmdbVotes": 8855}}, {"id": "tv-accused-2023", "title": "Accused", "year": 2023, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Crime", "Drama"], "overview": "In this crime anthology series, viewers discover how an ordinary person got caught up in an extraordinary situation, ultimately revealing how one wrong turn leads to another, until it\u2019s too late to turn back. Told\u2026", "poster": "assets/tv-accused-2023-poster.jpg", "backdrop": "assets/tv-accused-2023-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 202097, "ratings": {"rtCritics": 61, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.851, "tmdbVotes": 87}}, {"id": "tv-after-life-2019", "title": "After Life", "year": 2019, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "Tony had a perfect life. But after his wife Lisa suddenly dies, Tony changes. After contemplating taking his own life, he decides instead to live long enough to punish the world by saying and doing whatever he likes\u2026", "poster": "assets/tv-after-life-2019-poster.jpg", "backdrop": "assets/tv-after-life-2019-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 79410, "ratings": {"rtCritics": 72, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.902, "tmdbVotes": 1169}}, {"id": "tv-all-creatures-great-and-small-1978", "title": "All Creatures Great and Small", "year": 1978, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "The trials and misadventures of the staff at a country veterinary office in Yorkshire. James Herriot, a young animal surgeon, moves to a small Yorkshire town to begin his first job.", "poster": "assets/tv-all-creatures-great-and-small-1978-poster.jpg", "backdrop": "assets/tv-all-creatures-great-and-small-1978-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "center_crop", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 7406, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.8, "tmdbVotes": 50}}, {"id": "tv-american-housewife-2016", "title": "American Housewife", "year": 2016, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Comedy"], "overview": "A family comedy narrated by Katie, a strong-willed mother, raising her flawed family in a wealthy town filled with perfect wives and their perfect offspring.", "poster": "assets/tv-american-housewife-2016-poster.jpg", "backdrop": "assets/tv-american-housewife-2016-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 67117, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.7, "tmdbVotes": 187}}, {"id": "tv-atlantis-2013", "title": "Atlantis", "year": 2013, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action & Adventure", "Sci-Fi & Fantasy"], "overview": "A fantasy drama set in a world of legendary heroes and mythical creatures. Far from home and desperate for answers, Jason washes up on the shores of an ancient land. A mysterious place; a world of bull leaping, of\u2026", "poster": "assets/tv-atlantis-2013-poster.jpg", "backdrop": "assets/tv-atlantis-2013-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 47054, "ratings": {"rtCritics": 62, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.4, "tmdbVotes": 155}}, {"id": "tv-avatar-the-last-airbender-2024", "title": "Avatar: The Last Airbender", "year": 2024, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action & Adventure", "Sci-Fi & Fantasy", "Drama"], "overview": "A young boy known as the Avatar must master the four elemental powers to save a world at war \u2014 and fight a ruthless enemy bent on stopping him.", "poster": "assets/tv-avatar-the-last-airbender-2024-poster.jpg", "backdrop": "assets/tv-avatar-the-last-airbender-2024-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 82452, "ratings": {"rtCritics": 66, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.8, "tmdbVotes": 1406}}, {"id": "tv-avatar-seven-havens-2026", "title": "Avatar: Seven Havens", "year": 2026, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "In a world shattered by a devastating cataclysm, a young Earthbender discovers she's the new Avatar after Korra. But in this dangerous era, that title marks her as humanity's destroyer, not its savior. Hunted by both\u2026", "poster": "assets/tv-avatar-seven-havens-2026-poster.jpg", "backdrop": "assets/tv-avatar-seven-havens-2026-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 284833, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.9, "tmdbVotes": 183}}, {"id": "tv-batman-the-brave-and-the-bold-2008", "title": "Batman: The Brave and the Bold", "year": 2008, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "The Caped Crusader is teamed up with Blue Beetle, Green Arrow, Aquaman and countless others in his quest to uphold justice.", "poster": "assets/tv-batman-the-brave-and-the-bold-2008-poster.jpg", "backdrop": "assets/tv-batman-the-brave-and-the-bold-2008-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 15804, "ratings": {"rtCritics": 96, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.6, "tmdbVotes": 295}}, {"id": "tv-beat-bobby-flay-2013", "title": "Beat Bobby Flay", "year": 2013, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Reality"], "overview": "Two talented chefs go head-to-head for the chance to Beat Bobby Flay. To get to Bobby the chefs must first face off against each other, creating a spectacular dish with a secret ingredient of Bobby's choice. Judges\u2026", "poster": "assets/tv-beat-bobby-flay-2013-poster.jpg", "backdrop": "assets/tv-beat-bobby-flay-2013-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 62481, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.5, "tmdbVotes": 31}}, {"id": "tv-benson-1979", "title": "Benson", "year": 1979, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Comedy"], "overview": "A butler deals with life at the governor's mansion.", "poster": "assets/tv-benson-1979-poster.jpg", "backdrop": "assets/tv-benson-1979-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 1849, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7, "tmdbVotes": 46}}, {"id": "tv-black-rabbit-2025", "title": "Black Rabbit", "year": 2025, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Crime"], "overview": "A rising-star restaurateur is forced into New York's criminal underworld when his chaotic brother returns to town with loan sharks on his trail.", "poster": "assets/tv-black-rabbit-2025-poster.jpg", "backdrop": "assets/tv-black-rabbit-2025-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 249039, "ratings": {"rtCritics": 66, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.983, "tmdbVotes": 240}}, {"id": "tv-black-ish-2014", "title": "black-ish", "year": 2014, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Comedy"], "overview": "A family man struggles to gain a sense of cultural identity while raising his kids in a predominantly white, upper-middle-class neighborhood.", "poster": "assets/tv-black-ish-2014-poster.jpg", "backdrop": "assets/tv-black-ish-2014-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 61381, "ratings": {"rtCritics": 92, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.1, "tmdbVotes": 352}}, {"id": "tv-breaking-bad-2008", "title": "Breaking Bad", "year": 2008, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Crime"], "overview": "Walter White, a New Mexico chemistry teacher, is diagnosed with Stage III cancer and given a prognosis of only two years left to live. He becomes filled with a sense of fearlessness and an unrelenting desire to\u2026", "poster": "assets/tv-breaking-bad-2008-poster.jpg", "backdrop": "assets/tv-breaking-bad-2008-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "center_crop", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 1396, "ratings": {"rtCritics": 96, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.959, "tmdbVotes": 19030}}, {"id": "tv-the-capture-2019", "title": "The Capture", "year": 2019, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Crime", "Drama", "Mystery"], "overview": "When soldier Shaun Emery's conviction for a murder in Afghanistan is overturned due to flawed video evidence, he returns to life as a free man with his young daughter. But when damning CCTV footage from a night out\u2026", "poster": "assets/tv-the-capture-2019-poster.jpg", "backdrop": "assets/tv-the-capture-2019-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 93166, "ratings": {"rtCritics": 97, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.634, "tmdbVotes": 361}}], "discoverySource": {"state": "materialized_snapshot", "rankKnown": false, "selection": "First 18 alphabetically indexed movie stubs and first 18 series stubs, not ranked feed order", "observedAt": "2026-11-04T20:42:12.030108+00:00"}}], "notes": {"real": ["Profile keys and library membership derive from deployed Conductarr configuration and viewer-scoped Jellyfin GET responses.", "Names, years, overviews, library ratings, genres, season-container counts and watch/resume data come from actual Jellyfin metadata.", "All local artwork is copied from Jellyfin; discovery posters are the real materialized Conductarr recommendation artwork.", "Discover contains 36 real materialized personal recommendations per profile, with profile-scoped availability from read-only retained membership/request state.", "Justin has no playable resume items. Mindel and Shared each have one. No progress or watched flags were invented."], "approximations": ["Default profile initials and display capitalization are frontend presentation choices; colours reuse the existing PWA palette, not live user appearance configuration.", "Conductarr catalogue and recommendation GET endpoints both returned 401. Authentication was not bypassed. SQLite contains no retained recommendation feed/candidate snapshot tables; the source keeps ranked feeds in memory. Discovery therefore reads existing per-profile Jellyfin recommendation stubs as metadata only.", "Discovery selection is 18 alphabetically indexed movie suggestions plus 18 series suggestions, not personal rank order; rank is null. Materialization age and original feed ordering are unknown.", "Discovery stub runtime is synthetic (two seconds), so runtime, season count, rating and watch state are null rather than presenting stub values as real media facts.", "93 selected identities lack original landscape art in the materialized metadata; their backdrop is a marked crop of the real poster, not an original film backdrop. Existing artwork is reused; new artwork is centre-cropped to the required dimensions.", "Jellyfin server-side resizing requests maxWidth/maxHeight/quality. When the result had the wrong aspect ratio, sequential single-thread ffmpeg center crops produce exact 300x450 and 1280x720 JPEGs.", "Series seasonCount is Jellyfin ChildCount, including season containers for specials when present.", "Discover availability is a retained profile-membership/request snapshot, not a fresh playback or acquisition guarantee. not_here means absent from that profile in retained state, not absent from the entire household."], "missing": ["Justin Movies has seven live viewer-scoped films, not 200. No titles are invented or borrowed across profile boundaries.", "Discovery community/critic ratings, reliable runtime/season counts, personal feed ranking/freshness and 93 original landscape backdrops are unavailable through the permitted read paths."], "unmetRequirements": ["At least 200 real profile-scoped Justin Movies"], "mustNotBeShown": ["Recs Movies", "Recs Shows", "Justin Movies", "Justin Shows", "Mindel Movies", "Mindel Shows", "Shared Movies", "Shared Shows", "DGiC", "Stored names padded with spaces", "Internal bucket and acquisition-instance names"], "privacy": ["Includes actual watched and resume history for Justin, Mindel and Shared independently; Shared is not a union.", "No Jellyfin item/user IDs, source paths, service URLs, credentials, request actor identities, or private hotlinks are included. tmdbId is a public external title identity.", "Only the seven configured playable libraries are selected. Extra observed DGiC views and all recommendation stubs are excluded from playable collections.", "No profile is assumed to be a child or age-restricted. Each playable list and episode shelf is limited to that profile\u2019s configured libraries."], "sourceReadPaths": ["GET /Users (allowlisted mapping only)", "GET /Users/{userId}/Views", "GET /Users/{userId}/Items (parent-scoped playable libraries and metadata-only recommendation libraries)", "GET /Users/{userId}/Items/Resume", "GET /Shows/NextUp?UserId=...", "GET /Items/{itemId}/Images/Primary", "GET /Items/{itemId}/Images/Backdrop/0", "Conductarr GET /catalogue/discover?page=1&media_type=movie (401)", "Conductarr GET /api/v1/recommendations/profiles/justin/feed (401)", "SQLite file URI mode=ro plus PRAGMA query_only=ON: catalogue_metadata, bucket_memberships, native_requests; sqlite_master for schema inspection"], "productionMutations": 0, "artwork": {"files": 632, "bytes": 35201423, "posterDimensions": [300, 450], "backdropDimensions": [1280, 720], "posterQualityRequested": 70, "backdropQualityRequested": 65, "posterDerivedBackdropCount": 93}, "consumerContract": ["profiles is an array in Justin/Mindel/Shared order. Every profile owns movies/shows/anime/resume/nextUp/recentlyAdded/discover item arrays; empty shelves are intentional.", "Item paths are relative to fixture.json. Resolve assets against the fixture directory, not against the outer prototype document.", "Use destinations for visible navigation. No raw library display/stored names belong in UI.", "Deduplicate library/resume/discover by stable local id or (type,tmdbId). Never treat a materialized recommendation as a playable library item.", "played=null and watchStateKnown=false mean unknown, not unwatched. Null ratings are missing, not zero; communityRating source is Jellyfin, not an asserted TMDB/IMDb score.", "availability values are in_library/requested/not_here. No requested examples were observed in the selected discover set; do not fabricate them.", "Render artwork.backdropKind=poster_crop as a poster-derived landscape; prefer the poster over pretending it is original landscape art.", "This static fixture preserves actual current collection sizes, viewer-scoped watch state and unknown discovery ranking; request and playback demonstrations must remain labelled simulations."]}} \ No newline at end of file diff --git a/wolfskin-design/src/debug/java/org/justinvisser/wolfskin/design/HomeFixture.kt b/wolfskin-design/src/debug/java/org/justinvisser/wolfskin/design/HomeFixture.kt new file mode 100644 index 00000000..c046c290 --- /dev/null +++ b/wolfskin-design/src/debug/java/org/justinvisser/wolfskin/design/HomeFixture.kt @@ -0,0 +1,129 @@ +package org.justinvisser.wolfskin.design + +import android.content.Context +import org.json.JSONArray +import org.json.JSONObject + +/** The locked fixture is debug-only; release variants cannot construct synthetic household data. */ +class HomeFixture(context: Context) { + private val source = context.assets.open("wolfskin-home/fixture.json").bufferedReader().use { JSONObject(it.readText()) } + private val profiles = source.getJSONArray("profiles").objects() + private val allSeries = profiles.flatMap { it.items("shows") + it.items("anime") } + private val pool = profiles.flatMap { it.items("discover") }.distinctBy { it.identity() } + private val owners = linkedMapOf>().apply { + profiles.forEach { profile -> + listOf("movies", "shows", "anime").flatMap { profile.items(it) }.forEach { item -> + getOrPut(item.identity()) { linkedSetOf() }.add(profile.getString("name")) + } + } + } + + fun snapshot(person: String, state: String = "ready"): HomeSnapshot { + val profile = profiles.first { it.getString("key") == person } + val library = HomeLibrary(profile.items("resume").map(::title), profile.items("nextUp").map(::title), profile.items("recentlyAdded").map(::title), listOf("movies", "shows", "anime").associateWith { key -> profile.items(key).map(::title) }) + val status = when (state) { "unsigned" -> HomeAvailability.SignedOut; "cond-down" -> HomeAvailability.Unavailable; "offline", "cond-cached" -> HomeAvailability.Saved; "loading" -> HomeAvailability.Loading; else -> HomeAvailability.Ready } + val continuation = if (status == HomeAvailability.SignedOut || status == HomeAvailability.Unavailable) listOf(homeDiscoverState(status)) else continuation(profile, state) + var rows = buildHomeRows(library, continuation, state != "jf-down", state == "loading") + rows = rows.map { row -> + if (!row.catalogue) row else { + fun owned(title: HomeTitle): HomeTitle { + val names = owners[title.tmdbId?.let { "${title.type}:$it" } ?: title.id].orEmpty() + val held = title.held || profile.getString("name") in names + val other = if (held) null else names.filter { it != profile.getString("name") }.takeIf { it.isNotEmpty() }?.joinToString(" and ") + return if (held == title.held && other == title.otherOwner) title else title.copy(held = held, otherOwner = other) + } + val cards = row.cards.map(::owned) + row.copy(cards = cards, allCards = if (row.allCards === row.cards) cards else row.allCards.map(::owned)) + } + } + if (state == "missing") { + val missing = profiles.flatMap { person -> listOf("movies", "shows", "anime", "discover", "nextUp", "recentlyAdded").flatMap { key -> person.items(key).filterIndexed { index, _ -> index % 3 == 0 } } }.map { it.getString("id") }.toSet() + rows = rows.map { row -> row.copy(cards = row.cards.map { if (it.id in missing) it.copy(poster = null, backdrop = null) else it }) } + } + return HomeSnapshot(rows, status, state != "jf-down" && state != "offline", if (status == HomeAvailability.Saved) "20:42" else null) + } + + private fun continuation(profile: JSONObject, state: String): List = buildList { + val picks = profile.items("discover") + val movies = picks.filter { it.getString("type") == "movie" } + val shows = picks.filter { it.getString("type") == "tv" } + val played = listOf("movies", "shows", "anime").flatMap { profile.items(it) }.filter { it.optBoolean("played") } + val groups = linkedMapOf>>() + (movies + shows).forEach { candidate -> + played.map { it to genres(it).intersect(genres(candidate)).size }.filter { it.second > 0 }.sortedByDescending { it.second }.take(2).forEach { (seed, _) -> + groups.getOrPut(seed.identity()) { seed to mutableListOf() }.second.add(candidate) + } + } + val seen = mutableSetOf() + if (state == "picks-unavailable" || state == "no-seeds") { + add(HomeRow("picks-na", HomeRowKind.Note, text = if (state == "no-seeds") "Watch something to get picks for ${profile.getString("name")}." else "Picks unavailable right now.", calm = state == "no-seeds")) + } else { + val groupRows = groups.values.take(3) + fun take(items: List, limit: Int): List = items.filter { it.identity() !in seen }.take(limit).filter { seen.add(it.identity()) } + val movieRow = take(movies, minOf(12, kotlin.math.ceil(movies.size.toDouble() / (groupRows.size + 1)).toInt())) + val showRow = take(shows, minOf(12, kotlin.math.ceil(shows.size.toDouble() / (groupRows.size + 1)).toInt())) + val remaining = (movies + shows).count { it.identity() !in seen } + val size = if (groupRows.isEmpty()) 0 else minOf(8, kotlin.math.ceil(remaining.toDouble() / groupRows.size).toInt()) + val watchedRows = groupRows.map { (seed, items) -> Triple(seed, take(items, size), items) }.filter { it.second.size >= 3 } + if (movieRow.isNotEmpty()) add(shelf("pk-m", "Movies for you", movieRow, movies.size, movies)) + if (showRow.isNotEmpty()) add(shelf("pk-s", "Series for you", showRow, shows.size, shows)) + watchedRows.take(2).forEachIndexed { index, (seed, items, all) -> add(shelf("pk-w$index", "Because you watched ${seed.getString("title")}", items, all.size, all)) } + } + val excluded = flatMap { row -> row.cards }.map { it.id }.toSet() + val base = pool.filter { it.getString("id") !in excluded } + listOf("Netflix", "Prime Video").forEachIndexed { index, service -> + val shift = if (base.isEmpty()) 0 else index * 7 % base.size + val rotated = base.drop(shift) + base.take(shift) + add(shelf("new-$index", "New on $service", rotated.take(12).sortedByDescending { it.optInt("year") })) + } + add(shelf("trending", "Trending", base.take(WolfskinTokens.Behaviour.rowLimit.toInt()), base.size, base)) + listOf("Comedy", "Animation", "Science Fiction", "Horror", "Romance").forEach { genre -> + val titles = base.filter { genre in genres(it) && (genre !in setOf("Science Fiction", "Horror", "Romance") || it.getString("type") == "movie") } + if (titles.isNotEmpty()) add(shelf("genre-$genre", genre, titles.take(WolfskinTokens.Behaviour.rowLimit.toInt()), titles.size, titles)) + } + add(HomeRow("explore", HomeRowKind.Explore, "Explore more in Discover")) + } + + private fun shelf(id: String, name: String, items: List, total: Int = items.size, allItems: List = items): HomeRow { + val cards = items.map(::title) + return HomeRow(id, HomeRowKind.Shelf, name, cards, catalogue = true, total = total, allCards = if (allItems === items) cards else allItems.map(::title)) + } + + private fun title(item: JSONObject): HomeTitle = HomeTitle( + id = item.getString("id"), title = item.getString("title"), type = item.getString("type"), + year = item.intOrNull("year"), runtimeSeconds = item.intOrNull("runtimeSeconds"), seasons = item.intOrNull("seasonCount"), + overview = item.optString("overview"), poster = item.stringOrNull("poster")?.let { "file:///android_asset/wolfskin-home/$it" }, + backdrop = item.stringOrNull("backdrop")?.let { "file:///android_asset/wolfskin-home/$it" }, + posterOnly = item.optJSONObject("artwork")?.optString("backdropKind") == "poster_crop", + seriesTitle = item.stringOrNull("seriesTitle"), season = item.intOrNull("seasonNumber"), episode = item.intOrNull("episodeNumber"), + resumeSeconds = item.optDouble("resumeSeconds", 0.0).takeIf { it.isFinite() } ?: 0.0, + played = item.optBoolean("played"), addedAt = item.optString("addedAt", ""), genres = genres(item).toList(), ratings = ratings(item), + held = item.optString("availability") == "in_library", tmdbId = item.intOrNull("tmdbId"), + ) + + private fun ratings(item: JSONObject): List { + val episode = item.optString("type") == "episode" + val series = if (episode) allSeries.firstOrNull { it.optString("title") == item.optString("seriesTitle") } else item + val source = series?.optJSONObject("ratings") ?: JSONObject().apply { + put("rtCritics", series?.opt("criticRating")); put("tmdb", series?.opt("communityRating")) + } + val result = mutableListOf() + fun score(key: String, max: Double): Double? = if (source.isNull(key)) null else source.optDouble(key).takeIf { it.isFinite() && it in 0.0..max } + score("rtCritics", 100.0)?.let { result += HomeRating(when (source.optString("rtCriticsLabel")) { "Fresh", "Certified Fresh" -> "fresh"; "Rotten" -> "rotten"; else -> "tomato" }, it, true) } + score("rtAudience", 100.0)?.let { result += HomeRating(if (source.optString("rtAudienceLabel") == "Spilled") "spilled" else "upright", it, true) } + score("imdb", 10.0)?.takeIf { source.isNull("imdbVotes") || source.optInt("imdbVotes") > 0 }?.let { result += HomeRating("imdb", it) } + if (result.isEmpty()) score("tmdb", 10.0)?.takeIf { source.isNull("tmdbVotes") || source.optInt("tmdbVotes") > 0 }?.let { result += HomeRating("tmdb", it) } + if (episode && !item.isNull("communityRating")) { + val score = item.optDouble("communityRating") + if (score.isFinite() && score in 0.0..10.0) { result.removeAll { it.mark == "tmdb" }; result += HomeRating("tmdb", score, episode = true) } + } + return result + } + + private fun genres(item: JSONObject): Set = item.optJSONArray("genres")?.let { array -> (0 until array.length()).flatMap { index -> when (val name = array.getString(index)) { "Sci-Fi & Fantasy" -> listOf("Science Fiction", "Fantasy"); "Action & Adventure" -> listOf("Action", "Adventure"); "Sci-Fi" -> listOf("Science Fiction"); else -> listOf(name) } }.toSet() }.orEmpty() + private fun JSONObject.identity(): String = if (!isNull("tmdbId")) "${optString("type")}:${optInt("tmdbId")}" else getString("id") + private fun JSONObject.items(key: String): List = getJSONArray(key).objects() + private fun JSONArray.objects(): List = List(length()) { getJSONObject(it) } + private fun JSONObject.intOrNull(key: String): Int? = if (isNull(key)) null else optInt(key) + private fun JSONObject.stringOrNull(key: String): String? = if (isNull(key)) null else optString(key).takeIf { it.isNotEmpty() } +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/Caption.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/Caption.kt new file mode 100644 index 00000000..5f9a0742 --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/Caption.kt @@ -0,0 +1,72 @@ +package org.justinvisser.wolfskin.design + +import androidx.compose.animation.core.Animatable +import androidx.compose.animation.core.CubicBezierEasing +import androidx.compose.animation.core.tween +import androidx.compose.foundation.layout.Column +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.text.TextStyle +import androidx.tv.material3.Text +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.ui.draw.clipToBounds +import androidx.compose.ui.layout.Layout +import androidx.compose.ui.unit.constrainHeight + +/** Captions fade without moving the reserved band under the focused poster. */ +@Composable +fun Caption(title: String, facts: String, visible: Boolean, modifier: Modifier = Modifier, accentLastFact: Boolean = false, accentFirstFact: Boolean = false, + titleStyle: TextStyle = WolfskinTokens.Type.button, factsStyle: TextStyle = WolfskinTokens.Type.caption, + titleOverflow: TextOverflow = TextOverflow.Ellipsis) { + val alpha = remember(title, facts) { Animatable(0f) } + LaunchedEffect(alpha, visible) { + alpha.animateTo(if (visible) 1f else 0f, tween(WolfskinTokens.Motion.fast, easing = CubicBezierEasing(.25f, .1f, .25f, 1f))) + } + Column(modifier.graphicsLayer { this.alpha = alpha.value }) { + Text(title, color = WolfskinTokens.Color.fg, style = titleStyle, modifier = Modifier.exactLineBox(titleStyle), maxLines = 1, overflow = titleOverflow) + CaptionFacts(facts, accentFirstFact, accentLastFact, factsStyle) + } +} + +/** CSS flex facts: only coloured role/ownership spans shrink; ordinary facts and dots keep their width. */ +@Composable +private fun CaptionFacts(facts: String, accentFirst: Boolean, accentLast: Boolean, style: TextStyle) { + val parts = remember(facts) { facts.split(" ยท ") } + val muted = WolfskinTokens.Color.muted + val colour = WolfskinTokens.Color.accentText + Layout( + content = { + parts.forEachIndexed { index, part -> + val accented = (index == 0 && accentFirst) || (index == parts.lastIndex && accentLast) + Text(part, color = if (accented) colour else muted, style = style, modifier = Modifier.exactLineBox(style), maxLines = 1, overflow = TextOverflow.Clip) + if (index != parts.lastIndex) Text("ยท", color = muted.copy(alpha = muted.alpha * WolfskinTokens.Library.captionSeparatorOpacity), style = style, modifier = Modifier.exactLineBox(style)) + } + }, + modifier = Modifier.fillMaxWidth().clipToBounds(), + ) { children, constraints -> + val gap = WolfskinTokens.Library.captionFactsGap.roundToPx() + val basis = IntArray(children.size) + var fixed = gap * (children.size - 1).coerceAtLeast(0) + var flexible = 0 + fun shrinks(index: Int) = (index == 0 && accentFirst) || (index == children.lastIndex && accentLast) + children.forEachIndexed { index, child -> + val width = child.maxIntrinsicWidth(constraints.maxHeight) + basis[index] = width + if (shrinks(index)) flexible += width else fixed += width + } + val available = (constraints.maxWidth - fixed).coerceAtLeast(0) + val ratio = if (flexible > available) available.toFloat() / flexible else 1f + val measured = children.mapIndexed { index, child -> + val width = if (shrinks(index)) (basis[index] * ratio).toInt() else basis[index] + child.measure(constraints.copy(minWidth = 0, maxWidth = width, minHeight = 0)) + } + layout(constraints.maxWidth, constraints.constrainHeight(measured.maxOfOrNull { it.height } ?: 0)) { + var x = 0 + measured.forEach { child -> child.placeRelative(x, 0); x += child.width + gap } + } + } +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/CatalogueRecoveryCard.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/CatalogueRecoveryCard.kt new file mode 100644 index 00000000..db0a22f6 --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/CatalogueRecoveryCard.kt @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-2.0-only +package org.justinvisser.wolfskin.design + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.style.TextAlign +import androidx.tv.material3.Text +import org.justinvisser.wolfskin.design.WolfskinTokens.Color as C +import org.justinvisser.wolfskin.design.WolfskinTokens.Library as G + +/** Shelves and continuous grids share the same recoverable tail instead of a page selector. */ +@Composable +fun CatalogueRecoveryCard(retry: Boolean, focused: Boolean, onClick: () -> Unit, modifier: Modifier = Modifier) { + val shape = RoundedCornerShape(WolfskinTokens.Radius.card) + Column(modifier.size(WolfskinTokens.Card.posterW, WolfskinTokens.Card.posterH) + .focusScale(focused, WolfskinTokens.Focus.scaleCard) + .focusRing(focused, WolfskinTokens.Radius.card, WolfskinTokens.Focus.ringCardGap, WolfskinTokens.Focus.ringCardRing, C.accent, FocusLift.Card) + .background(C.surface, shape).border(G.borderWidth, C.border, shape).clickable(onClick = onClick).padding(G.tailPadding), + verticalArrangement = Arrangement.spacedBy(G.tailGap, Alignment.CenterVertically), horizontalAlignment = Alignment.CenterHorizontally) { + Glyph(if (retry) "alert" else "down", if (retry) C.warn else C.accentText, Modifier.size(G.tailIcon)) + Text(if (retry) "Try again" else "Show more", color = C.fg, style = WolfskinTokens.Type.button, textAlign = TextAlign.Center) + Text(if (retry) "More titles couldnโ€™t load" else "Only titles already shown came back", color = C.muted, + style = G.tailDescription, textAlign = TextAlign.Center) + } +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/ComingInFixture.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/ComingInFixture.kt new file mode 100644 index 00000000..50608f0b --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/ComingInFixture.kt @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0-only +package org.justinvisser.wolfskin.design + +import org.json.JSONObject + +/** Debug assets and native screenshots consume the same projection of the frozen prototype. */ +fun readComingInFixture(json: String, poster: (String) -> Any?): List { + val items = JSONObject(json).getJSONArray("items") + return List(items.length()) { index -> + val item = items.getJSONObject(index) + val scores = item.getJSONArray("ratings") + ComingInRequest( + id = item.getString("id"), mediaType = item.getString("mediaType"), tmdbId = item.getLong("tmdbId"), + title = item.getString("title"), requesterKey = item.getString("requesterKey"), requesterName = item.getString("requesterName"), + actorKey = item.getString("actorKey"), actorName = item.getString("actorName"), stage = ComingInStage.valueOf(item.getString("stage")), + poster = poster(item.getString("poster")), + ratings = List(scores.length()) { scoreIndex -> + val score = scores.getJSONObject(scoreIndex) + ComingInRating(score.getString("mark"), score.getDouble("score"), score.getBoolean("percentage")) + }, + ) + } +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/ComingInLineBox.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/ComingInLineBox.kt new file mode 100644 index 00000000..e7ae86a9 --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/ComingInLineBox.kt @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0-only +package org.justinvisser.wolfskin.design + +import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.FirstBaseline +import androidx.compose.ui.layout.layout +import androidx.compose.ui.unit.Dp + +/** A CSS line box has its own height and baseline, independent of native leading rounding. */ +internal fun Modifier.comingInLineBox(height: Dp, baseline: Dp): Modifier = layout { measurable, constraints -> + val text = measurable.measure(constraints.copy(minHeight = 0)) + val baselineOffset = baseline.roundToPx() - text[FirstBaseline] + layout(text.width, height.roundToPx()) { + text.placeRelative(0, baselineOffset) + } +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/ComingInRatings.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/ComingInRatings.kt new file mode 100644 index 00000000..3f2b0da1 --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/ComingInRatings.kt @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0-only +package org.justinvisser.wolfskin.design + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.width +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.compose.foundation.background +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.ui.draw.clip +import androidx.compose.ui.layout.ContentScale +import androidx.tv.material3.Text +import java.util.Locale +import org.justinvisser.wolfskin.design.WolfskinTokens.Requests as T + +/** Percentages remain whole; ten-point scores use the television's locale. */ +fun formatComingInRating(rating: ComingInRating, locale: Locale = Locale.getDefault()): String = + if (rating.percentage) "${rating.score.toInt()}%" else String.format(locale, "%.1f", rating.score) + +/** This row always displays the full supplier set rather than the card plate's shortened prefix. */ +@Composable +fun ComingInRatings(ratings: List, color: Color) { + Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(T.ratingsGap)) { + ratings.forEach { rating -> + Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(T.ratingsEntryGap)) { + val mark = when (rating.mark) { + "fresh" -> R.drawable.coming_in_rating_fresh + "rotten" -> R.drawable.coming_in_rating_rotten + "upright" -> R.drawable.coming_in_rating_upright + "spilled" -> R.drawable.coming_in_rating_spilled + "imdb" -> R.drawable.coming_in_rating_imdb + else -> R.drawable.coming_in_rating_tmdb + } + val wide = rating.mark == "imdb" || rating.mark == "tmdb" + Image(painterResource(mark), contentDescription = rating.mark, + modifier = Modifier.height(T.readinessGlyph).width(T.readinessGlyph * if (wide) T.ratingsWordmarkRatio else 1f) + .clip(ratingMarkShape).background(WolfskinTokens.Color.surface3), + contentScale = ContentScale.Fit) + Text(formatComingInRating(rating), style = ComingInTypography.rating, color = color) + } + } + } +} + +private val ratingMarkShape = RoundedCornerShape(WolfskinTokens.Radius.thumb) diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/ComingInSheet.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/ComingInSheet.kt new file mode 100644 index 00000000..40ed8f3c --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/ComingInSheet.kt @@ -0,0 +1,175 @@ +// SPDX-License-Identifier: GPL-2.0-only +package org.justinvisser.wolfskin.design + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.draw.clipToBounds +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.draw.drawWithCache +import androidx.compose.ui.graphics.drawscope.drawIntoCanvas +import androidx.compose.ui.graphics.nativeCanvas +import androidx.compose.ui.graphics.toArgb +import androidx.compose.ui.input.pointer.PointerEventType +import androidx.compose.ui.input.pointer.PointerEventPass +import androidx.compose.ui.input.pointer.pointerInput +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.text.style.TextOverflow +import androidx.tv.material3.Text +import coil3.compose.AsyncImage +import coil3.compose.AsyncImagePainter +import androidx.compose.runtime.mutableStateOf +import org.justinvisser.wolfskin.design.WolfskinTokens.Color as C +import org.justinvisser.wolfskin.design.WolfskinTokens.Layout as L +import org.justinvisser.wolfskin.design.WolfskinTokens.Requests as T + +/** The overlay intercepts pointer input as well as the shell's virtual D-pad focus. */ +@Composable +fun ComingInSheet(shell: ShellState, modifier: Modifier = Modifier) { + val state = shell.requests + val data = state.snapshot + LaunchedEffect(state.focusedId, data.signedIn, data.status) { + state.awaitFocusedRatings() + } + Box(modifier.fillMaxSize().background(C.sheetScrim).clickable { shell.closeRequests() }.testTag("coming-in-scrim")) + Column(modifier.fillMaxHeight().width(L.sheetWidth) + .offset(x = WolfskinTokens.Shell.stageWidth - L.sheetWidth) + .drawWithCache { + val panel = android.graphics.Paint(android.graphics.Paint.ANTI_ALIAS_FLAG).apply { + color = C.surface.toArgb() + setShadowLayer(T.shadowBlur.toPx(), T.shadowOffset.toPx(), 0f, T.shadowColor.toArgb()) + } + onDrawBehind { + drawIntoCanvas { it.nativeCanvas.drawRect(0f, 0f, size.width, size.height, panel) } + } + }.pointerInput(Unit) { + awaitPointerEventScope { + while (true) awaitPointerEvent(PointerEventPass.Final).changes.forEach { it.consume() } + } + } + .padding(horizontal = T.sheetPaddingX, vertical = T.sheetPaddingY) + .testTag("coming-in"), verticalArrangement = Arrangement.spacedBy(T.sheetGap)) { + Text("Coming in", Modifier.comingInLineBox(T.sheetTitleLineHeight, T.sheetTitleBaseline), style = ComingInTypography.title, color = C.fg) + when { + data.status == ComingInStatus.Loading && data.items.isEmpty() -> { + LazyColumn(verticalArrangement = Arrangement.spacedBy(T.listGap)) { + items(3, key = { "request-skeleton-$it" }, contentType = { "skeleton" }) { ComingInSkeleton() } + } + SheetButton("Close") { shell.closeRequests() } + } + data.status == ComingInStatus.Unavailable && data.items.isEmpty() -> { + Column(Modifier.fillMaxWidth().background(C.listRowRest, RoundedCornerShape(WolfskinTokens.Radius.panel)) + .padding(horizontal = T.receiptPaddingX, vertical = T.receiptPaddingY), + verticalArrangement = Arrangement.spacedBy(T.receiptGap)) { + Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(T.rowPaddingY)) { + Glyph("alert", C.warn, Modifier.size(T.receiptGlyph)) + Text("Requests unavailable", style = ComingInTypography.stateTitle, color = C.warn) + } + Text("Conductarr didnโ€™t answer.", style = ComingInTypography.body, color = C.muted) + } + SheetButton("Try again", primary = true) { shell.retryRequests() } + } + data.items.isEmpty() -> Text("Nothing coming in.", Modifier.padding(top = T.emptyMargin), style = ComingInTypography.body, color = C.muted) + else -> { + if (data.status == ComingInStatus.Unavailable) Text("Conductarr didnโ€™t answer.", style = ComingInTypography.caption, color = C.warn) + data.savedAt?.takeIf { data.status == ComingInStatus.Unavailable }?.let { SavedPill(it) } + if (data.partial) Text("Some requests may be missing: Conductarr answered only in part.", style = ComingInTypography.caption, color = C.warn) + val start = state.windowStart + val visibleRows = remember(data, start, state.windowSize) { + data.ordered.subList(start, (start + state.windowSize).coerceAtMost(data.ordered.size)) + } + LazyColumn(Modifier.clipToBounds().then(if (data.status == ComingInStatus.Unavailable) Modifier.weight(1f, fill = false) else Modifier), verticalArrangement = Arrangement.spacedBy(T.listGap)) { + itemsIndexed(visibleRows, + key = { _, item -> item.id }, contentType = { _, _ -> "request" }) { _, item -> + ComingInRow(item, shell.person, !state.recoveryFocused && item.id == state.focusedId, state.expanded && item.id == state.focusedId, + state.ratingsVisible && data.signedIn && item.id == state.focusedId, + onFocus = { state.focus(item.id) }, onClick = { state.focus(item.id); shell.activateRequest() }) + } + } + if (data.status == ComingInStatus.Unavailable) SheetButton("Try again", primary = true, focused = state.recoveryFocused) { shell.retryRequests() } + } + } + } +} + +@Composable +private fun SheetButton(label: String, primary: Boolean = false, focused: Boolean = true, onClick: () -> Unit) { + Box(Modifier.padding(top = T.buttonMargin)) { PickerButton(label, focused, primary, onClick = onClick) } +} + +@Composable +private fun ComingInSkeleton() { + Row(Modifier.fillMaxWidth().padding(horizontal = T.rowPaddingX, vertical = T.rowPaddingY), + verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(T.rowGap)) { + Box(Modifier.size(L.thumbWidth, L.thumbHeight).background(C.surface3, RoundedCornerShape(WolfskinTokens.Radius.thumb))) + Column(verticalArrangement = Arrangement.spacedBy(T.skeletonGap)) { + Box(Modifier.size(T.skeletonTitleWidth, T.skeletonTitleHeight).background(C.surface, RoundedCornerShape(WolfskinTokens.Shell.skeletonRadius))) + Box(Modifier.size(T.skeletonSubtitleWidth, T.skeletonSubtitleHeight).background(C.surface, RoundedCornerShape(WolfskinTokens.Radius.card))) + } + } +} + +/** Thumbnail slots do not resize when the text or the readiness block grows. */ +@OptIn(androidx.compose.ui.ExperimentalComposeUiApi::class, ExperimentalLayoutApi::class) +@Composable +fun ComingInRow(item: ComingInRequest, viewer: ShellPerson, focused: Boolean, expanded: Boolean, + showRatings: Boolean, onFocus: () -> Unit, onClick: () -> Unit) { + val foreground = if (focused) C.onFocus else C.fg + val secondary = if (focused) C.onFocus else C.muted + val context = LocalContext.current + val request = remember(item.poster, context) { + item.poster?.let { WolfskinImages.request(context, it, (L.thumbWidth.value * 2).toInt(), (L.thumbHeight.value * 2).toInt(), true) } + } + val posterReady = remember(request) { mutableStateOf(false) } + Row(Modifier.fillMaxWidth().focusScale(focused, WolfskinTokens.Focus.scaleRow) + .background(if (focused) C.fg else Color.Transparent, RoundedCornerShape(WolfskinTokens.Radius.panel)) + .pointerInput(item.id) { + awaitPointerEventScope { + while (true) if (awaitPointerEvent().type == PointerEventType.Enter) onFocus() + } + }.clickable(onClick = onClick) + .padding(horizontal = T.rowPaddingX, vertical = T.rowPaddingY).testTag("coming-row-${item.id}"), + verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(T.rowGap)) { + AsyncImage(model = request, imageLoader = WolfskinImages.loader(context), contentDescription = null, + modifier = Modifier.size(L.thumbWidth, L.thumbHeight).clip(RoundedCornerShape(WolfskinTokens.Radius.thumb)) + .background(if (posterReady.value) Color.Transparent else C.surface3), + onState = { posterReady.value = it is AsyncImagePainter.State.Success }, + contentScale = androidx.compose.ui.layout.ContentScale.Crop) + Column(Modifier.weight(1f)) { + Text(item.title, Modifier.comingInLineBox(T.titleLineHeight, T.titleBaseline), + style = ComingInTypography.listTitle, color = foreground, maxLines = 1, overflow = TextOverflow.Ellipsis) + Text("for ${item.recipient(viewer)} ยท by ${item.actor(viewer)}", Modifier.comingInLineBox(T.factsLineHeight, T.factsBaseline), + style = ComingInTypography.caption, color = secondary) + FlowRow(Modifier.padding(top = T.stageMargin).heightIn(min = T.stageLineHeight), horizontalArrangement = Arrangement.spacedBy(T.readinessGlyph)) { + Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(T.stageGap)) { + Glyph(item.stage.glyph, secondary, Modifier.size(T.stageGlyph)) + Text(item.stage.label, Modifier.comingInLineBox(T.stageLabelLineHeight, T.stageBaseline), style = ComingInTypography.label, color = secondary) + } + if (showRatings) ComingInRatings(item.ratings, foreground) + } + if (expanded) FlowRow(Modifier.padding(top = T.readinessMargin), + horizontalArrangement = Arrangement.spacedBy(T.readinessGapX), verticalArrangement = Arrangement.spacedBy(T.readinessGapY)) { + item.stage.readiness.forEachIndexed { index, word -> + Row { + val glyph = when (word) { "Done" -> "check"; "Failed" -> "alert"; "Not yet", "Unknown" -> null; else -> "clock" } + if (glyph != null) Glyph(glyph, secondary, Modifier.size(T.readinessGlyph).alignBy { it.measuredHeight }) + Text("${READINESS_NAMES[index]} ยท $word", Modifier.alignByBaseline(), style = ComingInTypography.readiness, color = secondary) + } + } + } + } + if (focused && !expanded) Glyph("right", foreground.copy(alpha = T.chevronAlpha), Modifier.size(T.chevron)) + } +} + +private val READINESS_NAMES = listOf("Request", "Download", "Library", "Playback") diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/ComingInState.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/ComingInState.kt new file mode 100644 index 00000000..1325cc0f --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/ComingInState.kt @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: GPL-2.0-only +package org.justinvisser.wolfskin.design + +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue + +import kotlinx.coroutines.delay +/** Household acquisition stages, ordered independently from their display wording. */ +enum class ComingInStage(val label: String, val rank: Int, val glyph: String, val readiness: List) { + Failed("Failed", 0, "alert", listOf("Done", "Failed", "Not yet", "Not yet")), + Downloading("Downloading", 1, "download", listOf("Done", "Downloading", "Not yet", "Not yet")), + AlmostReady("Almost ready", 1, "download", listOf("Done", "Done", "Being added", "Not yet")), + Checking("Checking", 2, "clock", listOf("Checking", "Unknown", "Not yet", "Not yet")), + Searching("Searching", 2, "clock", listOf("Done", "Searching", "Not yet", "Not yet")), + Waiting("Waiting", 3, "clock", listOf("Waiting", "Not yet", "Not yet", "Not yet")), + Ready("Ready", 4, "check", listOf("Done", "Done", "Done", "Not checked yet")), +} + +/** Ratings have already passed the supplier's observed-score and vote checks. */ +data class ComingInRating(val mark: String, val score: Double, val percentage: Boolean = false) + +/** Requests carry authenticated actor evidence, never the current viewer as a substitute. */ +data class ComingInRequest( + val id: String, + val mediaType: String, + val tmdbId: Long, + val title: String, + val requesterKey: String, + val requesterName: String, + val actorKey: String?, + val actorName: String?, + val stage: ComingInStage, + val poster: Any? = null, + val ratings: List = emptyList(), +) { + val ratingKey = "$mediaType:$tmdbId" + fun recipient(viewer: ShellPerson): String = if (requesterKey == viewer.key) "you" else requesterName + fun actor(viewer: ShellPerson): String = when { + actorKey == "shared" -> "Shared" + actorKey != null && actorKey == viewer.key -> "you" + else -> actorName ?: "Unknown" + } +} + +enum class ComingInStatus { Ready, Loading, Unavailable } + +/** The provider retains saved rows when refresh fails; an unavailable empty result is not empty success. */ +data class ComingInSnapshot( + val items: List = emptyList(), + val status: ComingInStatus = ComingInStatus.Unavailable, + val partial: Boolean = false, + val signedIn: Boolean = false, + val savedAt: String? = null, +) { + val ordered = items.sortedBy { it.stage.rank } + val openCount: Int get() = items.count { it.stage != ComingInStage.Ready } +} + +/** A bounded window and stable request id preserve focus across refreshes and title round trips. */ +class ComingInState { + var snapshot by mutableStateOf(ComingInSnapshot()) + private set + var focusedId by mutableStateOf(null) + private set + var expanded by mutableStateOf(false) + private set + var ratingsVisible by mutableStateOf(false) + private set + var recoveryFocused by mutableStateOf(false) + private set + private val cachedRatings = mutableSetOf() + val index: Int get() = snapshot.ordered.indexOfFirst { it.id == focusedId }.coerceAtLeast(0) + val focused: ComingInRequest? get() = snapshot.ordered.getOrNull(index) + val windowSize: Int get() = if (expanded) 4 else 5 + val windowStart: Int get() = (index - 2).coerceIn(0, (snapshot.ordered.size - windowSize).coerceAtLeast(0)) + + fun update(value: ComingInSnapshot) { + snapshot = if (value.status != ComingInStatus.Ready && value.signedIn && value.items.isEmpty() && snapshot.signedIn) { + snapshot.copy(status = value.status) + } else value + if (!snapshot.signedIn) cachedRatings.clear() + if (snapshot.ordered.none { it.id == focusedId }) focus(snapshot.ordered.firstOrNull()?.id) + ratingsVisible = snapshot.signedIn && focused?.ratingKey in cachedRatings + if (snapshot.status == ComingInStatus.Ready) recoveryFocused = false + } + + fun focus(id: String?) { + focusedId = id + recoveryFocused = false + expanded = false + ratingsVisible = snapshot.signedIn && focused?.ratingKey in cachedRatings + } + + /** Coroutine cancellation and the captured request id prevent stale focus reads from painting. */ + suspend fun awaitFocusedRatings() { + val item = focused ?: return + if (!snapshot.signedIn || snapshot.status != ComingInStatus.Ready || item.ratings.isEmpty() || ratingsVisible) return + delay(WolfskinTokens.Motion.ratingDwell.toLong()) + if (focusedId != item.id || !snapshot.signedIn || snapshot.status != ComingInStatus.Ready) return + cachedRatings.add(item.ratingKey) + ratingsVisible = true + } + + /** Return true only when a row requests a title; every direction remains trapped in the sheet. */ + fun key(key: ShellKey): Boolean { + if (recoveryFocused) { + if (key == ShellKey.Up) recoveryFocused = false + return false + } + when (key) { + ShellKey.Up -> focus(snapshot.ordered.getOrNull((index - 1).coerceAtLeast(0))?.id) + ShellKey.Down -> if (snapshot.status == ComingInStatus.Unavailable && index == snapshot.ordered.lastIndex) recoveryFocused = true + else focus(snapshot.ordered.getOrNull((index + 1).coerceAtMost(snapshot.ordered.lastIndex))?.id) + ShellKey.Right -> if (focused != null) expanded = true + ShellKey.Left -> expanded = false + ShellKey.Ok -> return focused != null + else -> Unit + } + return false + } +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/ComingInTypography.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/ComingInTypography.kt new file mode 100644 index 00000000..a8f3b3e0 --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/ComingInTypography.kt @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0-only +package org.justinvisser.wolfskin.design + +import androidx.compose.ui.text.style.LineHeightStyle +import androidx.compose.ui.text.font.FontWeight + +/** CSS line boxes retain their leading even on single lines; trimming changes sheet geometry. */ +internal object ComingInTypography { + private val lineBox = LineHeightStyle(LineHeightStyle.Alignment.Center, LineHeightStyle.Trim.None) + val title = WolfskinTokens.Type.sheetTitle.copy(lineHeightStyle = lineBox) + val listTitle = WolfskinTokens.Type.listTitle.copy(lineHeightStyle = lineBox) + val body = WolfskinTokens.Type.body.copy(lineHeightStyle = lineBox) + val label = WolfskinTokens.Type.label.copy(lineHeightStyle = lineBox) + val caption = WolfskinTokens.Type.caption.copy(lineHeightStyle = lineBox) + val stateTitle = WolfskinTokens.Type.stateTitle.copy(lineHeightStyle = lineBox, fontWeight = FontWeight.Bold) + val readiness = caption.copy(fontWeight = FontWeight.Bold) + val rating = WolfskinTokens.Type.label.copy(fontFeatureSettings = "tnum") +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/CssLineBox.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/CssLineBox.kt new file mode 100644 index 00000000..4f1d281a --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/CssLineBox.kt @@ -0,0 +1,68 @@ +package org.justinvisser.wolfskin.design + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.FirstBaseline +import androidx.compose.ui.layout.LastBaseline +import androidx.compose.ui.layout.Layout +import androidx.compose.ui.layout.LayoutModifier +import androidx.compose.ui.layout.Measurable +import androidx.compose.ui.layout.MeasureScope +import androidx.compose.ui.layout.ParentDataModifier +import androidx.compose.ui.unit.Constraints +import androidx.compose.ui.unit.Density +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.TextUnit +import kotlin.math.roundToInt + +internal data class CssLineBox(val lineHeight: TextUnit, val top: Dp, val bottom: Dp) : LayoutModifier, ParentDataModifier { + override fun Density.modifyParentData(parentData: Any?): Any = parentData ?: this@CssLineBox + fun Density.exactHeight(height: Int): Float { + val margins = top.toPx() + bottom.toPx() + return ((height - margins) / lineHeight.toPx()).roundToInt().coerceAtLeast(1) * lineHeight.toPx() + margins + } + override fun MeasureScope.measure(measurable: Measurable, constraints: Constraints) = with(measurable.measure(constraints.copy(minHeight = 0))) { + val line = lineHeight.toPx() + val lines = ((this[LastBaseline] - this[FirstBaseline]) / line).roundToInt().coerceAtLeast(0) + 1 + val textHeight = lines * line + val offset = top.toPx() + (textHeight - height) / 2f + layout(width, (textHeight + top.toPx() + bottom.toPx()).roundToInt()) { + placeRelative(0, offset.roundToInt()) + } + } +} + +private class CssColumnHeight : ParentDataModifier { + var pixels = 0f + override fun Density.modifyParentData(parentData: Any?): Any = parentData ?: this@CssColumnHeight +} + +/** Fractional line heights accumulate before rounding, rather than adding a rounded pixel per row. */ +@Composable +internal fun CssColumn(modifier: Modifier = Modifier, gap: Dp = WolfskinTokens.Shell.zero, content: @Composable () -> Unit) { + val exact = remember { CssColumnHeight() } + Layout(content, modifier.then(exact)) { children, constraints -> + val measured = Array(children.size) { children[it].measure(constraints.copy(minWidth = 0, minHeight = 0)) } + fun height(index: Int): Float = when (val data = children[index].parentData) { + is CssLineBox -> with(data) { exactHeight(measured[index].height) } + is CssColumnHeight -> data.pixels + else -> measured[index].height.toFloat() + } + val space = gap.toPx() + var total = 0f + var width = constraints.minWidth + for (index in measured.indices) { + total += height(index) + if (index == measured.lastIndex) 0f else space + width = maxOf(width, measured[index].width) + } + exact.pixels = total + layout(width.coerceIn(constraints.minWidth, constraints.maxWidth), total.roundToInt().coerceIn(constraints.minHeight, constraints.maxHeight)) { + var y = 0f + for (index in measured.indices) { + measured[index].placeRelative(0, y.roundToInt()) + y += height(index) + space + } + } + } +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/DiscoverArtwork.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/DiscoverArtwork.kt new file mode 100644 index 00000000..92e63ad9 --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/DiscoverArtwork.kt @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: GPL-2.0-only +package org.justinvisser.wolfskin.design + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.wrapContentSize +import androidx.compose.ui.Alignment +import androidx.compose.ui.draw.clipToBounds +import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.runtime.Composable +import androidx.compose.runtime.compositionLocalOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.blur +import androidx.compose.ui.draw.clip +import androidx.compose.ui.draw.dropShadow +import androidx.compose.ui.graphics.shadow.Shadow +import androidx.compose.ui.unit.DpOffset +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.draw.drawWithCache +import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.graphics.ColorMatrix +import androidx.compose.ui.graphics.ImageBitmap +import androidx.compose.ui.graphics.painter.BitmapPainter +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.testTag +import coil3.compose.AsyncImage +import org.justinvisser.wolfskin.design.WolfskinTokens.Color as C +import org.justinvisser.wolfskin.design.WolfskinTokens.Discover as D +import org.justinvisser.wolfskin.design.WolfskinTokens.Layout as L + +/** Native captures provide decoded local art; neither posters nor heroes perform image HTTP reads. */ +val LocalDiscoverArt = compositionLocalOf<((String) -> ImageBitmap?)?> { null } + +/** Decode requests use the actual art slot, with RGB565 only for upright posters. */ +@Composable +fun DiscoverArtwork(path: String?, modifier: Modifier, poster: Boolean = false, dim: Boolean = false, onError: () -> Unit = {}) { + if (path == null) return + val bitmap = LocalDiscoverArt.current?.invoke(path) + val painter = remember(bitmap) { bitmap?.let(::BitmapPainter) } + val filter = remember(dim) { if (dim) ColorFilter.colorMatrix(ColorMatrix().apply { + setToSaturation(D.ambientSaturation) + this *= ColorMatrix().apply { setToScale(D.ambientBrightness, D.ambientBrightness, D.ambientBrightness, 1f) } + }) else null } + val context = LocalContext.current + val request = remember(context, path, poster) { + WolfskinImages.request(context, path, if (poster) 256 else 1280, if (poster) 384 else 720, poster) + } + if (painter != null) Image(painter, null, modifier, contentScale = ContentScale.Crop, colorFilter = filter) + else AsyncImage( + model = request, + imageLoader = WolfskinImages.loader(context), + contentDescription = null, modifier = modifier, contentScale = ContentScale.Crop, colorFilter = filter, + onError = { onError() }, + ) +} + +/** Poster-only titles retain the one-sheet over a blurred wash rather than stretching the poster. */ +@Composable +fun DiscoverBackdrop(title: DiscoverTitle, detail: Boolean = false, modifier: Modifier = Modifier) { + val failed = remember(title.poster, title.backdrop) { androidx.compose.runtime.mutableStateOf(false) } + Box(modifier.size(WolfskinTokens.Shell.stageWidth, WolfskinTokens.Shell.stageHeight).clipToBounds().background(C.surface3)) { + if (failed.value || (title.poster == null && title.backdrop == null)) HomeAmbient(Modifier.fillMaxSize().testTag("discover-missing-art")) + else if (title.posterOnly) { + DiscoverArtwork(title.poster, Modifier.offset(-D.ambientInset, -D.ambientInset) + .wrapContentSize(Alignment.TopStart, unbounded = true) + .size(WolfskinTokens.Shell.stageWidth + D.ambientInset * 2, WolfskinTokens.Shell.stageHeight + D.ambientInset * 2) + .graphicsLayer { scaleX = D.ambientScale; scaleY = D.ambientScale }.blur(D.ambientBlur), dim = true, onError = { failed.value = true }) + DiscoverArtwork(title.poster, Modifier.offset( + WolfskinTokens.Shell.stageWidth - D.heroSheetRight - if (detail) L.heroSheetWidth else D.heroSheetWidth, + if (detail) L.navBand else D.heroSheetTop, + ).size(if (detail) L.heroSheetWidth else D.heroSheetWidth, if (detail) L.heroSheetHeight else D.heroSheetHeight) + .dropShadow(RoundedCornerShape(WolfskinTokens.Radius.heroSheet), Shadow( + radius = WolfskinTokens.Lift.heroBlur, color = Color.Black.copy(alpha = WolfskinTokens.Lift.heroOpacity), + offset = DpOffset(WolfskinTokens.Shell.zero, WolfskinTokens.Lift.heroY))) + .clip(RoundedCornerShape(WolfskinTokens.Radius.heroSheet)), poster = true, onError = { failed.value = true }) + } else DiscoverArtwork(title.backdrop ?: title.poster, Modifier.fillMaxSize(), onError = { failed.value = true }) + Box(Modifier.fillMaxSize().drawWithCache { + val scrim = Brush.horizontalGradient(0f to C.bg.copy(alpha = .92f), .42f to C.bg.copy(alpha = .55f), .70f to C.bg.copy(alpha = 0f), endX = size.width) + onDrawBehind { drawRect(scrim) } + }) + Box(Modifier.fillMaxSize().background(Brush.verticalGradient(0f to C.bg.copy(alpha = 0f), .52f to C.bg.copy(alpha = 0f), .74f to C.bg.copy(alpha = .6f), 1f to C.bg))) + } +} + +/** Missing art is deterministic and quiet; it does not imply a provider read succeeded. */ +fun discoverFallback(title: String): Brush { + val hue = title.fold(0) { hash, char -> (hash * 31 + char.code) % 360 }.toFloat() + return Brush.linearGradient(listOf(Color.hsl(hue, .22f, .22f), Color.hsl(hue, .26f, .10f))) +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/DiscoverCardProjection.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/DiscoverCardProjection.kt new file mode 100644 index 00000000..a638c6e6 --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/DiscoverCardProjection.kt @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0-only +package org.justinvisser.wolfskin.design + +/** Discover metadata projects into the same poster and grid contract as Libraries. */ +internal fun DiscoverTitle.libraryCard(state: DiscoverState): LibraryTitle { + val receipts = state.requests[key].orEmpty() + val held = state.shell.person.key in heldBy + val availability = when { + held -> "In your library" + receipts.isNotEmpty() -> { + val recipients = receipts.joinToString(", ") { request -> + if (request.requester == state.shell.person.key) "you" + else state.shell.people.firstOrNull { it.key == request.requester }?.name ?: request.requester.orEmpty() + } + "Requested for $recipients ยท ${receipts.first().stage}" + } + heldBy.isNotEmpty() -> "In ${heldBy.joinToString(" and ") { key -> state.shell.people.firstOrNull { it.key == key }?.name ?: key }}โ€™s library" + else -> "" + } + return LibraryTitle(id = key, title = title, type = type, year = year, + runtimeSeconds = runtimeSeconds?.toLong(), seasons = seasonCount, poster = poster, + ratings = ratings.map { LibraryRating(it.source, it.score, it.label) }, availability = availability, + badge = when { + held -> "held" + receipts.isEmpty() -> null + receipts.all { it.stage == "Failed" } -> "failed" + else -> "requested" + }) +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/DiscoverFixture.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/DiscoverFixture.kt new file mode 100644 index 00000000..0b8d52e7 --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/DiscoverFixture.kt @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-2.0-only +package org.justinvisser.wolfskin.design + +import org.json.JSONArray +import org.json.JSONObject + +/** Projects supplied prototype data; this class never loads a bundled fixture or contacts a server. */ +class DiscoverFixture(json: String, private val artPath: (String) -> String = { it }) { + private val profiles = JSONObject(json).getJSONArray("profiles").objects() + private val holdings = profiles.associate { profile -> + profile.getString("key") to listOf("movies", "shows", "anime").flatMap { profile.getJSONArray(it).objects() } + .map { identity(it) }.toSet() + } + private val pool = profiles.flatMap { it.getJSONArray("discover").objects() }.distinctBy(::identity).map(::title) + val services = listOf("Netflix", "Prime Video", "Disney+", "HBO Max", "Apple TV+", "Videoland", "Hulu", "NPO Start", "Crunchyroll") + .mapIndexed { index, name -> DiscoverService(index.toLong(), name, listOf(355f, 200f, 230f, 265f, 0f, 20f, 140f, 25f, 30f)[index]) } + + fun snapshot(person: String): DiscoverSnapshot { + val profile = profiles.first { it.getString("key") == person } + val picks = profile.getJSONArray("discover").objects().map(::title) + val played = listOf("movies", "shows", "anime").flatMap { profile.getJSONArray(it).objects() } + .filter { it.optBoolean("played") } + val groups = linkedMapOf>>() + picks.sortedBy { if (it.type == "movie") 0 else 1 }.forEach { pick -> + played.map { it to normalizedGenres(it.getJSONArray("genres").strings()).intersect(normalizedGenres(pick.genres)).size } + .filter { it.second > 0 }.sortedByDescending { it.second }.take(2).forEach { (seed, _) -> + groups.getOrPut(identity(seed)) { seed.getString("title") to mutableListOf() }.second.add(pick) + } + } + val lanes = services.mapIndexed { index, service -> + val source = rotate(pool, index * 7).sortedByDescending { it.year } + DiscoverLane("new-$index", "New on ${service.name}", source.take(12), fullTitles = source) + } + listOf(DiscoverLane("trending", "Trending", pool.take(20), pool.size, fullTitles = pool)) + + listOf("Comedy", "Animation", "Science Fiction", "Horror", "Romance").map { genre -> + val items = pool.filter { genre in normalizedGenres(it.genres) && (genre !in setOf("Science Fiction", "Horror", "Romance") || it.type == "movie") } + DiscoverLane("genre-$genre", genre, items.take(20), items.size, fullTitles = items) + } + return DiscoverSnapshot(picks, groups.values.map { DiscoverSeed(it.first, it.second.toList()) }, services, lanes, status = DiscoverStatus.Ready, reusesFixtureLanes = true) + } + + fun service(service: DiscoverService, type: String): List { + val base = rotate(pool.filter { it.type == type }, service.id.toInt() * 5) + val noun = if (type == "movie") "movies" else "series" + val genres = base.flatMap { it.genres }.groupingBy { it }.eachCount().entries.sortedByDescending { it.value }.take(3) + return listOf( + DiscoverLane("sv-pop", "Popular $noun", base.drop(1).take(20)), + DiscoverLane("sv-new", "New $noun", base.sortedByDescending { it.year }.take(20)), + DiscoverLane("sv-top", "Top rated $noun", rotate(base, 11).take(20)), + ) + genres.map { genre -> DiscoverLane("sv-g-${genre.key}", "${genre.key} $noun", base.filter { genre.key in it.genres }.take(20)) } + } + + fun find(name: String): DiscoverTitle = (pool + profiles.flatMap { p -> listOf("movies", "shows", "anime").flatMap { p.getJSONArray(it).objects() }.map(::title) }).first { it.title == name } + + private fun title(item: JSONObject): DiscoverTitle = DiscoverTitle( + tmdb = item.optLong("tmdbId", item.getString("id").hashCode().toLong().let { if (it < 0) -it else it }), + type = item.getString("type"), title = item.getString("title"), year = item.nullableInt("year"), + genres = item.getJSONArray("genres").strings(), overview = item.optString("overview"), + poster = item.nullableString("poster")?.let(artPath), backdrop = item.nullableString("backdrop")?.let(artPath), + posterOnly = item.optJSONObject("artwork")?.optString("backdropKind") == "poster_crop", + runtimeSeconds = item.nullableInt("runtimeSeconds"), seasonCount = item.nullableInt("seasonCount"), + ratings = ratings(item.optJSONObject("ratings")), heldBy = holdings.filterValues { identity(item) in it }.keys, + ) + + private fun ratings(json: JSONObject?): List = buildList { + if (json == null) return@buildList + for ((field, source, label) in listOf(Triple("rtCritics", "rtCritics", "rtCriticsLabel"), Triple("rtAudience", "rtAudience", "rtAudienceLabel"), Triple("imdb", "imdb", ""))) { + if (!json.isNull(field)) add(DiscoverRating(source, json.getDouble(field), json.nullableString(label))) + } + if (isEmpty() && !json.isNull("tmdb") && json.optInt("tmdbVotes") > 0) add(DiscoverRating("tmdb", json.getDouble("tmdb"))) + } + + private fun identity(json: JSONObject): String = "${json.getString("type")}:${json.optLong("tmdbId", json.getString("id").hashCode().toLong().let { if (it < 0) -it else it })}" + private fun rotate(items: List, offset: Int): List = if (items.isEmpty()) items else items.drop(offset % items.size) + items.take(offset % items.size) + private fun normalizedGenres(genres: List): Set = genres.flatMap { + when (it) { "Sci-Fi & Fantasy" -> listOf("Science Fiction", "Fantasy"); "Action & Adventure" -> listOf("Action", "Adventure"); "Sci-Fi" -> listOf("Science Fiction"); else -> listOf(it) } + }.toSet() +} + +private fun JSONArray.objects(): List = List(length()) { getJSONObject(it) } +private fun JSONArray.strings(): List = List(length()) { getString(it) } +private fun JSONObject.nullableString(key: String): String? = if (isNull(key)) null else optString(key).takeIf { it.isNotEmpty() } +private fun JSONObject.nullableInt(key: String): Int? = if (isNull(key)) null else getInt(key) diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/DiscoverLaneProjection.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/DiscoverLaneProjection.kt new file mode 100644 index 00000000..bda06cdc --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/DiscoverLaneProjection.kt @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: GPL-2.0-only +package org.justinvisser.wolfskin.design + +import kotlin.math.ceil + +/** Dropped seed groups must not suppress titles from the later catalogue lanes. */ +internal fun projectDiscoverLanes(snapshot: DiscoverSnapshot, heroes: List, filter: String, hidden: Map): List { + fun matches(item: DiscoverTitle) = filter == "all" || item.type == filter + val seen = heroes.mapTo(mutableSetOf()) { it.key } + val result = mutableListOf() + fun take(items: List, limit: Int) = items.filter { matches(it) && it.key !in hidden && it.key !in seen }.take(limit).filter { seen.add(it.key) } + if (snapshot.status == DiscoverStatus.Ready) { + val groups = snapshot.seeds.map { seed -> seed.copy(items = seed.items.filter { matches(it) && it.key !in hidden }) }.filter { it.items.isNotEmpty() }.take(3) + for ((type, name) in listOf("movie" to "Movies", "tv" to "Series")) { + val all = snapshot.picks.filter { it.type == type && matches(it) && it.key !in hidden } + val count = all.count { it.key !in seen } + val items = take(all, minOf(12, ceil(count.toDouble() / (groups.size + 1)).toInt())) + if (items.isNotEmpty()) result += DiscoverLane("pk-$type", "$name for you", items, all.size, pick = true, fullTitles = all) + } + val size = if (groups.isEmpty()) 0 else minOf(8, ceil(snapshot.picks.count { matches(it) && it.key !in seen && it.key !in hidden }.toDouble() / groups.size).toInt()) + groups.forEachIndexed { index, seed -> + val items = take(seed.items, size) + if (items.size >= 3) result += DiscoverLane("pk-w$index", "Because you watched ${seed.title}", items, seed.items.size, pick = true, fullTitles = seed.items) + } + } + val displayed = heroes.mapTo(mutableSetOf()) { it.key } + result.forEach { lane -> lane.titles.forEach { displayed.add(it.key) } } + if (snapshot.services.isNotEmpty()) result += DiscoverLane("svc", "Services", emptyList()) + snapshot.lanes.forEach { lane -> + val source = lane.fullTitles.filter { matches(it) && it.key !in displayed && it.key !in hidden } + val items = source.take(if (lane.id.startsWith("new-")) 12 else WolfskinTokens.Behaviour.rowLimit.toInt()) + if (items.isNotEmpty() || lane.tail == DiscoverTail.Retry || lane.tail == DiscoverTail.ShowMore) { + result += lane.copy(titles = items, fullTitles = source, total = if (lane.id.startsWith("new-")) items.size else source.size, + tail = if (lane.tail == DiscoverTail.Retry || lane.tail == DiscoverTail.ShowMore) lane.tail else if (!lane.id.startsWith("new-") && source.size > items.size) DiscoverTail.SeeAll else DiscoverTail.None) + if (!snapshot.reusesFixtureLanes) items.forEach { displayed.add(it.key) } + } + } + val hiddenItems = (snapshot.hidden + snapshot.picks).distinctBy { it.key }.filter { it.key in hidden && matches(it) } + if (hiddenItems.isNotEmpty()) result += DiscoverLane("hidden", "Hidden picks", hiddenItems, hidden = true) + return result +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/DiscoverModel.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/DiscoverModel.kt new file mode 100644 index 00000000..3fc3b296 --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/DiscoverModel.kt @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-2.0-only +package org.justinvisser.wolfskin.design + +/** Catalogue identity is stable across lanes, filters, requests and dismissals. */ +data class DiscoverTitle( + val tmdb: Long, + val type: String, + val title: String, + val year: Int? = null, + val genres: List = emptyList(), + val overview: String = "", + val poster: String? = null, + val backdrop: String? = null, + val posterOnly: Boolean = false, + val runtimeSeconds: Int? = null, + val seasonCount: Int? = null, + val seasons: List? = null, + val ratings: List = emptyList(), + val heldBy: Set = emptySet(), + val score: Double = 0.0, +) { + val key: String get() = "$type:$tmdb" + val typeWord: String get() = if (type == "movie") "Movie" else "Series" +} + +/** Observed source marks keep labels separate from score values. */ +data class DiscoverRating(val source: String, val score: Double, val label: String? = null) + +/** A contribution group preserves feed order rather than assigning a visible rank. */ +data class DiscoverSeed(val title: String, val items: List) + +/** Services carry their catalogue id and a text wordmark, never third-party logos. */ +data class DiscoverService(val id: Long, val name: String, val hue: Float) + +enum class DiscoverStatus { Ready, NeedsSignIn, Unavailable, Loading, NoSeeds, PicksUnavailable } +enum class DiscoverTail { None, SeeAll, Retry, ShowMore } + +/** Provider data is immutable; screen focus never mutates source ordering. */ +data class DiscoverSnapshot( + val picks: List = emptyList(), + val seeds: List = emptyList(), + val services: List = emptyList(), + val lanes: List = emptyList(), + val hidden: List = emptyList(), + val status: DiscoverStatus = DiscoverStatus.NeedsSignIn, + val savedAt: String? = null, + val reusesFixtureLanes: Boolean = false, +) + +/** Lane identity survives lazy recycling and provider refreshes. */ +data class DiscoverLane( + val id: String, + val title: String, + val titles: List, + val total: Int = titles.size, + val tail: DiscoverTail = if (total > titles.size) DiscoverTail.SeeAll else DiscoverTail.None, + val pick: Boolean = false, + val hidden: Boolean = false, + val fullTitles: List = titles, +) + +/** Caller identity is deliberately absent: the authenticated client supplies the actor. */ +data class DiscoverRequest(val title: DiscoverTitle, val requester: String, val profile: String, val fromRecommendation: Boolean = true) + +/** Request outcomes distinguish uncertainty from an acknowledged receipt. */ +data class DiscoverRequestResult( + val phase: RequestPhase, + val actor: String? = null, + val stage: String = "Waiting", + val requester: String? = null, +) + +enum class RequestPhase { Choose, LoadingRecipients, RecipientsUnavailable, Sending, Receipt, NotConfirmed, Pending, Refused } + +/** Production adapters use the generated Conductarr client; fixture adapters cannot send HTTP. */ +interface DiscoverOperations { + suspend fun request(intent: DiscoverRequest): DiscoverRequestResult + suspend fun check(intent: DiscoverRequest): DiscoverRequestResult + suspend fun hide(profile: String, title: DiscoverTitle): Boolean + suspend fun restore(profile: String, title: DiscoverTitle): Boolean + suspend fun refresh(): DiscoverSnapshot +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/DiscoverOverlay.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/DiscoverOverlay.kt new file mode 100644 index 00000000..caf98275 --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/DiscoverOverlay.kt @@ -0,0 +1,174 @@ +// SPDX-License-Identifier: GPL-2.0-only +package org.justinvisser.wolfskin.design + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.alpha +import androidx.compose.ui.draw.dropShadow +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.RectangleShape +import androidx.compose.ui.graphics.shadow.Shadow +import androidx.compose.ui.unit.DpOffset +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.layout.layout +import androidx.tv.material3.Text +import org.justinvisser.wolfskin.design.WolfskinTokens.Color as C +import org.justinvisser.wolfskin.design.WolfskinTokens.Discover as D +import org.justinvisser.wolfskin.design.WolfskinTokens.Layout as L + +/** Sheets draw after the shell nav: their scrim consumes pointers and focus stays inside. */ +@Composable +fun DiscoverOverlay(state: DiscoverState) { + val overlay = state.overlay + if (overlay != null && !state.shell.pickerVisible) { + Box(Modifier.fillMaxSize().background(C.sheetScrim).clickable(onClick = {}).testTag("discover-overlay")) { + Column(Modifier.align(Alignment.CenterEnd).width(L.sheetWidth).fillMaxSize() + .dropShadow(RectangleShape, Shadow(radius = WolfskinTokens.Lift.sheetBlur, + color = Color.Black.copy(alpha = WolfskinTokens.Lift.sheetOpacity), + offset = DpOffset(WolfskinTokens.Lift.sheetX, WolfskinTokens.Shell.zero))) + .background(C.surface).padding(D.sheetPaddingX, D.sheetPaddingY), verticalArrangement = Arrangement.spacedBy(D.sheetGap)) { + when (overlay) { + is DiscoverOverlayState.Request -> RequestSheet(state, overlay.state) + is DiscoverOverlayState.Hidden -> { + ReceiptPanel("Hidden from your picks", "${overlay.title.title} leaves every row of ${state.shell.person.name}โ€™s picks. It waits under Hidden picks at the end of Discover.") + Row(Modifier.padding(top = D.sheetButtonTop), horizontalArrangement = Arrangement.spacedBy(L.buttonGap)) { + DiscoverButton("Undo", overlay.focus == 0) { state.restore(overlay.title) } + DiscoverButton("Done", overlay.focus == 1, primary = false) { overlay.focus = 1; state.key(ShellKey.Ok) } + } + } + is DiscoverOverlayState.Restore -> { + Text(overlay.title.title, Modifier.discoverLineBox(DiscoverType.sheetTitle), color = C.fg, style = DiscoverType.sheetTitle) + Text("Hidden from ${state.shell.person.name}โ€™s picks.", + Modifier.offset(y = D.sheetSubTop).padding(bottom = D.sheetSubGap + D.sheetSubTop).discoverLineBox(DiscoverType.body), + color = C.muted, style = DiscoverType.body) + Row(Modifier.padding(top = D.sheetButtonTop), horizontalArrangement = Arrangement.spacedBy(L.buttonGap)) { + DiscoverButton("Show again", overlay.focus == 0) { state.restore(overlay.title) } + DiscoverButton("Back", overlay.focus == 1, primary = false) { state.overlay = null } + } + } + } + } + } + } + state.toast?.let { RecoveryToast(it) } +} + +@Composable +private fun RequestSheet(state: DiscoverState, sheet: RequestSheetState) { + Text(if (sheet.held) "Add for someone" else "Request", color = C.fg, style = DiscoverType.sheetTitle) + Text("${sheet.title.title} ยท ${sheet.title.typeWord}${sheet.title.year?.let { " ยท $it" }.orEmpty()}", + Modifier.offset(y = D.sheetSubTop).padding(bottom = D.sheetSubGap + D.sheetSubTop), color = C.muted, style = DiscoverType.body) + if (state.isSignedIn) DiscoverRatings(sheet.title.ratings, Modifier.layout { measurable, constraints -> + val placeable = measurable.measure(constraints) + layout(placeable.width, placeable.height + (D.sheetRatingTop + D.sheetRatingBottom).roundToPx()) { + placeable.placeRelative(0, D.sheetRatingTop.roundToPx()) + } + }) + when (sheet.phase) { + RequestPhase.Choose, RequestPhase.Sending -> RequestChoices(state, sheet) + RequestPhase.LoadingRecipients -> { + Text("For", Modifier.padding(top = D.sheetLabelTop), color = C.dim, style = DiscoverType.label) + repeat(3) { + Row(Modifier.fillMaxWidth().height(L.sheetRow).background(C.listRowRest, RoundedCornerShape(WolfskinTokens.Radius.listRow)).padding(horizontal = D.sheetRowPadding), + horizontalArrangement = Arrangement.spacedBy(D.sheetPersonGap), verticalAlignment = Alignment.CenterVertically) { + Box(Modifier.size(D.sheetAvatar).background(C.surface, CircleShape)) + Box(Modifier.width(D.skeletonNameWidth).height(D.skeletonNameHeight).background(C.surface, RoundedCornerShape(WolfskinTokens.Shell.skeletonRadius))) + } + } + Box(Modifier.padding(top = D.sheetButtonTop)) { + DiscoverButton("Close", true, primary = false) { state.overlay = null } + } + } + else -> RequestOutcome(state, sheet) + } +} + +@Composable +private fun RequestChoices(state: DiscoverState, sheet: RequestSheetState) { + Text("For", Modifier.padding(top = D.sheetLabelTop), color = C.dim, style = DiscoverType.label) + sheet.people.forEachIndexed { index, person -> + val focused = sheet.focus == index + val disabled = person.key in sheet.title.heldBy + Row(Modifier.fillMaxWidth().height(L.sheetRow).alpha(if (disabled) .5f else 1f) + .focusScale(focused, WolfskinTokens.Focus.scaleRow) + .background(if (focused) C.fg else C.listRowRest, RoundedCornerShape(WolfskinTokens.Radius.listRow)) + .clickable(enabled = !disabled && sheet.phase == RequestPhase.Choose) { sheet.selected = index; sheet.focus = sheet.buttonIndex } + .padding(horizontal = D.sheetRowPadding), horizontalArrangement = Arrangement.spacedBy(D.sheetPersonGap), verticalAlignment = Alignment.CenterVertically) { + Avatar(person, D.sheetAvatar, WolfskinTokens.Type.avatarLetterSheetRow) + Text(person.name + if (person.key == sheet.viewer.key) " (you)" else "", Modifier.weight(1f), color = if (focused) C.onFocus else C.fg, style = DiscoverType.listTitle) + if (disabled) Text("In library", color = (if (focused) C.onFocus else C.fg).copy(alpha = D.reasonOpacity), style = DiscoverType.reason) + else Box(Modifier.size(D.sheetRadio).background(if (sheet.selected == index) C.accent else C.listRowRest.copy(alpha = 0f), CircleShape) + .border(if (sheet.selected != index || focused) D.sheetRadioRing else WolfskinTokens.Shell.zero, if (focused) C.onFocus.copy(alpha = .5f) else C.fg.copy(alpha = .35f), CircleShape), contentAlignment = Alignment.Center) { + if (sheet.selected == index) Box(Modifier.size(D.sheetRadioDot).background(C.onFocus, CircleShape)) + } + } + } + if (sheet.blocked) Text("Season details are unknown right now, so this series canโ€™t be requested yet. Nothing was sent.", color = C.warn, style = DiscoverType.caption) + else if (sheet.title.type == "tv" && !sheet.held) Text("Whole series: every listed season. Other seasons may download too.", color = C.dim, style = DiscoverType.caption) + Box(Modifier.padding(top = D.sheetButtonTop)) { + DiscoverButton(if (sheet.blocked) "Close" else sheet.buttonLabel, sheet.focus == sheet.buttonIndex, glyph = if (sheet.blocked) null else "plus", primary = !sheet.blocked) { sheet.focus = sheet.buttonIndex; state.key(ShellKey.Ok) } + } +} + +@Composable +private fun RequestOutcome(state: DiscoverState, sheet: RequestSheetState) { + val phase = sheet.phase + val name = sheet.selectedPerson.name + val actor = sheet.result?.actor ?: state.shell.person.name + val text = when (phase) { + RequestPhase.Receipt -> "for ${if (sheet.selectedPerson.key == state.shell.person.key) "you" else name} ยท by $actor" + RequestPhase.NotConfirmed -> "The request service didnโ€™t answer. Nothing is assumed filed." + RequestPhase.Pending -> "Seerr hasnโ€™t confirmed it yet. Checking again looks first, so nothing is filed twice." + RequestPhase.Refused -> "$name canโ€™t receive requests from this TV." + else -> "Conductarr didnโ€™t say who this TV may request for. Nothing was sent." + } + val heading = when (phase) { + RequestPhase.Receipt -> if (sheet.held) "Adding to $nameโ€™s library" else "Requested" + RequestPhase.NotConfirmed -> "Not confirmed" + RequestPhase.Pending -> "Request unresolved" + RequestPhase.Refused -> "Refused" + else -> "Canโ€™t read who can receive requests" + } + ReceiptPanel(heading, text, if (phase == RequestPhase.Receipt) C.fg else if (phase == RequestPhase.Refused) C.fail else C.warn, + if (phase == RequestPhase.Receipt) sheet.result?.stage ?: "Waiting" else null) + if (phase == RequestPhase.Receipt) Text("Follow it under Requests in Settings.", color = C.dim, style = DiscoverType.caption) + Row(Modifier.padding(top = D.sheetButtonTop), horizontalArrangement = Arrangement.spacedBy(L.buttonGap)) { + if (phase in setOf(RequestPhase.NotConfirmed, RequestPhase.Pending, RequestPhase.RecipientsUnavailable)) { + DiscoverButton(if (phase == RequestPhase.RecipientsUnavailable) "Try again" else "Check again", sheet.focus == sheet.buttonIndex) { sheet.focus = sheet.buttonIndex; state.key(ShellKey.Ok) } + DiscoverButton("Close", sheet.focus != sheet.buttonIndex, primary = false) { state.overlay = null } + } else DiscoverButton(if (phase == RequestPhase.Receipt) "Done" else "Close", true) { state.overlay = null } + } +} + +@Composable +private fun ReceiptPanel(title: String, text: String, color: androidx.compose.ui.graphics.Color = C.fg, stage: String? = null) { + Column(Modifier.fillMaxWidth().background(C.listRowRest, RoundedCornerShape(WolfskinTokens.Radius.panel)).padding(WolfskinTokens.Shell.panelPaddingX, WolfskinTokens.Shell.panelPaddingY), verticalArrangement = Arrangement.spacedBy(WolfskinTokens.Shell.panelGap)) { + Row(horizontalArrangement = Arrangement.spacedBy(L.badgeInset), verticalAlignment = Alignment.CenterVertically) { + Glyph(if (title == "Requested" || title == "Hidden from your picks" || title.startsWith("Adding")) "check" else if (title == "Request unresolved") "clock" else "alert", color, Modifier.size(WolfskinTokens.Shell.panelIcon)) + Text(title, color = color, style = DiscoverType.stateTitle) + } + Text(text, color = C.muted, style = DiscoverType.body) + if (stage != null) Row(horizontalArrangement = Arrangement.spacedBy(D.stageGap), verticalAlignment = Alignment.CenterVertically) { + val stageColor = when (stage) { "Ready" -> C.ok; "Failed" -> C.fail; "Downloading", "Almost" -> C.accent; else -> C.muted } + Glyph("clock", stageColor, Modifier.size(L.buttonIcon)) + Text(stage, color = stageColor, style = DiscoverType.label) + } + } +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/DiscoverRatings.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/DiscoverRatings.kt new file mode 100644 index 00000000..62a55b57 --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/DiscoverRatings.kt @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0-only +package org.justinvisser.wolfskin.design + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.width +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.Alignment +import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.graphics.ColorMatrix +import androidx.compose.ui.platform.LocalConfiguration +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.res.painterResource +import androidx.tv.material3.Text +import java.util.Locale +import org.justinvisser.wolfskin.design.WolfskinTokens.Color as C + +/** Localized score formatting never infers a tomato label from its percentage. */ +fun formatDiscoverRating(rating: DiscoverRating, locale: Locale): String = + if (rating.source.startsWith("rt")) "${rating.score.toInt()}%" else String.format(locale, "%.1f", rating.score) + +/** Heroes, title destinations and sheets show every observed score without a dwell or truncation. */ +@Composable +fun DiscoverRatings(ratings: List, modifier: Modifier = Modifier) { + if (ratings.isEmpty()) return + val locale = LocalConfiguration.current.locales[0] + val labels = remember(ratings, locale) { ratings.map { formatDiscoverRating(it, locale) } } + val style = DiscoverType.ratings + val markSize = with(LocalDensity.current) { style.fontSize.toDp() } + val desaturated = remember { ColorFilter.colorMatrix(ColorMatrix().apply { setToSaturation(0f) }) } + Row(modifier, horizontalArrangement = Arrangement.spacedBy(markSize * .7142857f), verticalAlignment = Alignment.CenterVertically) { + ratings.forEachIndexed { index, rating -> + val resource = when (rating.source) { + "rtCritics" -> if (rating.label == "Rotten") R.drawable.ic_rotten_tomatoes_rotten else R.drawable.ic_rotten_tomatoes_fresh + "rtAudience" -> if (rating.label == "Spilled") R.drawable.ic_rt_spilled else R.drawable.ic_rt_upright + "imdb" -> R.drawable.ic_rating_imdb + else -> R.drawable.ic_rating_tmdb + } + val muted = rating.source == "rtCritics" && rating.label != "Rotten" && rating.label != "Fresh" && rating.label != "Certified Fresh" + val wordmark = rating.source == "imdb" || rating.source == "tmdb" + Row(horizontalArrangement = Arrangement.spacedBy(markSize * .2857143f), verticalAlignment = Alignment.CenterVertically) { + Image(painterResource(resource), null, Modifier.height(markSize).width(markSize * if (wordmark) 1.8f else 1f), + alpha = if (muted) .55f else 1f, colorFilter = if (muted) desaturated else null) + Text(labels[index], color = C.fg, style = style, maxLines = 1) + } + } + } +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/DiscoverScreen.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/DiscoverScreen.kt new file mode 100644 index 00000000..548e04d6 --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/DiscoverScreen.kt @@ -0,0 +1,195 @@ +// SPDX-License-Identifier: GPL-2.0-only +package org.justinvisser.wolfskin.design + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.runtime.DisposableEffect +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.text.style.TextOverflow +import androidx.tv.material3.Text +import org.justinvisser.wolfskin.design.WolfskinTokens.Color as C +import org.justinvisser.wolfskin.design.WolfskinTokens.Discover as D +import org.justinvisser.wolfskin.design.WolfskinTokens.Layout as L + +/** Discover uses the shell's real scroller, Back ladder and per-person focus memory. */ +@Composable +fun DiscoverScreen(state: DiscoverState, modifier: Modifier = Modifier) { + val shell = state.shell + val focus = remember(state) { object : ShellContentFocus by state {} } + DisposableEffect(focus) { + shell.contentFocus = focus + onDispose { if (shell.contentFocus === focus) { shell.contentFocus = null; shell.contentOverlayVisible = false } } + } + LaunchedEffect(shell.route, state.snapshot.savedAt) { shell.view.savedAt = state.snapshot.savedAt } + LaunchedEffect(state.toast) { if (state.toast != null) { kotlinx.coroutines.delay(WolfskinTokens.Motion.toast.toLong()); state.toast = null } } + val focusedTitle = if (state.collection != null) null else state.focusedLane?.titles?.getOrNull(state.column) + LaunchedEffect(focusedTitle?.key, state.contentFocused, state.snapshot.savedAt) { + state.plateKey = null + if (state.contentFocused && focusedTitle != null && (state.snapshot.savedAt == null || focusedTitle.key in state.observedRatings)) { + if (focusedTitle.key !in state.observedRatings) kotlinx.coroutines.delay(WolfskinTokens.Motion.ratingDwell.toLong()) + state.observedRatings.add(focusedTitle.key); state.plateKey = focusedTitle.key + } + } + if (state.title != null) { DiscoverTitleDestination(state, modifier); return } + state.collection?.let { + LibraryScreen(shell, it, modifier, ratingsSignedIn = state.isSignedIn, offlineArt = LocalDiscoverArt.current, registerFocus = false) + return + } + if (state.snapshot.status == DiscoverStatus.Loading) { + val loading = remember(state) { LibraryGridState("Discover", emptyList(), catalogue = true).apply { status = LibraryStatus.Loading } } + LibraryScreen(shell, loading, modifier, offlineArt = LocalDiscoverArt.current, registerFocus = false) + return + } + val density = LocalDensity.current + val list = shell.view.listState + val note = state.snapshot.status in setOf(DiscoverStatus.NoSeeds, DiscoverStatus.PicksUnavailable) + val heights = remember(state.hasHero, state.lanes, note, state.hasCatalogue) { + buildList { + add(if (state.hasHero) L.row_phero else L.row_lhead) + add(if (state.hasCatalogue) L.row_chips else WolfskinTokens.Shell.zero) + if (!state.hasCatalogue) add(L.row_state) else { + if (note) add(L.row_note) + state.lanes.forEach { lane -> add(L.rowHeadingBand + (if (lane.id == "svc") WolfskinTokens.Card.entryH else WolfskinTokens.Card.posterH + WolfskinTokens.Card.posterCaptionBand) + L.rowGapAfter) } + } + } + } + LaunchedEffect(state.focusedRow, shell.navFocused, heights) { + if (!shell.navFocused) { + val row = state.focusedRow + val physical = row + if (row >= state.firstShelf && note) 1 else 0 + var top = WolfskinTokens.Shell.zero + for (index in 0 until physical.coerceAtMost(heights.size)) top += heights[index] + val fits = top < D.anchorFitTop && top + heights[physical.coerceAtMost(heights.lastIndex)] <= WolfskinTokens.Shell.stageHeight - D.anchorBottomClearance + val target = if (row <= 1 || fits) 0f else with(density) { (top - L.pinnedLine).toPx() } + var current = WolfskinTokens.Shell.zero + for (index in 0 until list.firstVisibleItemIndex.coerceAtMost(heights.size)) current += heights[index] + animateFrameScroll(list, target - with(density) { current.toPx() } - list.firstVisibleItemScrollOffset) + } + } + Box(modifier.fillMaxSize().testTag("discover-screen")) { + if (state.hasHero && state.service == null && list.firstVisibleItemIndex == 0) state.hero?.let { DiscoverBackdrop(it, modifier = Modifier.graphicsLayer { translationY = -list.firstVisibleItemScrollOffset.toFloat() }) } + LazyColumn(state = list, contentPadding = PaddingValues(bottom = (WolfskinTokens.Shell.stageHeight - L.pinnedLine - heights.last()).coerceAtLeast(D.frameBottomMin)), modifier = Modifier.fillMaxSize()) { + item(key = "discover-header", contentType = if (state.hasHero && state.service == null) "hero" else "header") { + if (state.hasHero && state.service == null) DiscoverHero(state) else LibraryHeader(state.shell.person, state.service?.name ?: "Discover", if (state.service != null) "General interest" else "") + } + item(key = "discover-chips", contentType = "chips") { + if (state.snapshot.status !in setOf(DiscoverStatus.NeedsSignIn, DiscoverStatus.Unavailable, DiscoverStatus.Loading)) DiscoverChips(state) + } + if (state.snapshot.status in setOf(DiscoverStatus.NeedsSignIn, DiscoverStatus.Unavailable)) item(key = "discover-state", contentType = "state") { DiscoverStatePanel(state) } + else { + if (state.snapshot.status in setOf(DiscoverStatus.NoSeeds, DiscoverStatus.PicksUnavailable)) item(key = "discover-note", contentType = "note") { + Box(Modifier.height(L.row_note).fillMaxWidth()) { + Row(Modifier.offset(L.safeSide, D.noteTop), horizontalArrangement = Arrangement.spacedBy(D.noteGap), verticalAlignment = Alignment.CenterVertically) { + val color = if (state.snapshot.status == DiscoverStatus.NoSeeds) C.muted else C.warn + Glyph(if (state.snapshot.status == DiscoverStatus.NoSeeds) "eye" else "alert", color, Modifier.size(D.noteIcon)) + Text(if (state.snapshot.status == DiscoverStatus.NoSeeds) "Watch something to get picks for ${shell.person.name}." else "Picks unavailable right now.", color = color, style = DiscoverType.body) + } + } + } + itemsIndexed(state.lanes, key = { _, lane -> lane.id }, contentType = { _, _ -> "shelf" }) { index, lane -> DiscoverShelf(state, lane, index + state.firstShelf) } + } + } + } +} + +@Composable +private fun DiscoverHero(state: DiscoverState) { + val title = state.hero ?: return + Column(Modifier.fillMaxWidth().height(L.row_phero).padding(start = L.safeSide, bottom = L.heroCopyBottom), verticalArrangement = Arrangement.Bottom) { + Row(horizontalArrangement = Arrangement.spacedBy(WolfskinTokens.Card.posterGap), verticalAlignment = Alignment.CenterVertically) { + Glyph("seerr", C.accentText, Modifier.size(L.buttonIcon)) + Text(if (state.snapshot.status == DiscoverStatus.Ready) "For you" else "Trending", color = C.accentText, style = DiscoverType.label) + } + Spacer(Modifier.height(D.heroKickerGap)) + Text(title.title, Modifier.width(L.heroCopyWidth).testTag("discover-hero-title-box").discoverLineBox(DiscoverType.hero), color = C.fg, style = DiscoverType.hero, maxLines = 2, overflow = TextOverflow.Ellipsis) + Spacer(Modifier.height(D.heroTitleGap)) + Row(Modifier.height(D.heroFactsHeight), horizontalArrangement = Arrangement.spacedBy(D.heroFactsGap), verticalAlignment = Alignment.CenterVertically) { + Text("${title.typeWord}${title.year?.let { " ยท $it" }.orEmpty()}", color = C.muted, style = DiscoverType.body) + if (title.genres.isNotEmpty()) Text(title.genres.take(2).joinToString(", "), color = C.muted, style = DiscoverType.body) + if (state.isSignedIn) DiscoverRatings(title.ratings) + if (state.shell.person.key in title.heldBy) Text("In your library", color = C.accentText, style = DiscoverType.body) + } + Spacer(Modifier.height(D.heroMetaGap)) + Text(title.overview, Modifier.width(L.heroOverviewMax), color = C.muted, style = DiscoverType.body, maxLines = 2, overflow = TextOverflow.Ellipsis) + Spacer(Modifier.height(D.heroOverviewGap)) + Row(verticalAlignment = Alignment.CenterVertically) { + DiscoverButton("Details", state.contentFocused && state.focusedRow == 0, "about") { state.openTitle(title) } + Row(Modifier.padding(start = D.dotMargin), horizontalArrangement = Arrangement.spacedBy(D.dotGap), verticalAlignment = Alignment.CenterVertically) { + Glyph("left", C.fg.copy(alpha = if (state.contentFocused && state.focusedRow == 0) 1f else 0f), Modifier.size(D.dotChevron)) + state.heroes.forEachIndexed { index, _ -> Box(Modifier.size(if (index == state.slide) D.dotActive else D.dotSize, D.dotSize).background(if (index == state.slide) C.fg else C.fg.copy(alpha = .3f), CircleShape)) } + Glyph("right", C.fg.copy(alpha = if (state.contentFocused && state.focusedRow == 0) 1f else 0f), Modifier.size(D.dotChevron)) + } + } + } +} + +@Composable +private fun DiscoverChips(state: DiscoverState) { + Row(Modifier.fillMaxWidth().height(L.row_chips).padding(start = L.safeSide, top = D.chipTop), horizontalArrangement = Arrangement.spacedBy(D.chipGap)) { + (if (state.service == null) listOf("all" to "All", "movie" to "Movies", "tv" to "Series") else listOf("movie" to "Movies", "tv" to "Series")).forEachIndexed { index, (value, label) -> + val focused = state.contentFocused && state.focusedRow == 1 && state.column == index + Box(Modifier.height(D.chipHeight).focusScale(focused, WolfskinTokens.Focus.scaleControl) + .background(if (focused) C.fg else if (state.filter == value) C.accentSoft else C.chipRest, RoundedCornerShape(WolfskinTokens.Radius.chip)) + .border(if (!focused && state.filter == value) WolfskinTokens.Focus.ringCardRing / 2 else WolfskinTokens.Shell.zero, if (!focused && state.filter == value) C.accent else C.chipRest.copy(alpha = 0f), RoundedCornerShape(WolfskinTokens.Radius.chip)) + .clickable { state.focus(1, index); state.key(ShellKey.Ok) }.padding(horizontal = D.chipPadding), contentAlignment = Alignment.Center) { + Text(label, color = if (focused) C.onFocus else if (state.filter == value) C.accentText else C.fg, style = DiscoverType.label) + } + } + } +} + +@Composable +private fun DiscoverStatePanel(state: DiscoverState) { + val signIn = state.snapshot.status == DiscoverStatus.NeedsSignIn + Box(Modifier.fillMaxWidth().height(L.row_state)) { + Column(Modifier.padding(start = L.safeSide, top = D.stateTop).wrapContentHeight(Alignment.Top, unbounded = true).width(L.stateWidth) + .background(C.surface, RoundedCornerShape(WolfskinTokens.Radius.panel)) + .border(WolfskinTokens.Library.borderWidth, C.border, RoundedCornerShape(WolfskinTokens.Radius.panel)) + .padding(WolfskinTokens.Library.borderWidth).padding(D.statePaddingX, D.statePaddingY)) { + Row(horizontalArrangement = Arrangement.spacedBy(L.badgeInset), verticalAlignment = Alignment.CenterVertically) { + Glyph(if (signIn) "profile" else "alert", if (signIn) C.accentText else C.warn, Modifier.size(L.buttonIcon)) + Text(if (signIn) "Discover needs sign-in" else "Discover is resting", color = C.fg, style = DiscoverType.stateTitle) + } + Text(if (signIn) "Sign this TV in to Conductarr to see picks and request titles. Your library plays as usual." else "Conductarr canโ€™t be reached. Your library still plays.", Modifier.padding(top = L.navBlobAvatarPad, bottom = D.stateTextGap), color = C.muted, style = DiscoverType.body) + DiscoverButton("Try again", state.contentFocused, primary = signIn) { state.refresh() } + } + } +} + +/** Hero and sheet buttons reuse the shell's scale and outside-ring primitives. */ +@Composable +fun DiscoverButton(label: String, focused: Boolean, glyph: String? = null, primary: Boolean = true, onClick: () -> Unit) { + Row(Modifier.height(L.buttonHeight).focusScale(focused, WolfskinTokens.Focus.scaleControl) + .focusRing(focused, WolfskinTokens.Radius.button, WolfskinTokens.Focus.ringButtonGap, WolfskinTokens.Focus.ringButtonRing, C.accent, FocusLift.Button) + .background(if (primary) C.fg else if (focused) C.buttonSecondaryFocused else C.buttonSecondary, RoundedCornerShape(WolfskinTokens.Radius.button)) + .clickable(onClick = onClick).padding(horizontal = L.buttonPaddingX), horizontalArrangement = Arrangement.spacedBy(L.badgeInset), verticalAlignment = Alignment.CenterVertically) { + if (glyph != null) Glyph(glyph, if (primary) C.onFocus else C.fg, Modifier.size(L.buttonIcon)) + Text(label, color = if (primary) C.onFocus else C.fg, style = DiscoverType.button, maxLines = 1) + } +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/DiscoverShelf.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/DiscoverShelf.kt new file mode 100644 index 00000000..8883d432 --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/DiscoverShelf.kt @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: GPL-2.0-only +package org.justinvisser.wolfskin.design + +import androidx.compose.animation.core.tween +import androidx.compose.animation.core.CubicBezierEasing +import androidx.compose.foundation.gestures.animateScrollBy +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.zIndex +import androidx.tv.material3.Text +import org.justinvisser.wolfskin.design.WolfskinTokens.Card as K +import org.justinvisser.wolfskin.design.WolfskinTokens.Color as C +import org.justinvisser.wolfskin.design.WolfskinTokens.Discover as D +import org.justinvisser.wolfskin.design.WolfskinTokens.Layout as L + +/** Every shelf is lazy and keyed; the focused caption is outside the scaled art slot. */ +@Composable +fun DiscoverShelf(state: DiscoverState, lane: DiscoverLane, row: Int) { + val services = lane.id == "svc" + val height = if (services) K.entryH else K.posterH + val cards = rememberLazyListState() + val count = if (services) state.snapshot.services.size else lane.titles.size + if (lane.tail == DiscoverTail.None) 0 else 1 + val column = (state.shell.view.cards[lane.id] ?: 0).coerceIn(0, (count - 1).coerceAtLeast(0)) + val active = state.contentFocused && state.focusedRow == row + val slots = ((L.contentWidth + K.posterGap) / K.posterPitch).toInt() + val first = state.shell.view.cards["first:${lane.id}"] ?: 0 + var initialized by remember { mutableStateOf(false) } + LaunchedEffect(column, count) { + var target = first + if (column > target + slots - 2) target = column - (slots - 2) + if (column < target + 1) target = (column - 1).coerceAtLeast(0) + target = target.coerceIn(0, (count - slots).coerceAtLeast(0)) + state.shell.view.cards["first:${lane.id}"] = target + val offset = cards.layoutInfo.visibleItemsInfo.firstOrNull { it.index == target }?.offset + if (initialized && offset != null) { + if (offset != 0) cards.animateScrollBy(offset.toFloat(), tween(WolfskinTokens.Motion.base, easing = CubicBezierEasing(.25f, .1f, .25f, 1f))) + } else cards.scrollToItem(target) + initialized = true + } + Box(Modifier.fillMaxWidth().height(L.rowHeadingBand + height + (if (services) WolfskinTokens.Shell.zero else K.posterCaptionBand) + L.rowGapAfter).testTag("discover-lane-${lane.id}")) { + Text(lane.title, Modifier.offset(L.safeSide), color = C.fg, style = DiscoverType.rowHeading, maxLines = 1) + LazyRow(state = cards, userScrollEnabled = false, + contentPadding = PaddingValues(start = L.safeSide, end = WolfskinTokens.Shell.stageWidth - L.safeSide - (K.posterW * slots + K.posterGap * (slots - 1)), top = K.posterGap, bottom = K.posterGap), + horizontalArrangement = Arrangement.spacedBy(K.posterGap), + modifier = Modifier.offset(y = L.rowHeadingBand - K.posterGap).height(height + K.posterGap * 2)) { + if (services) itemsIndexed(state.snapshot.services, key = { _, service -> "service:${service.id}" }, contentType = { _, _ -> "entry" }) { index, service -> + Box(Modifier.size(K.entryW, K.entryH).focusScale(active && index == column, WolfskinTokens.Focus.scaleCard) + .focusRing(active && index == column, WolfskinTokens.Radius.card, WolfskinTokens.Focus.ringCardGap, WolfskinTokens.Focus.ringCardRing, C.accent, FocusLift.Card) + .background(Brush.linearGradient(listOf(Color.hsl(service.hue, .30f, .26f), Color.hsl(service.hue, .30f, .12f))), RoundedCornerShape(WolfskinTokens.Radius.card)) + .border(WolfskinTokens.Library.borderWidth, C.border.copy(alpha = D.entryBorderOpacity), RoundedCornerShape(WolfskinTokens.Radius.card)) + .clickable { state.focus(row, index); state.openService(service) }, contentAlignment = Alignment.BottomStart) { + Text(service.name, Modifier.padding(start = D.entryPaddingX, bottom = D.entryPaddingY), style = DiscoverType.entry, color = C.fg) + } + } else { + itemsIndexed(lane.titles, key = { _, item -> item.key }, contentType = { _, _ -> "poster" }) { index, item -> + DiscoverPoster(state, item, active && index == column, Modifier.clickable { + state.focus(row, index) + if (lane.hidden) state.overlay = DiscoverOverlayState.Restore(item) else state.openTitle(item) + }) + } + if (lane.tail != DiscoverTail.None) item(key = "tail:${lane.id}", contentType = if (lane.tail == DiscoverTail.SeeAll) "seeAll" else "tail") { + DiscoverTailCard(lane, active && column == lane.titles.size) { state.focus(row, lane.titles.size); state.key(ShellKey.Ok) } + } + } + } + if (!services && active) { + val item = lane.titles.getOrNull(column) + Caption( + item?.title ?: if (lane.tail == DiscoverTail.SeeAll) "See all ${lane.title}" else if (lane.tail == DiscoverTail.Retry) "Try again" else "Show more", + if (item != null) buildDiscoverCaptionFacts(item, state, lane.hidden) else if (lane.tail == DiscoverTail.SeeAll) "${lane.total} titles" else if (lane.tail == DiscoverTail.Retry) "${lane.title} stopped loading" else "The last read only repeated titles", + true, Modifier.offset(L.safeSide + K.posterPitch * (column - first), L.rowHeadingBand + K.posterH + L.captionOffset).width(WolfskinTokens.Library.captionWidth), + accentFirstFact = lane.hidden, + accentLastFact = item != null && (item.heldBy.isNotEmpty() || state.requests[item.key].orEmpty().isNotEmpty()), + ) + } + } +} + +/** Only the focused poster reads the ratings plate; cached observations paint immediately. */ +@Composable +fun DiscoverPoster(state: DiscoverState, title: DiscoverTitle, focused: Boolean, modifier: Modifier = Modifier) { + val receipts = state.requests[title.key] + val card = remember(title, receipts, state.shell.person.key) { title.libraryCard(state) } + LibraryPoster(card, focused, focused && state.plateKey == title.key && state.isSignedIn, true, + modifier.zIndex(if (focused) 1f else 0f), offlineArt = LocalDiscoverArt.current) +} + +@Composable +internal fun DiscoverTailCard(lane: DiscoverLane, focused: Boolean, onClick: () -> Unit) { + if (lane.tail == DiscoverTail.SeeAll) LibrarySeeAllCard(lane.total, focused, onClick) + else CatalogueRecoveryCard(lane.tail == DiscoverTail.Retry, focused, onClick) +} + +internal fun buildDiscoverCaptionFacts(title: DiscoverTitle, state: DiscoverState, hidden: Boolean): String { + val card = title.libraryCard(state) + return (if (hidden) "Hidden from your picks ยท " else "") + card.facts(true) +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/DiscoverState.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/DiscoverState.kt new file mode 100644 index 00000000..b157e831 --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/DiscoverState.kt @@ -0,0 +1,358 @@ +// SPDX-License-Identifier: GPL-2.0-only +package org.justinvisser.wolfskin.design + +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateMapOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock + +/** One person owns a Discover view; the shell retains its root list and card memory. */ +class DiscoverState( + val shell: ShellState, + initial: DiscoverSnapshot, + private val operations: DiscoverOperations, + private val scope: CoroutineScope, + private val onPush: (String) -> Unit = {}, + private val onPop: () -> Unit = {}, + private val serviceLanes: (DiscoverService, String) -> List = { _, _ -> emptyList() }, + private val nowMillis: () -> Long = System::currentTimeMillis, +) : ShellContentFocus { + var snapshot by mutableStateOf(initial) + private set + private var savedTime = initial.savedAt ?: formatSavedTime() + private var serviceFilter by mutableStateOf("movie") + var filter: String + get() = if (service != null) serviceFilter else DISCOVER_FILTERS[shell.rememberedView("discover").cards["filter"] ?: 0] + set(value) { + if (service != null) serviceFilter = value + else shell.rememberedView("discover").cards["filter"] = DISCOVER_FILTERS.indexOf(value) + } + var slide: Int + get() = (shell.rememberedView("discover").cards["slide"] ?: 0).coerceIn(0, (heroes.size - 1).coerceAtLeast(0)) + set(value) { shell.rememberedView("discover").cards["slide"] = value } + var title by mutableStateOf(null) + var service by mutableStateOf(null) + var collection by mutableStateOf(null) + var titleButton by mutableStateOf(0) + private var activeOverlay by mutableStateOf(null) + var overlay: DiscoverOverlayState? + get() = activeOverlay + set(value) { activeOverlay = value; shell.contentOverlayVisible = value != null } + var toast by mutableStateOf(null) + val observedRatings = mutableSetOf() + var plateKey by mutableStateOf(null) + val requests = mutableStateMapOf>() + private val requestSheets = mutableMapOf, RequestSheetState>() + private val hidden = mutableStateMapOf().apply { initial.hidden.forEach { put(it.key, it) } } + private lateinit var collectionCards: LinkedHashMap + private var revision by mutableStateOf(0) + private var cachedRevision = -1 + private var cachedFilter = "" + private var cachedService: DiscoverService? = null + private var cachedLanes = emptyList() + private var cachedHeroesRevision = -1 + private var cachedHeroesFilter = "" + private var cachedHeroes = emptyList() + private val dismissalMutex = Mutex() + private val dismissalVersions = mutableMapOf() + private var rootFilter = "all" + + override val hasContent: Boolean get() = snapshot.status != DiscoverStatus.Loading + val isSignedIn: Boolean get() = snapshot.status != DiscoverStatus.NeedsSignIn + val hasCatalogue: Boolean get() = when (snapshot.status) { + DiscoverStatus.Ready, DiscoverStatus.NoSeeds, DiscoverStatus.PicksUnavailable -> true + else -> false + } + val canRequest: Boolean get() = hasCatalogue && snapshot.savedAt == null + val hasHero: Boolean get() = service == null && collection == null && heroes.isNotEmpty() && hasCatalogue + val heroes: List get() { + if (cachedHeroesRevision != revision || cachedHeroesFilter != filter) { + val source = if (snapshot.status == DiscoverStatus.Ready) snapshot.picks else snapshot.lanes.firstOrNull { it.id == "trending" }?.titles.orEmpty() + cachedHeroes = source.asSequence().filter { it.key !in hidden && matches(it) } + .sortedWith(compareByDescending { it.score }.thenBy { if (it.type == "movie") 0 else 1 }) + .take(if (snapshot.status == DiscoverStatus.Ready) 5 else 1).toList() + cachedHeroesRevision = revision; cachedHeroesFilter = filter + } + return cachedHeroes + } + val hero: DiscoverTitle? get() = heroes.getOrNull(slide) + val lanes: List get() { + if (cachedRevision != revision || cachedFilter != filter || cachedService != service) { + cachedLanes = buildLanes(); cachedRevision = revision; cachedFilter = filter; cachedService = service + } + return cachedLanes + } + val firstShelf: Int get() = 2 + val rowCount: Int get() = firstShelf + lanes.size + val focusedRow: Int get() = shell.view.row.coerceIn(0, (rowCount - 1).coerceAtLeast(0)) + val focusedLane: DiscoverLane? get() = lanes.getOrNull(focusedRow - firstShelf) + val column: Int get() = shell.view.cards[rowKey].orZero().coerceAtMost(maxColumn()) + val rowKey: String get() = when (focusedRow) { 0 -> "phero"; 1 -> "dchips"; else -> focusedLane?.id.orEmpty() } + val isCard: Boolean get() = title == null && focusedRow >= firstShelf && focusedLane != null + val contentFocused: Boolean get() = !shell.navFocused && !shell.pickerVisible && overlay == null + override val cardKey: String? get() = when { + overlay != null || title != null -> null + collection != null -> collection?.cardKey + isCard -> "$rowKey:$column" + else -> null + } + + fun focus(row: Int, column: Int = 0) { + shell.navFocused = false; shell.view.row = row + shell.view.cards[rowKey] = column.coerceIn(0, maxColumn()) + } + + private fun moveRow(direction: Int) { + val target = focusedRow + direction + if (target < if (hasHero) 0 else 1) { shell.focusNav(shell.currentTab); return } + if (target >= rowCount) return + val key = when (target) { 0 -> "phero"; 1 -> "dchips"; else -> lanes[target - firstShelf].id } + val nearest = if (focusedRow >= firstShelf && target >= firstShelf) + column - shell.view.cards["first:$rowKey"].orZero() + shell.view.cards["first:$key"].orZero() + else 0 + focus(target, shell.view.cards[key] ?: nearest.coerceAtLeast(0)) + } + + fun openTitle(item: DiscoverTitle) { + title = item; titleButton = 0 + if (isSignedIn && item.ratings.isNotEmpty()) observedRatings.add(item.key) + onPush("discover-title/${item.key}") + } + fun openCollection(lane: DiscoverLane) { + var titles = lane.fullTitles.associateBy { it.key } + collectionCards = LinkedHashMap(titles.size).apply { + titles.values.forEach { put(it.key, it.libraryCard(this@DiscoverState)) } + } + lateinit var grid: LibraryGridState + grid = LibraryGridState(lane.title, collectionCards.values.filter { it.id !in hidden }, catalogue = true, observedRatings = observedRatings, + onTitle = { openTitle(titles.getValue(it.id)) }, onDiscover = { collection = null; onPop() }, onRecover = { + scope.launch { + reload() + if (collection !== grid) return@launch + grid.savedAt = snapshot.savedAt + val fresh = lanes.firstOrNull { it.id == lane.id } + if (canRequest && fresh != null) { + titles = fresh.fullTitles.associateBy { it.key } + collectionCards = LinkedHashMap(titles.size).apply { + titles.values.forEach { put(it.key, it.libraryCard(this@DiscoverState)) } + } + grid.tail = when (fresh.tail) { DiscoverTail.Retry -> GridTail.Retry; DiscoverTail.ShowMore -> GridTail.ShowMore; else -> GridTail.None } + updateCollectionCards() + } else grid.tail = GridTail.Retry + } + }).apply { + savedAt = snapshot.savedAt + tail = when (lane.tail) { DiscoverTail.Retry -> GridTail.Retry; DiscoverTail.ShowMore -> GridTail.ShowMore; else -> GridTail.None } + } + collection = grid + onPush("discover-see-all/${lane.id}") + } + + private fun updateCollectionCards(changed: DiscoverTitle? = null) { + val grid = collection ?: return + val focused = title?.key ?: grid.focusedTitle?.id + if (changed != null && changed.key in collectionCards) collectionCards[changed.key] = changed.libraryCard(this) + grid.source = collectionCards.values.filter { it.id !in hidden } + val restored = grid.items.indexOfFirst { it.id == focused } + grid.index = if (restored >= 0) restored else grid.index.coerceIn(0, + if (grid.tail == GridTail.None) grid.items.lastIndex.coerceAtLeast(0) else grid.tailIndex) + } + fun isHidden(item: DiscoverTitle): Boolean = item.key in hidden + fun isPick(item: DiscoverTitle): Boolean = snapshot.picks.any { it.key == item.key } || isHidden(item) + + fun openService(item: DiscoverService) { + rootFilter = filter; service = item; filter = "movie"; revision++ + onPush("discover-service/${item.id}") + focus(firstShelf) + } + + fun enterRoute(route: String) { + if (route == "discover") { title = null; collection = null; if (service != null) filter = rootFilter; service = null } + else if (route.startsWith("discover-service") || route.startsWith("discover-see-all")) title = null + } + + /** Card hold/release handling belongs to the shell, including the shared catalogue grid. */ + override fun key(key: ShellKey): Boolean { + if (overlay != null) { overlayKey(key); return true } + if (shell.route != "discover" && !shell.route.startsWith("discover-")) return false + if (snapshot.status == DiscoverStatus.Loading) { shell.focusNav(shell.currentTab); return true } + if (title == null) collection?.let { + if (key == ShellKey.Back) { collection = null; onPop(); return true } + return it.key(key) + } + if (key == ShellKey.Back) { + if (title != null) { title = null; onPop() } + else if (service != null) { service = null; filter = rootFilter; revision++; onPop() } + else shell.focusNav(shell.currentTab) + return true + } + if (title != null) { titleKey(key); return true } + if (!hasCatalogue) { + if (key == ShellKey.Up) shell.focusNav(shell.currentTab) else if (key == ShellKey.Ok) refresh() + return true + } + when (key) { + ShellKey.Up -> moveRow(-1) + ShellKey.Down -> moveRow(1) + ShellKey.Left, ShellKey.Right -> { + val direction = if (key == ShellKey.Left) -1 else 1 + if (focusedRow == 0) slide = (slide + direction).coerceIn(0, (heroes.size - 1).coerceAtLeast(0)) + else shell.view.cards[rowKey] = (column + direction).coerceIn(0, maxColumn()) + } + ShellKey.Ok -> when { + isCard -> activateCard() + focusedRow == 0 -> hero?.let(::openTitle) + focusedRow == 1 -> { filter = (if (service == null) DISCOVER_FILTERS else listOf("movie", "tv"))[column]; if (service == null) slide = 0; revision++ } + } + } + return true + } + + private fun maxColumn(): Int = when (focusedRow) { + 0 -> heroes.lastIndex + 1 -> if (service == null) 2 else 1 + else -> if (focusedLane?.id == "svc") snapshot.services.lastIndex else focusedLane?.let { it.titles.size - 1 + if (it.tail != DiscoverTail.None) 1 else 0 } ?: 0 + }.coerceAtLeast(0) + + private fun activateCard() { + val lane = focusedLane ?: return + if (lane.id == "svc") { snapshot.services.getOrNull(column)?.let(::openService); return } + val item = lane.titles.getOrNull(column) + if (item == null) { + if (lane.tail in setOf(DiscoverTail.Retry, DiscoverTail.ShowMore)) refresh() + else openCollection(lane) + } else if (lane.hidden) overlay = DiscoverOverlayState.Restore(item) + else openTitle(item) + } + + private fun titleKey(key: ShellKey) { + if (!canRequest) { + if (key == ShellKey.Up) shell.focusNav(shell.currentTab) else if (key == ShellKey.Ok) refresh() + return + } + when (key) { + ShellKey.Up -> shell.focusNav(shell.currentTab) + ShellKey.Left -> titleButton = (titleButton - 1).coerceAtLeast(0) + ShellKey.Right -> titleButton = (titleButton + 1).coerceAtMost(if (title?.let(::isPick) == true) 2 else 1) + ShellKey.Ok -> when (titleButton) { + 0 -> if (requests[requireNotNull(title).key]?.any { it.requester == shell.person.key } == true) shell.requestsVisible = true else openRequest(false) + 1 -> openRequest(true) + 2 -> title?.let { if (it.key in hidden) restore(it) else hide(it) } + } + else -> Unit + } + } + + fun openRequest(other: Boolean, item: DiscoverTitle = requireNotNull(title), phase: RequestPhase = RequestPhase.Choose) { + if (!canRequest) { refresh(); return } + val choice = RequestSheetState(item, shell.person, shell.people, other, phase) + val previous = requestSheets[item.key to choice.selectedPerson.key] + overlay = DiscoverOverlayState.Request( + if (phase == RequestPhase.Choose && previous?.phase in setOf(RequestPhase.Sending, RequestPhase.NotConfirmed, RequestPhase.Pending)) requireNotNull(previous) else choice, + ) + } + + private fun overlayKey(key: ShellKey) { + when (val sheet = overlay) { + is DiscoverOverlayState.Request -> sheet.state.key(key, ::send, { overlay = null }) { + scope.launch { + reload() + sheet.state.phase = if (canRequest) RequestPhase.Choose else RequestPhase.RecipientsUnavailable + sheet.state.focus = sheet.state.buttonIndex + } + } + is DiscoverOverlayState.Hidden -> when (key) { + ShellKey.Left, ShellKey.Up -> sheet.focus = 0 + ShellKey.Right, ShellKey.Down -> sheet.focus = 1 + ShellKey.Back -> overlay = null + ShellKey.Ok -> if (sheet.focus == 0) restore(sheet.title) else { overlay = null; title = null; onPop() } + } + is DiscoverOverlayState.Restore -> when (key) { + ShellKey.Left, ShellKey.Up -> sheet.focus = 0 + ShellKey.Right, ShellKey.Down -> sheet.focus = 1 + ShellKey.Back -> overlay = null + ShellKey.Ok -> if (sheet.focus == 0) restore(sheet.title) else overlay = null + } + null -> Unit + } + } + + private fun send(sheet: RequestSheetState, check: Boolean) { + if (!canRequest || (!check && !sheet.canSubmit)) return + if (!check) { + val previous = requestSheets[sheet.title.key to sheet.selectedPerson.key] + if (previous?.phase in setOf(RequestPhase.Sending, RequestPhase.NotConfirmed, RequestPhase.Pending)) { + overlay = DiscoverOverlayState.Request(requireNotNull(previous)) + return + } + } + val intent = DiscoverRequest(sheet.title, sheet.selectedPerson.key, sheet.viewer.key, isPick(sheet.title)) + requestSheets[sheet.title.key to sheet.selectedPerson.key] = sheet + sheet.phase = RequestPhase.Sending + scope.launch { + val result = (if (check) operations.check(intent) else operations.request(intent)).copy(requester = intent.requester) + sheet.result = result; sheet.phase = result.phase; sheet.focus = sheet.buttonIndex + if (result.phase == RequestPhase.Receipt) { + requests[sheet.title.key] = buildList { + requests[sheet.title.key].orEmpty().forEach { if (it.requester != result.requester) add(it) } + add(result) + } + updateCollectionCards(sheet.title) + } + } + } + + fun hide(item: DiscoverTitle) { + if (!canRequest) { refresh(); return } + hidden[item.key] = item; revision++; overlay = DiscoverOverlayState.Hidden(item) + updateCollectionCards() + val profile = shell.person.key + val version = (dismissalVersions[item.key] ?: 0) + 1 + dismissalVersions[item.key] = version + scope.launch { + val success = dismissalMutex.withLock { operations.hide(profile, item) } + if (!success && dismissalVersions[item.key] == version) { hidden.remove(item.key); revision++; updateCollectionCards(); overlay = null; toast = "Couldnโ€™t hide this pick. Try again." } + } + } + + fun restore(item: DiscoverTitle) { + if (!canRequest) { refresh(); return } + hidden.remove(item.key); revision++; overlay = null; toast = "Back in your picks." + updateCollectionCards() + val profile = shell.person.key + val version = (dismissalVersions[item.key] ?: 0) + 1 + dismissalVersions[item.key] = version + scope.launch { + val success = dismissalMutex.withLock { operations.restore(profile, item) } + if (!success && dismissalVersions[item.key] == version) { hidden[item.key] = item; revision++; updateCollectionCards(); toast = "Couldnโ€™t restore this pick. Try again." } + } + } + + fun refresh() { scope.launch { reload() } } + + private suspend fun reload() { + val refreshed = operations.refresh() + val failed = refreshed.status == DiscoverStatus.Unavailable + snapshot = if (failed && hasCatalogue) snapshot.copy(savedAt = savedTime) else refreshed + if (!failed && hasCatalogue) savedTime = formatSavedTime() + revision++ + toast = if (failed) RecoveryMessage.StillUnreachable else null + } + private fun matches(item: DiscoverTitle): Boolean = filter == "all" || item.type == filter + private fun formatSavedTime(): String = java.time.Instant.ofEpochMilli(nowMillis()).atZone(java.time.ZoneId.systemDefault()).format(java.time.format.DateTimeFormatter.ofPattern("HH:mm")) + + private fun buildLanes(): List { + val lanes = service?.let { + serviceLanes(it, filter).filter { lane -> lane.titles.isNotEmpty() } + } ?: projectDiscoverLanes(snapshot, heroes, filter, hidden) + return if (snapshot.savedAt != null) lanes + DiscoverLane("offline-recovery", "Try again", emptyList(), tail = DiscoverTail.Retry) else lanes + } +} + +private fun Int?.orZero(): Int = this ?: 0 + +private val DISCOVER_FILTERS = listOf("all", "movie", "tv") diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/DiscoverTitleDestination.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/DiscoverTitleDestination.kt new file mode 100644 index 00000000..81247975 --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/DiscoverTitleDestination.kt @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-2.0-only +package org.justinvisser.wolfskin.design + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.width +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.testTag +import androidx.tv.material3.Text +import org.justinvisser.wolfskin.design.WolfskinTokens.Color as C +import org.justinvisser.wolfskin.design.WolfskinTokens.Discover as D +import org.justinvisser.wolfskin.design.WolfskinTokens.Layout as L + +/** Explicit destination stub exposes only the Discover-owned request and pick actions. */ +@Composable +fun DiscoverTitleDestination(state: DiscoverState, modifier: Modifier = Modifier) { + val title = state.title ?: return + val focused = state.contentFocused + Box(modifier.fillMaxSize().testTag("discover-title-destination-stub")) { + DiscoverBackdrop(title, detail = true) + Column(Modifier.offset(L.safeSide, L.detailCopyTop).width(L.detailCopyWidth)) { + Text(title.title, color = C.fg, style = WolfskinTokens.Type.displayDetail, maxLines = 2) + Spacer(Modifier.height(D.heroTitleGap)) + Text("${title.typeWord}${title.year?.let { " ยท $it" }.orEmpty()} ยท ${title.genres.take(2).joinToString(", ")}", color = C.muted, style = WolfskinTokens.Type.body) + Spacer(Modifier.height(D.heroMetaGap)) + if (state.isSignedIn) DiscoverRatings(title.ratings) + Spacer(Modifier.height(D.heroMetaGap)) + Text(title.overview, color = C.muted, style = WolfskinTokens.Type.body, maxLines = 3) + Spacer(Modifier.height(D.heroOverviewGap)) + Row(horizontalArrangement = Arrangement.spacedBy(L.buttonGap)) { + if (!state.canRequest) DiscoverButton("Try again", focused) { state.refresh() } else { + val receipt = state.requests[title.key]?.firstOrNull { it.requester == state.shell.person.key } + DiscoverButton(if (receipt == null) "Request" else "Requested ยท ${receipt.stage}", focused && state.titleButton == 0, glyph = if (receipt == null) "plus" else "clock") { + state.titleButton = 0; state.key(ShellKey.Ok) + } + DiscoverButton(if (state.shell.person.key in title.heldBy) "Add for someone" else "For someone else", focused && state.titleButton == 1, glyph = "profile", primary = false) { state.openRequest(true) } + if (state.isPick(title)) DiscoverButton(if (state.isHidden(title)) "Show again" else "Not interested", focused && state.titleButton == 2, glyph = if (state.isHidden(title)) "undo" else "hide", primary = false) { state.titleButton = 2; state.key(ShellKey.Ok) } + } + } + } + } +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/DiscoverType.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/DiscoverType.kt new file mode 100644 index 00000000..45df9669 --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/DiscoverType.kt @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: GPL-2.0-only +package org.justinvisser.wolfskin.design + +import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.FirstBaseline +import androidx.compose.ui.layout.LastBaseline +import androidx.compose.ui.layout.layout +import androidx.compose.ui.text.TextStyle +import kotlin.math.roundToInt +import androidx.compose.ui.text.PlatformTextStyle +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.LineHeightStyle + +/** CSS line boxes survive native first/last-line trimming only within Discover's text stacks. */ +internal object DiscoverType { + private val lineBox = LineHeightStyle(LineHeightStyle.Alignment.Center, LineHeightStyle.Trim.None) + private val platform = PlatformTextStyle(includeFontPadding = false) + val hero = WolfskinTokens.Type.displayHero.copy(lineHeightStyle = lineBox, platformStyle = platform) + val body = WolfskinTokens.Type.body.copy(lineHeightStyle = lineBox, platformStyle = platform) + val label = WolfskinTokens.Type.label.copy(lineHeightStyle = lineBox, platformStyle = platform) + val button = WolfskinTokens.Type.button.copy(lineHeightStyle = lineBox, platformStyle = platform) + val sheetTitle = WolfskinTokens.Type.sheetTitle.copy(lineHeightStyle = lineBox, platformStyle = platform) + val stateTitle = WolfskinTokens.Type.stateTitle.copy(fontWeight = FontWeight.Bold, lineHeightStyle = lineBox, platformStyle = platform) + val listTitle = WolfskinTokens.Type.listTitle.copy(lineHeightStyle = lineBox, platformStyle = platform) + val caption = WolfskinTokens.Type.caption.copy(lineHeightStyle = lineBox, platformStyle = platform) + val reason = WolfskinTokens.Type.caption.copy(fontWeight = FontWeight.Medium, lineHeightStyle = lineBox, platformStyle = platform) + val rowHeading = WolfskinTokens.Type.rowHeading.copy(lineHeightStyle = lineBox, platformStyle = platform) + val entry = WolfskinTokens.Discover.entryText.copy(lineHeightStyle = lineBox, platformStyle = platform) + val ratings = WolfskinTokens.Type.ratingPlate.copy(fontFeatureSettings = "tnum", lineHeightStyle = lineBox, platformStyle = platform) +} + +/** Paragraph overflow must not expand the CSS block height. */ +internal fun Modifier.discoverLineBox(style: TextStyle): Modifier = layout { measurable, constraints -> + val paragraph = measurable.measure(constraints) + val lineHeight = style.lineHeight.toPx() + val lines = ((paragraph[LastBaseline] - paragraph[FirstBaseline]) / lineHeight).roundToInt() + 1 + val height = (lines * lineHeight).roundToInt().coerceIn(constraints.minHeight, constraints.maxHeight) + layout(paragraph.width, height) { + paragraph.placeRelative(0, (height - paragraph.height) / 2) + } +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/Focus.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/Focus.kt new file mode 100644 index 00000000..147409ea --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/Focus.kt @@ -0,0 +1,75 @@ +package org.justinvisser.wolfskin.design + +import androidx.compose.animation.core.CubicBezierEasing +import androidx.compose.animation.core.animateFloatAsState +import androidx.compose.animation.core.tween +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.rememberUpdatedState +import androidx.compose.runtime.remember +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.foundation.hoverable +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.interaction.collectIsHoveredAsState +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.ui.draw.dropShadow +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.drawBehind +import androidx.compose.ui.geometry.CornerRadius +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.geometry.Size +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.unit.Dp + +/** Only transforms animate: focus never changes measured geometry. */ +@Composable +fun Modifier.focusScale(focused: Boolean, scale: Float): Modifier { + val animated by animateFloatAsState( + if (focused) scale else 1f, + tween(WolfskinTokens.Motion.fast, easing = CubicBezierEasing(.25f, .1f, .25f, 1f)), + label = "focus-scale", + ) + return graphicsLayer { scaleX = animated; scaleY = animated } +} + +/** Content lifts are distinct from the white person/gear rings. */ +enum class FocusLift { None, Card, Button } + +/** Draw the ring outside the slot; neither the gap nor the ring obscures content. */ +@Composable +fun Modifier.focusRing(focused: Boolean, radius: Dp, gap: Dp, width: Dp, color: Color, lift: FocusLift = FocusLift.None): Modifier { + val ringAlpha by animateFloatAsState(if (focused) 1f else 0f, + tween(WolfskinTokens.Motion.fast, easing = CubicBezierEasing(.25f, .1f, .25f, 1f)), label = "focus-ring") + val shadow = if (lift == FocusLift.None) this else { + val shape = remember(radius) { RoundedCornerShape(radius) } + val density = LocalDensity.current + val blur = with(density) { (if (lift == FocusLift.Card) WolfskinTokens.Lift.cardBlur else WolfskinTokens.Lift.buttonBlur).toPx() } + val shift = with(density) { (if (lift == FocusLift.Card) WolfskinTokens.Lift.cardY else WolfskinTokens.Lift.buttonY).toPx() } + dropShadow(shape) { + this.radius = blur + offset = Offset(0f, shift) + this.color = Color.Black + alpha = ringAlpha * if (lift == FocusLift.Card) WolfskinTokens.Lift.cardOpacity else WolfskinTokens.Lift.buttonOpacity + } + } + return shadow.drawBehind { + if (ringAlpha > 0f) { + val outer = (gap + width).toPx() + val inner = gap.toPx() + drawRoundRect(color.copy(alpha = color.alpha * ringAlpha), Offset(-outer, -outer), Size(size.width + 2 * outer, size.height + 2 * outer), CornerRadius(radius.toPx() + outer)) + drawRoundRect(WolfskinTokens.Color.bg, Offset(-inner, -inner), Size(size.width + 2 * inner, size.height + 2 * inner), CornerRadius(radius.toPx() + inner)) + } + } +} + +/** Pointing changes the same logical focus as the D-pad without activating an action. */ +@Composable +fun Modifier.focusOnPointerEnter(onEnter: () -> Unit): Modifier { + val action by rememberUpdatedState(onEnter) + val interactions = remember { MutableInteractionSource() } + val hovered by interactions.collectIsHoveredAsState() + LaunchedEffect(hovered) { if (hovered) action() } + return hoverable(interactions) +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/FrameScroll.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/FrameScroll.kt new file mode 100644 index 00000000..18b83e5f --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/FrameScroll.kt @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0-only +package org.justinvisser.wolfskin.design + +import androidx.compose.animation.core.CubicBezierEasing +import androidx.compose.animation.core.animate +import androidx.compose.animation.core.tween +import androidx.compose.foundation.lazy.LazyListState + +/** Every frame follows focus with the same bounded scroll tween. */ +internal suspend fun animateFrameScroll(list: LazyListState, distance: Float) { + if (distance == 0f) return + list.scroll { + var previous = 0f + animate(0f, distance, animationSpec = tween(WolfskinTokens.Motion.scroll, + easing = CubicBezierEasing(.33f, 1f, .68f, 1f))) { value, _ -> + scrollBy(value - previous) + previous = value + } + } +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/Glyph.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/Glyph.kt new file mode 100644 index 00000000..5a9227d3 --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/Glyph.kt @@ -0,0 +1,43 @@ +package org.justinvisser.wolfskin.design + +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.tv.material3.Icon + +/** Shared glyph geometry comes from the locked prototype, never a platform icon font. */ +@Composable +fun Glyph(name: String, color: Color, modifier: Modifier = Modifier) { + val resource = when (name) { + "gear" -> R.drawable.wolfskin_gear + "requests" -> R.drawable.wolfskin_tray + "interface" -> R.drawable.wolfskin_grid + "play", "playback" -> R.drawable.wolfskin_play + "tv", "nextup" -> R.drawable.wolfskin_tv + "users", "profile" -> R.drawable.wolfskin_users + "about" -> R.drawable.wolfskin_info + "sparkle", "seerr" -> R.drawable.wolfskin_sparkle + "advanced" -> R.drawable.wolfskin_sort + "alert" -> R.drawable.wolfskin_alert + "wifi" -> R.drawable.wolfskin_wifi + "clock" -> R.drawable.wolfskin_clock + "plus" -> R.drawable.wolfskin_plus + "check" -> R.drawable.wolfskin_check + "hide" -> R.drawable.wolfskin_hide + "undo" -> R.drawable.wolfskin_undo + "left" -> R.drawable.wolfskin_left + "download" -> R.drawable.wolfskin_download + "film" -> R.drawable.wolfskin_film + "eye" -> R.drawable.wolfskin_eye + "down" -> R.drawable.wolfskin_down + "restart" -> R.drawable.title_restart + "version" -> R.drawable.title_version + "tracks" -> R.drawable.title_tracks + "eyeoff" -> R.drawable.title_eyeoff + "trailer" -> R.drawable.title_trailer + "more" -> R.drawable.title_more + else -> R.drawable.wolfskin_right + } + Icon(painterResource(resource), contentDescription = null, modifier = modifier, tint = color) +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/HomeAmbient.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/HomeAmbient.kt new file mode 100644 index 00000000..7f6b300a --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/HomeAmbient.kt @@ -0,0 +1,32 @@ +package org.justinvisser.wolfskin.design + +import android.graphics.Matrix +import android.graphics.RadialGradient +import android.graphics.Shader +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.geometry.Size +import androidx.compose.ui.graphics.ShaderBrush +import androidx.compose.ui.graphics.toArgb + +/** Empty hero art keeps the locked elliptical ambient wash rather than flashing a black frame. */ +@Composable +fun HomeAmbient(modifier: Modifier = Modifier) { + val brush = remember { + object : ShaderBrush() { + override fun createShader(size: Size): Shader { + val centerX = size.width * .7f + val centerY = size.height * .2f + val radiusX = size.width * 1.2f + val radiusY = size.height * .9f + return RadialGradient(centerX, centerY, radiusX, intArrayOf(WolfskinTokens.Color.surface3.toArgb(), WolfskinTokens.Color.bg.toArgb()), null, Shader.TileMode.CLAMP).apply { + setLocalMatrix(Matrix().apply { setScale(1f, radiusY / radiusX, centerX, centerY) }) + } + } + } + } + Box(modifier.background(brush)) +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/HomeFocus.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/HomeFocus.kt new file mode 100644 index 00000000..e91b22cd --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/HomeFocus.kt @@ -0,0 +1,115 @@ +package org.justinvisser.wolfskin.design + +import kotlin.math.abs + +/** Home navigation mutates the shell's per-person view, including each row's remembered column. */ +class HomeFocus( + private val shell: ShellState, + private val rows: List, + private val onAction: (HomeAction) -> Unit, +) : ShellContentFocus { + private val view = shell.rememberedView("home") + override val hasContent: Boolean get() = rows.any { it.focusable } + override val cardKey: String? get() = row?.let { if (it.kind == HomeRowKind.Shelf) it.cards.getOrNull(column)?.id ?: it.id else null } + val row: HomeRow? get() = rows.getOrNull(view.row) + val column: Int get() = row?.let { view.cards[it.id] ?: 0 } ?: 0 + + fun focus(index: Int, column: Int) { + shell.navFocused = false + view.row = index + view.home.focusedKey = rows[index].id + val target = rows[index] + val bounded = column.coerceIn(0, (target.count - 1).coerceAtLeast(0)) + view.cards[target.id] = bounded + if (target.kind == HomeRowKind.Shelf) view.home.firstCards[target.id] = target.adjustedFirst(bounded, view.home.firstCards[target.id] ?: 0) + } + + override fun key(key: ShellKey): Boolean { + val current = row ?: return false + if (key == ShellKey.Back) return false + if (key == ShellKey.Ok) { activate(current); return true } + if (reenterVisible()) return true + when (key) { + ShellKey.Left -> focus(view.row, (column - 1).coerceAtLeast(0)) + ShellKey.Right -> focus(view.row, (column + 1).coerceAtMost((current.count - 1).coerceAtLeast(0))) + ShellKey.Up, ShellKey.Down -> { + val direction = if (key == ShellKey.Up) -1 else 1 + var next = view.row + direction + while (next in rows.indices && !rows[next].focusable) next += direction + if (next in rows.indices) { + val target = rows[next] + val nearest = nearest(current, target) + focus(next, view.cards[target.id] ?: nearest) + } else if (direction < 0) { + view.row = rows.indexOfFirst { it.focusable }.coerceAtLeast(0) + view.home.resetScroll++ + shell.navFocused = true + shell.navIndex = shell.currentTab + } + } + } + return true + } + + private fun reenterVisible(): Boolean { + val layout = view.listState.layoutInfo + if (layout.totalItemsCount == 0 || view.home.positionedKey != row?.id || view.listState.isScrollInProgress) return false + val density = layout.viewportSize.width / WolfskinTokens.Shell.stageWidth.value + val current = layout.visibleItemsInfo.firstOrNull { it.index == view.row } + if (current != null && current.offset + current.size >= WolfskinTokens.Layout.navSolidAfter.value * density && + current.offset <= layout.viewportSize.height - WolfskinTokens.Layout.rowHeadingBand.value * 2 * density) return false + val first = layout.visibleItemsInfo.firstOrNull { + rows[it.index].focusable && it.offset + it.size > WolfskinTokens.Layout.rowHeadingBand.value * density && + it.offset < layout.viewportSize.height - WolfskinTokens.Layout.row_endcta.value * density + } ?: return false + focus(first.index, view.cards[rows[first.index].id] ?: 0) + return true + } + + private fun activate(row: HomeRow) { + when (row.kind) { + HomeRowKind.Hero -> row.cards.firstOrNull()?.let { title -> + onAction(if (column == 0 && row.heroKind != "pick") HomeAction.Play(title, row.heroKind == "resume") else HomeAction.Details(title)) + } + HomeRowKind.Shelf -> if (column < row.cards.size) onAction(HomeAction.Details(row.cards[column])) else onAction(HomeAction.SeeAll(row)) + HomeRowKind.State -> onAction(HomeAction.Retry) + HomeRowKind.Explore -> onAction(HomeAction.Discover) + else -> Unit + } + } + + private fun nearest(from: HomeRow, to: HomeRow): Int { + if (to.kind != HomeRowKind.Shelf) return (column * pitch(from) / pitch(to)).toInt() + val fromFirst = if (from.kind == HomeRowKind.Shelf) view.home.firstCards[from.id] ?: from.adjustedFirst(column, 0) else 0 + val x = (column - fromFirst) * pitch(from) + from.cardWidth.value / 2 + val first = (view.home.firstCards[to.id] ?: 0).coerceIn(0, (to.count - to.focusSlots).coerceAtLeast(0)) + val last = minOf(to.count - 1, first + to.focusSlots - 1) + var best = first + var distance = Float.POSITIVE_INFINITY + for (index in first..last) { + val candidate = abs((index - first) * pitch(to) + to.cardWidth.value / 2 - x) + if (candidate < distance) { best = index; distance = candidate } + } + return best + } + + private fun pitch(row: HomeRow): Float = when (row.cardKind) { + HomeCardKind.Poster -> WolfskinTokens.Card.posterPitch.value + HomeCardKind.Tile -> WolfskinTokens.Card.tilePitch.value + HomeCardKind.Wide -> WolfskinTokens.Card.widePitch.value + } +} + +internal val HomeRow.focusSlots: Int get() = when (cardKind) { + HomeCardKind.Poster -> 6 + HomeCardKind.Tile -> 4 + HomeCardKind.Wide -> 3 +} + +/** Keep one card behind focus, but do not shift again while focus stays in the visible middle. */ +internal fun HomeRow.adjustedFirst(column: Int, previous: Int): Int { + var first = previous + if (column > first + focusSlots - 2) first = column - (focusSlots - 2) + if (column < first + 1) first = (column - 1).coerceAtLeast(0) + return first.coerceIn(0, (count - focusSlots).coerceAtLeast(0)) +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/HomeHeader.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/HomeHeader.kt new file mode 100644 index 00000000..eb487f62 --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/HomeHeader.kt @@ -0,0 +1,92 @@ +package org.justinvisser.wolfskin.design + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextOverflow +import androidx.tv.material3.Text +import org.justinvisser.wolfskin.design.WolfskinTokens.Color as C +import org.justinvisser.wolfskin.design.WolfskinTokens.Home as H +import org.justinvisser.wolfskin.design.WolfskinTokens.Layout as L +import org.justinvisser.wolfskin.design.HomeType as T + +/** The hero occupies one row while its backdrop extends beneath the first shelves. */ +@Composable +fun HomeHero(row: HomeRow, focused: Boolean, column: Int, ratings: List, onButton: (Int) -> Unit, onHover: (Int) -> Unit) { + Box(Modifier.fillMaxWidth().height(L.row_hero)) { + if (!row.skeleton) { + val title = row.cards.first() + val artModifier = Modifier.wrapContentSize(Alignment.TopStart, unbounded = true).requiredSize(WolfskinTokens.Shell.stageWidth, WolfskinTokens.Shell.stageHeight) + TitleArtwork(title.title, title.type, title.poster, WolfskinTokens.Shell.stageWidth, WolfskinTokens.Shell.stageHeight, artModifier, backdrop = title.backdrop, posterOnly = title.posterOnly, landscape = true, hero = true) + Box(artModifier.background(Brush.verticalGradient(0f to C.bg.copy(alpha = 0f), .52f to C.bg.copy(alpha = 0f), .74f to C.bg.copy(alpha = .6f), 1f to C.bg))) + Box(artModifier.background(Brush.horizontalGradient(0f to C.bg.copy(alpha = .92f), .42f to C.bg.copy(alpha = .55f), .70f to C.bg.copy(alpha = 0f)))) + Column(Modifier.align(Alignment.BottomStart).padding(start = L.safeSide, bottom = L.heroCopyBottom).width(L.heroCopyWidth)) { + Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(H.kickerGap)) { + Glyph(if (row.heroKind == "pick") "seerr" else "playback", C.accentText, Modifier.size(L.buttonIcon * (28f / 30f))) + Text(when (row.heroKind) { "resume" -> "Continue watching"; "next" -> "Up next"; "new" -> "New in your library"; else -> "For you" }, modifier = Modifier.exactLineBox(T.label), color = C.accentText, style = T.label) + } + Spacer(Modifier.height(H.kickerBottom)) + Text(title.displayTitle, modifier = Modifier.exactLineBox(T.displayHero), color = C.fg, style = T.displayHero, maxLines = 2, overflow = TextOverflow.Ellipsis) + Spacer(Modifier.height(H.titleBottom)) + Row(Modifier.heightIn(min = H.factsHeight), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(H.factsGap)) { + Text(if (title.isEpisode) title.subtitle else title.year?.toString().orEmpty(), modifier = Modifier.exactLineBox(T.body), color = C.muted, style = T.body, maxLines = 1) + if (row.heroKind == "resume" || title.runtimeSeconds != null) Text(if (row.heroKind == "resume") title.remaining else title.runtime, modifier = Modifier.exactLineBox(T.body), color = C.muted, style = T.body, maxLines = 1) + HomeRatingsRow(ratings) + } + Spacer(Modifier.height(H.factsBottom)) + Text(title.overview, color = C.muted, style = T.body, maxLines = 2, overflow = TextOverflow.Ellipsis, modifier = Modifier.width(L.heroOverviewMax).exactLineBox(T.body)) + Spacer(Modifier.height(H.overviewBottom)) + Row(horizontalArrangement = Arrangement.spacedBy(L.buttonGap)) { + val primary = if (row.heroKind == "pick") "Details" else (if (row.heroKind == "resume") "Resume" else "Play") + if (title.isEpisode) " ${title.episodeLabel}" else "" + PickerButton(primary, focused && column == 0, true, if (row.heroKind == "pick") "about" else "playback", onFocus = { onHover(0) }, textStyle = T.button) { onButton(0) } + if (row.heroKind != "pick") PickerButton("Details", focused && column == 1, false, "about", onFocus = { onHover(1) }, textStyle = T.button) { onButton(1) } + } + } + } else { + HomeAmbient(Modifier.wrapContentSize(Alignment.TopStart, unbounded = true).requiredSize(WolfskinTokens.Shell.stageWidth, WolfskinTokens.Shell.stageHeight)) + Column(Modifier.align(Alignment.BottomStart).padding(start = L.safeSide, bottom = L.heroCopyBottom)) { + Box(Modifier.size(H.heroSkeletonWidth, H.heroSkeletonHeight).background(C.surface, RoundedCornerShape(WolfskinTokens.Radius.card))) + Spacer(Modifier.height(H.heroSkeletonGap)) + Box(Modifier.size(H.heroSkeletonFactsWidth, H.heroSkeletonFactsHeight).background(C.surface, RoundedCornerShape(WolfskinTokens.Radius.cardSheet))) + Spacer(Modifier.height(H.heroSkeletonButtonGap)) + Box(Modifier.size(H.heroSkeletonButtonWidth, L.buttonHeight).background(C.surface, RoundedCornerShape(WolfskinTokens.Radius.button))) + } + } + } +} + +/** Discover continues in the same scroller, under the active person's identity. */ +@Composable +fun HomeSection(person: ShellPerson, savedAt: String?) { + Box(Modifier.fillMaxWidth().height(L.row_section)) { + Row(Modifier.padding(start = L.safeSide, top = H.sectionTop), horizontalArrangement = Arrangement.spacedBy(H.sectionGap), verticalAlignment = Alignment.CenterVertically) { + Text("Discover", color = C.fg, style = T.sectionTitle) + Avatar(person, H.sectionAvatar, T.avatarLetterSectionHeader) + Text("Picks for you first, then whatโ€™s out there", color = C.muted, style = T.body) + savedAt?.let { SavedPill(it) } + } + } +} + +/** Failures keep a focusable recovery action without covering working library shelves. */ +@Composable +fun HomeRecovery(row: HomeRow, focused: Boolean, retry: () -> Unit, onHover: () -> Unit) { + Box(Modifier.fillMaxWidth().height(L.row_state)) { + Column(Modifier.offset(L.safeSide, H.stateTop).width(L.stateWidth).background(C.surface, RoundedCornerShape(WolfskinTokens.Radius.panel)).border(H.hairline, C.border, RoundedCornerShape(WolfskinTokens.Radius.panel)).padding(horizontal = H.statePaddingX + H.hairline, vertical = H.statePaddingY + H.hairline)) { + Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(H.plateTop)) { + Glyph(if (row.calm) "profile" else "alert", if (row.calm) C.accentText else C.warn, Modifier.size(H.stateIcon)) + Text(row.title, modifier = Modifier.exactLineBox(T.stateTitle), color = C.fg, style = T.stateTitle.copy(fontWeight = FontWeight.Bold)) + } + Spacer(Modifier.height(H.stateGap)) + Text(row.text, modifier = Modifier.exactLineBox(T.body), color = C.muted, style = T.body) + Spacer(Modifier.height(H.stateTextBottom)) + PickerButton("Try again", focused, row.calm, onFocus = onHover, textStyle = T.button, onClick = retry) + } + } +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/HomeModel.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/HomeModel.kt new file mode 100644 index 00000000..d2e6adb2 --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/HomeModel.kt @@ -0,0 +1,92 @@ +package org.justinvisser.wolfskin.design + +import androidx.compose.runtime.Immutable +import java.util.Locale +import kotlin.math.roundToInt + +/** A screen-owned media projection, independent of Jellyfin and catalogue DTOs. */ +@Immutable +data class HomeTitle( + val id: String, + val title: String, + val type: String, + val year: Int? = null, + val runtimeSeconds: Int? = null, + val seasons: Int? = null, + val overview: String = "", + val poster: String? = null, + val backdrop: String? = null, + val posterOnly: Boolean = false, + val seriesTitle: String? = null, + val season: Int? = null, + val episode: Int? = null, + val resumeSeconds: Double = 0.0, + val played: Boolean = false, + val addedAt: String = "", + val genres: List = emptyList(), + val ratings: List = emptyList(), + val held: Boolean = false, + val otherOwner: String? = null, + val tmdbId: Int? = null, +) { + val isEpisode: Boolean get() = type == "episode" + val displayTitle: String get() = seriesTitle ?: title + val episodeLabel: String get() = "S$season E$episode" + val runtime: String get() { + val minutes = ((runtimeSeconds ?: 0) / 60.0).roundToInt() + return if (minutes >= 60) "${minutes / 60}h ${minutes % 60}m" else "${minutes}m" + } + val remaining: String get() = "${(((runtimeSeconds ?: 0) - resumeSeconds) / 60).roundToInt().coerceAtLeast(1)} min left" + val subtitle: String get() = if (isEpisode) "$episodeLabel ยท $title" else "${if (type == "movie") "Movie" else "Series"} ยท ${year ?: ""}" + val facts: String get() = listOfNotNull(year?.toString(), if (type == "movie") runtimeSeconds?.let { runtime } ?: "Movie" else seasons?.let { "$it ${if (it == 1) "season" else "seasons"}" } ?: "Series").joinToString(" ยท ") +} + +/** Only observed, range-checked scores reach this model; formatting follows the TV locale. */ +@Immutable +data class HomeRating(val mark: String, val score: Double, val percentage: Boolean = false, val episode: Boolean = false) { + fun format(locale: Locale = Locale.getDefault()): String = if (percentage) "${score.toInt()}%" else String.format(locale, "%.1f", score) +} + +enum class HomeCardKind { Poster, Tile, Wide } +enum class HomeRowKind { Hero, Shelf, Section, State, Note, Explore } +enum class HomeAvailability { Ready, Loading, SignedOut, Unavailable, Saved } + +/** Rows retain stable keys while a refresh replaces their immutable contents. */ +@Immutable +data class HomeRow( + val id: String, + val kind: HomeRowKind, + val title: String = "", + val cards: List = emptyList(), + val cardKind: HomeCardKind = HomeCardKind.Poster, + val catalogue: Boolean = false, + val total: Int = cards.size, + val target: String? = null, + val text: String = "", + val heroKind: String = "next", + val skeleton: Boolean = false, + val calm: Boolean = false, + val allCards: List = cards, +) { + val hasSeeAll: Boolean get() = total > cards.size + val count: Int get() = when (kind) { HomeRowKind.Hero -> if (heroKind == "pick") 1 else 2; HomeRowKind.Shelf -> cards.size + if (hasSeeAll) 1 else 0; HomeRowKind.State, HomeRowKind.Explore -> 1; else -> 0 } + val focusable: Boolean get() = !skeleton && count > 0 +} + +/** One snapshot paints immediately; source status never discards a saved view. */ +@Immutable +data class HomeSnapshot( + val rows: List, + val conductarr: HomeAvailability = HomeAvailability.SignedOut, + val jellyfinAvailable: Boolean = true, + val savedAt: String? = null, +) + +/** Home emits integration intents, never owns the upstream player or later-slice pages. */ +sealed interface HomeAction { + data class Play(val title: HomeTitle, val resume: Boolean) : HomeAction + data class Details(val title: HomeTitle) : HomeAction + data class SeeAll(val row: HomeRow) : HomeAction + data object Discover : HomeAction + data object Retry : HomeAction +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/HomeRatingCache.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/HomeRatingCache.kt new file mode 100644 index 00000000..89ea3093 --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/HomeRatingCache.kt @@ -0,0 +1,28 @@ +package org.justinvisser.wolfskin.design + +/** The screen's ratings cache uses an injected clock and never caches failed reads. */ +class HomeRatingCache(private val clock: () -> Long = System::currentTimeMillis) { + private data class Entry(val ratings: List, val readAt: Long) + private val entries = linkedMapOf() + + fun read(title: HomeTitle): List? { + val key = key(title) + val entry = entries[key] ?: return null + if (clock() - entry.readAt >= lifetimeMillis) { entries.remove(key); return null } + return entry.ratings + } + + fun save(title: HomeTitle, ratings: List) { + val key = key(title) + entries.remove(key) + entries[key] = Entry(ratings, clock()) + while (entries.size > capacity) entries.remove(entries.keys.first()) + } + + private fun key(title: HomeTitle): String = if (title.isEpisode) "episode:${title.id}" else "${title.type}:${title.tmdbId ?: title.id}" + + companion object { + private const val capacity = 300 + private val lifetimeMillis = (WolfskinTokens.Behaviour.cacheRatingsHours * 60 * 60 * 1000).toLong() + } +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/HomeRatings.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/HomeRatings.kt new file mode 100644 index 00000000..11ea2f3f --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/HomeRatings.kt @@ -0,0 +1,91 @@ +package org.justinvisser.wolfskin.design + +import androidx.compose.animation.core.animateFloatAsState +import androidx.compose.animation.core.tween +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.BoxWithConstraints +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.graphics.ColorMatrix +import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.rememberTextMeasurer +import androidx.compose.ui.unit.TextUnit +import androidx.tv.material3.Text +import java.util.Locale +import org.justinvisser.wolfskin.design.WolfskinTokens.Color as C +import org.justinvisser.wolfskin.design.WolfskinTokens.Home as H +import org.justinvisser.wolfskin.design.HomeType as T + +/** Formatting is measured before fitting, so decimal commas obey the same one-line rule. */ +@Composable +fun HomeRatingsRow(ratings: List, modifier: Modifier = Modifier, fontSize: TextUnit = T.ratingPlate.fontSize, plate: Boolean = false) { + val density = LocalDensity.current + val size = with(density) { fontSize.toDp() } + val entryGap = if (plate) size * .64f else H.ratingGap + val markGap = if (plate) size * .29f else H.ratingMarkGap + Row(modifier, horizontalArrangement = Arrangement.spacedBy(entryGap), verticalAlignment = Alignment.CenterVertically) { + ratings.forEach { rating -> + Row(horizontalArrangement = Arrangement.spacedBy(markGap), verticalAlignment = Alignment.CenterVertically) { + val resource = when (rating.mark) { + "rotten" -> R.drawable.ic_rotten_tomatoes_rotten + "upright" -> R.drawable.ic_rt_upright + "spilled" -> R.drawable.ic_rt_spilled + "imdb" -> R.drawable.ic_rating_imdb + "tmdb" -> R.drawable.ic_rating_tmdb + else -> R.drawable.ic_rotten_tomatoes_fresh + } + val muted = rating.mark == "tomato" + Image(painterResource(resource), null, Modifier.size(size * if (rating.mark == "imdb" || rating.mark == "tmdb") 1.8f else 1f, size).graphicsLayer { alpha = if (muted) .55f else 1f }, colorFilter = if (muted) ColorFilter.colorMatrix(ColorMatrix().apply { setToSaturation(0f) }) else null) + if (rating.episode) Text("Ep", color = C.muted, style = T.ratingPlate.copy(fontSize = fontSize, lineHeight = fontSize * 1.2f, fontWeight = T.label.fontWeight), maxLines = 1) + Text(rating.format(), color = C.fg, style = T.ratingPlate.copy(fontSize = fontSize, lineHeight = fontSize * 1.2f, fontFeatureSettings = "tnum"), maxLines = 1, softWrap = false) + } + } + } +} + +/** The plate is a prefix of the full ratings set; its first entry is never discarded. */ +@Composable +fun HomeRatingPlate(ratings: List, visible: Boolean, modifier: Modifier = Modifier) { + val alpha by animateFloatAsState(if (visible && ratings.isNotEmpty()) 1f else 0f, tween(WolfskinTokens.Motion.base), label = "rating-plate") + if (ratings.isEmpty()) return + val measurer = rememberTextMeasurer() + val density = LocalDensity.current + val locale = Locale.getDefault() + BoxWithConstraints(modifier.graphicsLayer { this.alpha = alpha }.background(Brush.verticalGradient(0f to C.bg.copy(alpha = .9f), .52f to C.bg.copy(alpha = .72f), 1f to C.bg.copy(alpha = 0f))).padding(start = H.plateSide, end = H.plateSide, top = H.plateTop, bottom = H.plateFade)) { + val available = with(density) { maxWidth.toPx() } + val fitted = remember(ratings, available, density, locale) { + val base = T.ratingPlate.fontSize + val floor = T.caption.fontSize + fun width(size: TextUnit, entries: List): Float { + val em = with(density) { size.toPx() } + return entries.sumOf { rating -> + val mark = em * if (rating.mark == "imdb" || rating.mark == "tmdb") 1.8f else 1f + val number = measurer.measure(rating.format(locale), T.ratingPlate.copy(fontSize = size)).size.width + val episode = if (rating.episode) measurer.measure("Ep", T.ratingPlate.copy(fontSize = size, fontWeight = T.label.fontWeight)).size.width + em * .29f else 0f + (mark + em * .29f + number + episode).toDouble() + }.toFloat() + (entries.size - 1).coerceAtLeast(0) * em * .64f + } + var size = base + val initialWidth = width(base, ratings) + if (initialWidth > available) size = base * (available / initialWidth).coerceAtLeast(floor.value / base.value) + val step = (base.value - floor.value) / 8 + while (size > floor && width(size, ratings) > available) size = base * ((size.value - step).coerceAtLeast(floor.value) / base.value) + var count = ratings.size + while (count > 1 && width(size, ratings.take(count)) > available) count-- + size to ratings.take(count) + } + HomeRatingsRow(fitted.second, fontSize = fitted.first, plate = true) + } +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/HomeRows.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/HomeRows.kt new file mode 100644 index 00000000..4c7f8beb --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/HomeRows.kt @@ -0,0 +1,55 @@ +package org.justinvisser.wolfskin.design + +/** Source reads preserve their order; the hero is removed by stable item identity. */ +data class HomeLibrary( + val resume: List = emptyList(), + val nextUp: List = emptyList(), + val newest: List = emptyList(), + val destinations: Map> = emptyMap(), + val destinationTotals: Map = emptyMap(), +) + +/** Merge the two sources into the single Home frame without inventing playable items. */ +fun buildHomeRows( + library: HomeLibrary, + continuation: List, + libraryAvailable: Boolean = true, + loading: Boolean = false, +): List = buildList { + if (loading) { + add(HomeRow("hero-sk", HomeRowKind.Hero, skeleton = true)) + listOf(HomeCardKind.Tile, HomeCardKind.Tile, HomeCardKind.Poster, HomeCardKind.Poster).forEachIndexed { index, kind -> + add(HomeRow("sk$index", HomeRowKind.Shelf, cardKind = kind, skeleton = true)) + } + return@buildList + } + val choice = when { + library.resume.isNotEmpty() -> "resume" to library.resume.first() + library.nextUp.isNotEmpty() -> "next" to library.nextUp.first() + library.newest.isNotEmpty() -> "new" to library.newest.first() + else -> continuation.firstNotNullOfOrNull { it.cards.firstOrNull() }?.let { "pick" to it } + } + val hero = choice?.second + if (hero != null) add(HomeRow("hero", HomeRowKind.Hero, cards = listOf(hero), heroKind = choice.first)) + if (!libraryAvailable) { + add(HomeRow("jf-down", HomeRowKind.State, "Your library canโ€™t be reached", text = "Jellyfin isnโ€™t answering, so nothing can play right now.")) + } else { + listOf(Triple("cw", "Continue watching", library.resume), Triple("nu", "Next up", library.nextUp), Triple("new", "New in your library", library.newest)).forEach { (id, title, source) -> + val cards = source.filter { it.id != hero?.id } + if (cards.isNotEmpty()) add(HomeRow(id, HomeRowKind.Shelf, title, cards, if (id == "cw") HomeCardKind.Wide else HomeCardKind.Tile)) + } + listOf("movies", "shows", "anime").forEach { destination -> + val titles = library.destinations[destination].orEmpty().sortedWith(compareBy { it.played }.thenByDescending { it.addedAt }) + if (titles.isNotEmpty()) add(HomeRow("lib-$destination", HomeRowKind.Shelf, if (destination == "anime") "Anime" else "Your $destination", titles.take(WolfskinTokens.Behaviour.rowLimit.toInt()), total = library.destinationTotals[destination] ?: titles.size, target = destination)) + } + } + add(HomeRow("disc-h", HomeRowKind.Section, "Discover")) + addAll(continuation) +} + +/** Authentication failure is distinct from an unreachable signed-in catalogue. */ +fun homeDiscoverState(status: HomeAvailability): HomeRow = if (status == HomeAvailability.SignedOut) { + HomeRow("signin", HomeRowKind.State, "Discover needs sign-in", text = "Sign this TV in to Conductarr to see picks and request titles. Your library plays as usual.", calm = true) +} else { + HomeRow("cond-down", HomeRowKind.State, "Discover is resting", text = "Conductarr canโ€™t be reached. Your library still plays.") +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/HomeScreen.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/HomeScreen.kt new file mode 100644 index 00000000..2d0a646c --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/HomeScreen.kt @@ -0,0 +1,129 @@ +package org.justinvisser.wolfskin.design + +import androidx.compose.animation.core.CubicBezierEasing +import androidx.compose.animation.core.tween +import androidx.compose.foundation.gestures.animateScrollBy +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.runtime.* +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.semantics.stateDescription +import androidx.tv.material3.Text +import kotlinx.coroutines.delay +import org.justinvisser.wolfskin.design.WolfskinTokens.Color as C +import org.justinvisser.wolfskin.design.WolfskinTokens.Home as H +import org.justinvisser.wolfskin.design.WolfskinTokens.Layout as L + +/** One collector owns the focused card dwell; cached scores appear on re-entry without another read. */ +@Composable +fun HomeScreen( + shell: ShellState, + snapshot: HomeSnapshot, + modifier: Modifier = Modifier, + onAction: (HomeAction) -> Unit, +) { + val view = shell.rememberedView("home") + LaunchedEffect(view, snapshot.savedAt) { view.savedAt = snapshot.savedAt } + val action by rememberUpdatedState(onAction) + val focus = remember(shell, snapshot.rows, view) { HomeFocus(shell, snapshot.rows) { action(it) } } + DisposableEffect(shell, focus) { + shell.contentFocus = focus + onDispose { if (shell.contentFocus === focus) shell.contentFocus = null } + } + LaunchedEffect(snapshot.rows, view) { + snapshot.rows.forEach { item -> + view.cards[item.id]?.let { view.cards[item.id] = it.coerceIn(0, (item.count - 1).coerceAtLeast(0)) } + } + val remembered = snapshot.rows.indexOfFirst { it.id == view.home.focusedKey && it.focusable } + if (remembered >= 0) view.row = remembered + if (snapshot.rows.none { it.focusable }) { + if (view.home.focusedKey == null && !shell.navFocused) view.home.loadingEntryRevision = shell.inputRevision + shell.navFocused = true + shell.navIndex = shell.currentTab + } else { + if (view.home.loadingEntryRevision == shell.inputRevision) focus.focus(snapshot.rows.indexOfFirst { it.focusable }, 0) + view.home.loadingEntryRevision = null + if (snapshot.rows.getOrNull(view.row)?.focusable != true) view.row = snapshot.rows.indexOfFirst { it.focusable } + } + view.home.focusedKey = snapshot.rows.getOrNull(view.row)?.id + } + val density = LocalDensity.current + val heights = remember(snapshot.rows) { snapshot.rows.map { rowHeight(it) } } + val topInset = if (snapshot.rows.firstOrNull()?.kind == HomeRowKind.Hero) WolfskinTokens.Shell.zero else L.pinnedLine + val context = LocalContext.current + LaunchedEffect(view.row, snapshot.rows) { + snapshot.rows.drop(view.row + 1).firstOrNull { it.kind == HomeRowKind.Shelf && !it.skeleton }?.let { WolfskinImages.prefetch(context, it) } + } + LaunchedEffect(view) { + if (view.home.positionedKey != null) { + view.home.focusedKey?.let { view.home.tracks[it] }?.let { track -> + track.scrollToItem(track.firstVisibleItemIndex, track.firstVisibleItemScrollOffset) + } + view.listState.scrollToItem(view.listState.firstVisibleItemIndex, view.listState.firstVisibleItemScrollOffset) + } + } + LaunchedEffect(view, view.row, view.home.resetScroll, snapshot.rows) { + val key = snapshot.rows.getOrNull(view.row)?.id + if (view.home.positionedKey == key && view.home.positionedReset == view.home.resetScroll) return@LaunchedEffect + val topRequested = shell.navFocused && view.home.resetScroll > 0 && view.home.positionedReset != view.home.resetScroll + val target = if (topRequested) 0f else with(density) { + (heights.take(view.row).fold(topInset) { total, height -> total + height } - if (snapshot.rows.getOrNull(view.row)?.kind == HomeRowKind.Hero) WolfskinTokens.Shell.zero else L.pinnedLine).toPx() + }.coerceAtLeast(0f) + view.home.positionedKey = key + view.home.positionedReset = view.home.resetScroll + val current = with(density) { heights.take(view.listState.firstVisibleItemIndex).fold(WolfskinTokens.Shell.zero) { total, height -> total + height }.toPx() } + view.listState.firstVisibleItemScrollOffset + view.listState.animateScrollBy(target - current, tween(WolfskinTokens.Motion.scroll, easing = CubicBezierEasing(.33f, 1f, .68f, 1f))) + } + val cache = view.home.ratings + val row = snapshot.rows.getOrNull(view.row) + val title = row?.cards?.getOrNull(focus.column) + val hero = snapshot.rows.firstOrNull { it.kind == HomeRowKind.Hero }?.cards?.firstOrNull() + var heroRatings by remember(hero?.id) { mutableStateOf(hero?.let(cache::read).orEmpty()) } + var focusedRatings by remember(title?.id, shell.navFocused) { mutableStateOf(title?.let(cache::read).orEmpty()) } + LaunchedEffect(title?.id, hero?.id, shell.navFocused, shell.pickerVisible, snapshot.conductarr) { + if (hero != null && snapshot.conductarr == HomeAvailability.Ready) { + heroRatings = hero.ratings + cache.save(hero, heroRatings) + } + if (title != null && !shell.navFocused && !shell.pickerVisible && snapshot.conductarr == HomeAvailability.Ready) { + val saved = cache.read(title) + if (saved == null && row.kind != HomeRowKind.Hero) delay(WolfskinTokens.Motion.ratingDwell.toLong()) + focusedRatings = saved ?: title.ratings.also { cache.save(title, it) } + } + } + val showRatings = snapshot.conductarr != HomeAvailability.SignedOut + val trailingSpace = maxOf(H.frameBottom, WolfskinTokens.Shell.stageHeight - L.pinnedLine - (heights.lastOrNull() ?: WolfskinTokens.Shell.zero)) + LazyColumn(state = view.listState, modifier = modifier.testTag("wolfskin-home").semantics { stateDescription = "${row?.id}:${focus.column}" }, contentPadding = PaddingValues(top = topInset, bottom = trailingSpace)) { + itemsIndexed(snapshot.rows, key = { _, item -> item.id }, contentType = { _, item -> item.kind.name.lowercase() }) { index, item -> + val selected = index == view.row && !shell.navFocused + fun activate(column: Int) { focus.focus(index, column); focus.key(ShellKey.Ok) } + when (item.kind) { + HomeRowKind.Hero -> HomeHero(item, selected, focus.column, if (showRatings) heroRatings else emptyList(), ::activate) { focus.focus(index, it) } + HomeRowKind.Shelf -> HomeShelf(item, view.home, selected, view.cards[item.id] ?: 0, if (showRatings && selected) focusedRatings else emptyList(), ::activate) { focus.focus(index, it) } + HomeRowKind.Section -> HomeSection(shell.person, snapshot.savedAt) + HomeRowKind.State -> HomeRecovery(item, selected, { activate(0) }) { focus.focus(index, 0) } + HomeRowKind.Note -> Row(Modifier.fillMaxWidth().height(L.row_note).padding(start = L.safeSide, top = H.noteTop), horizontalArrangement = Arrangement.spacedBy(H.noteGap)) { + Glyph(if (item.calm) "eye" else "alert", if (item.calm) C.muted else C.warn, Modifier.size(L.buttonIcon)) + Text(item.text, color = if (item.calm) C.muted else C.warn, style = HomeType.body) + } + HomeRowKind.Explore -> Box(Modifier.fillMaxWidth().height(L.row_endcta).padding(start = L.safeSide, top = H.endTop)) { + PickerButton("Explore more in Discover", selected, true, "seerr", onFocus = { focus.focus(index, 0) }, textStyle = HomeType.button) { activate(0) } + } + } + } + } +} + +private fun rowHeight(row: HomeRow) = when (row.kind) { + HomeRowKind.Hero -> L.row_hero + HomeRowKind.Shelf -> L.rowHeadingBand + row.cardHeight + (if (row.cardKind == HomeCardKind.Poster) WolfskinTokens.Card.posterCaptionBand else WolfskinTokens.Shell.zero) + L.rowGapAfter + HomeRowKind.Section -> L.row_section + HomeRowKind.State -> L.row_state + HomeRowKind.Note -> L.row_note + HomeRowKind.Explore -> L.row_endcta +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/HomeShelf.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/HomeShelf.kt new file mode 100644 index 00000000..9b97fe8b --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/HomeShelf.kt @@ -0,0 +1,110 @@ +package org.justinvisser.wolfskin.design + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.animation.core.tween +import androidx.compose.foundation.gestures.animateScrollBy +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.foundation.lazy.LazyListState +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.SideEffect +import androidx.compose.runtime.remember +import androidx.compose.runtime.getValue +import androidx.compose.runtime.rememberUpdatedState +import androidx.compose.runtime.snapshotFlow +import kotlinx.coroutines.flow.collectLatest +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.draw.clip +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.zIndex +import androidx.tv.material3.Text +import org.justinvisser.wolfskin.design.WolfskinTokens.Card as K +import org.justinvisser.wolfskin.design.WolfskinTokens.Color as C +import org.justinvisser.wolfskin.design.WolfskinTokens.Home as H +import org.justinvisser.wolfskin.design.WolfskinTokens.Layout as L +import org.justinvisser.wolfskin.design.HomeType as T + +/** Every lazy row and card uses a stable source identity and an explicit content type. */ +@Composable +fun HomeShelf(row: HomeRow, memory: HomeViewMemory, focused: Boolean, column: Int, ratings: List, onCard: (Int) -> Unit, onHover: (Int) -> Unit) { + val width = row.cardWidth + val height = row.cardHeight + val caption = if (row.cardKind == HomeCardKind.Poster) K.posterCaptionBand else WolfskinTokens.Shell.zero + val first = row.adjustedFirst(column, memory.firstCards[row.id] ?: 0) + SideEffect { if (memory.firstCards[row.id] != first) memory.firstCards[row.id] = first } + val track = remember(memory, row.id) { memory.tracks.getOrPut(row.id) { LazyListState(first) } } + val targetFirst by rememberUpdatedState(first) + val density = LocalDensity.current + LaunchedEffect(track) { + track.scrollToItem(track.firstVisibleItemIndex, track.firstVisibleItemScrollOffset) + var positionedFirst = targetFirst + snapshotFlow { targetFirst }.collectLatest { target -> + if (target != positionedFirst) { + positionedFirst = target + val pitch = with(density) { (width + K.posterGap).toPx() } + track.animateScrollBy((target - track.firstVisibleItemIndex) * pitch - track.firstVisibleItemScrollOffset, tween(WolfskinTokens.Motion.base)) + } + } + } + Box(Modifier.fillMaxWidth().height(L.rowHeadingBand + height + caption + L.rowGapAfter)) { + if (!row.skeleton) Text(row.title, color = C.fg, style = T.rowHeading, maxLines = 1, modifier = Modifier.offset(x = L.safeSide)) + val cards = if (row.skeleton) List(if (row.cardKind == HomeCardKind.Poster) 8 else 5) { null } else row.cards + if (row.hasSeeAll) listOf(null) else emptyList() + LazyRow(state = track, modifier = Modifier.fillMaxWidth().offset(y = L.rowHeadingBand - L.rowGapAfter).height(height + L.rowGapAfter * 2), contentPadding = PaddingValues(horizontal = L.safeSide, vertical = L.rowGapAfter), horizontalArrangement = Arrangement.spacedBy(K.posterGap), userScrollEnabled = !row.skeleton) { + itemsIndexed(cards, key = { index, title -> title?.id ?: "${row.id}:tail:$index" }, contentType = { _, title -> if (row.skeleton) "skeleton" else if (title == null) "seeAll" else row.cardKind.name.lowercase() }) { index, title -> + val selected = focused && column == index + val cardModifier = Modifier.zIndex(if (selected) 2f else 0f).testTag("home-card:${row.id}:$index") + .then(if (!row.skeleton) Modifier.focusOnPointerEnter { onHover(index) } else Modifier) + if (title == null && !row.skeleton) { + LibrarySeeAllCard(row.total, selected, { onCard(index) }, cardModifier, width, height, T.listTitle, T.label) + } else TitleCard(selected, cardModifier.then(if (!row.skeleton) Modifier.clickable { onCard(index) } else Modifier), width, height) { + if (title == null) Box(Modifier.fillMaxSize().background(C.surface)) else { + TitleArtwork(title.title, title.type, title.poster, width, height, Modifier.fillMaxSize(), backdrop = title.backdrop, posterOnly = title.posterOnly, landscape = row.cardKind != HomeCardKind.Poster) + if (row.cardKind != HomeCardKind.Poster) TileOverlay(title) + if (row.catalogue && title.held) Box(Modifier.align(Alignment.BottomEnd).padding(L.badgeInset).size(L.badge).background(C.ok, CircleShape), contentAlignment = Alignment.Center) { Text("โœ“", color = C.onFocus, style = T.button) } + if (title.resumeSeconds > 0 && title.runtimeSeconds != null) Box(Modifier.align(Alignment.BottomCenter).padding(horizontal = H.progressInset).padding(bottom = if (row.cardKind == HomeCardKind.Poster) H.posterProgressBottom else H.progressBottom).fillMaxWidth().height(L.progressBar).clip(RoundedCornerShape(WolfskinTokens.Radius.progress)).background(C.progressTrack)) { + Box(Modifier.fillMaxHeight().fillMaxWidth((title.resumeSeconds / title.runtimeSeconds).toFloat().coerceIn(0f, 1f)).background(C.accent)) + } + HomeRatingPlate(if (selected) ratings else emptyList(), selected, Modifier.fillMaxWidth()) + } + } + } + } + if (row.cardKind == HomeCardKind.Poster && focused && !row.skeleton) { + val title = row.cards.getOrNull(column) + val availability = when { + title == null -> null + row.catalogue -> if (title.held) "In your library" else title.otherOwner?.let { "In $itโ€™s library" } + title.played -> "Watched" + title.resumeSeconds > 0 -> title.remaining + else -> null + } + val facts = remember(title, row.total, availability) { + (title?.facts ?: "${row.total} titles").replace(" ยท ", " ยท ") + availability?.let { " ยท $it" }.orEmpty() + } + Caption(title?.title ?: "See all ${row.title}", facts, true, Modifier.offset(L.safeSide + (width + K.posterGap) * (column - first), L.rowHeadingBand + height + L.captionOffset).width(H.captionWidth), accentLastFact = availability != null, titleStyle = T.button, factsStyle = T.caption, titleOverflow = TextOverflow.Ellipsis) + } + } +} + +@Composable +private fun TileOverlay(title: HomeTitle) { + Box(Modifier.fillMaxSize(), contentAlignment = Alignment.BottomStart) { + Column(Modifier.fillMaxWidth().background(Brush.verticalGradient(listOf(C.bg.copy(alpha = 0f), C.bg.copy(alpha = .92f)))).padding(start = H.cardPadding, end = H.cardPadding, top = H.cardOverlayTop, bottom = H.cardOverlayBottom)) { + Text(title.displayTitle, modifier = Modifier.exactLineBox(T.button), color = C.fg, style = T.button, maxLines = 1, overflow = TextOverflow.Ellipsis) + Text(title.subtitle, modifier = Modifier.exactLineBox(T.caption), color = C.muted, style = T.caption, maxLines = 1, overflow = TextOverflow.Ellipsis) + } + } +} + +val HomeRow.cardWidth: Dp get() = when (cardKind) { HomeCardKind.Poster -> K.posterW; HomeCardKind.Tile -> K.tileW; HomeCardKind.Wide -> K.wideW } +val HomeRow.cardHeight: Dp get() = when (cardKind) { HomeCardKind.Poster -> K.posterH; HomeCardKind.Tile -> K.tileH; HomeCardKind.Wide -> K.wideH } diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/HomeType.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/HomeType.kt new file mode 100644 index 00000000..f54faeaa --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/HomeType.kt @@ -0,0 +1,24 @@ +package org.justinvisser.wolfskin.design + +import androidx.compose.ui.text.PlatformTextStyle +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.style.LineHeightStyle + +/** Home keeps full CSS line boxes without moving retained shell or library typography. */ +object HomeType { + private fun fullBox(style: TextStyle): TextStyle = style.copy( + platformStyle = PlatformTextStyle(includeFontPadding = false), + lineHeightStyle = LineHeightStyle(LineHeightStyle.Alignment.Center, LineHeightStyle.Trim.None, LineHeightStyle.Mode.Tight), + ) + val body = fullBox(WolfskinTokens.Type.body) + val button = fullBox(WolfskinTokens.Type.button) + val caption = fullBox(WolfskinTokens.Type.caption) + val label = fullBox(WolfskinTokens.Type.label) + val displayHero = fullBox(WolfskinTokens.Type.displayHero) + val stateTitle = fullBox(WolfskinTokens.Type.stateTitle) + val sectionTitle = fullBox(WolfskinTokens.Type.sectionTitle) + val rowHeading = WolfskinTokens.Type.rowHeading + val ratingPlate = WolfskinTokens.Type.ratingPlate + val listTitle = fullBox(WolfskinTokens.Type.listTitle) + val avatarLetterSectionHeader = WolfskinTokens.Type.avatarLetterSectionHeader +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/HomeViewMemory.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/HomeViewMemory.kt new file mode 100644 index 00000000..65f379ad --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/HomeViewMemory.kt @@ -0,0 +1,19 @@ +package org.justinvisser.wolfskin.design + +import androidx.compose.foundation.lazy.LazyListState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.mutableStateMapOf +import androidx.compose.runtime.setValue + +/** Focus-follow runs on a new row, never on re-entry to an already-positioned saved viewport. */ +class HomeViewMemory { + val ratings = HomeRatingCache() + val firstCards = mutableStateMapOf() + val tracks = mutableMapOf() + var loadingEntryRevision: Long? = null + var focusedKey: String? = null + var positionedKey: String? = null + var resetScroll by mutableIntStateOf(0) + var positionedReset = -1 +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/Identity.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/Identity.kt new file mode 100644 index 00000000..266cbded --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/Identity.kt @@ -0,0 +1,39 @@ +package org.justinvisser.wolfskin.design + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.unit.Dp +import androidx.tv.material3.Text + +/** Fixed household colours never depend on preference or avatar presets. */ +fun personColor(key: String): Color = when (key.lowercase()) { + "justin" -> WolfskinTokens.PersonColor.justin + "mindel" -> WolfskinTokens.PersonColor.mindel + "shared" -> WolfskinTokens.PersonColor.shared + else -> WolfskinTokens.Color.accent +} + +/** The same mark anchors the picker and the persistent navigation. */ +@Composable +fun Wordmark(modifier: Modifier = Modifier) { + Row(modifier) { + Text("Wolf", color = WolfskinTokens.Color.fg, style = WolfskinTokens.Type.wordmark) + Text("skin", color = WolfskinTokens.Color.accent, style = WolfskinTokens.Type.wordmark) + } +} + +/** Initials are drawn over opaque person colour at the exact slot size. */ +@Composable +fun Avatar(person: ShellPerson, diameter: Dp, textStyle: TextStyle, modifier: Modifier = Modifier, letterColor: Color = WolfskinTokens.Color.onFocus) { + Box(modifier.size(diameter).background(personColor(person.key), CircleShape), contentAlignment = Alignment.Center) { + Text(person.initial, color = letterColor, style = textStyle) + } +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/LibraryFixture.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/LibraryFixture.kt new file mode 100644 index 00000000..24f680c3 --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/LibraryFixture.kt @@ -0,0 +1,56 @@ +package org.justinvisser.wolfskin.design + +import org.json.JSONArray +import org.json.JSONObject + +/** The locked fixture is supplied by debug assets or JVM resources, never a release fallback. */ +class LibraryFixture(json: String, private val posterPrefix: String) { + private val document = JSONObject(json) + private val profiles = document.getJSONArray("profiles") + private val people = (0 until profiles.length()).associate { profiles.getJSONObject(it).let { person -> person.getString("key") to person } } + private val holders = buildMap> { + people.forEach { (key, person) -> + for (destination in listOf("movies", "shows", "anime")) { + val library = person.optJSONArray(destination) ?: continue + for (index in 0 until library.length()) { + val item = library.getJSONObject(index) + getOrPut("${item.optString("type")}:${item.optString("tmdbId")}") { mutableListOf() }.add(key.replaceFirstChar { it.uppercase() }) + } + } + } + } + + fun library(person: String, destination: String): List = readTitles(people.getValue(person).optJSONArray(destination) ?: JSONArray()) + fun picks(person: String, type: String): List = readTitles(people.getValue(person).getJSONArray("discover")).filter { it.type == type } + fun trending(): List = readTitles(document.getJSONObject("seeAll").getJSONArray("trending")) + fun duplicatePage(): List = readTitles(document.getJSONObject("seeAll").getJSONArray("duplicate")) + + private fun readTitles(array: JSONArray): List = List(array.length()) { index -> + val item = array.getJSONObject(index) + val type = item.getString("type") + val ratings = item.optJSONObject("ratings") + val owners = holders["$type:${item.optString("tmdbId")}"].orEmpty() + val mine = item.optString("availability") == "in_library" + LibraryTitle( + id = item.getString("id"), title = item.getString("title"), type = type, + year = item.optInt("year").takeIf { it > 0 }, runtimeSeconds = item.optLong("runtimeSeconds").takeIf { it > 0 }, + seasons = item.optInt("seasonCount").takeIf { it > 0 }, + poster = item.optString("poster").takeIf { it.isNotBlank() && it != "null" }?.let { posterPrefix + it }, + played = item.optBoolean("played"), progress = item.optDouble("progress", 0.0).toFloat(), + addedAt = item.optString("addedAt"), ratings = buildList { + fun append(source: String, field: String, label: String? = null) { + val score = ratings?.optDouble(field, Double.NaN) ?: Double.NaN + val maximum = if (source.startsWith("rt")) 100 else 10 + if (score.isFinite() && score in 0.0..maximum.toDouble()) add(LibraryRating(source, score, label)) + } + append("rtCritics", "rtCritics", ratings?.optString("rtCriticsLabel")) + append("rtAudience", "rtAudience", ratings?.optString("rtAudienceLabel")) + if (type == "movie" && (ratings?.optInt("imdbVotes", 0) ?: 0) > 0) append("imdb", "imdb") + if (isEmpty() && (ratings?.optInt("tmdbVotes", 0) ?: 0) > 0) append("tmdb", "tmdb") + }, + availability = if (mine) "In your library" else if (owners.isNotEmpty()) "In ${owners.joinToString(" and ")}โ€™s library" else "", + badge = if (mine) "held" else null, + tmdbId = item.optString("tmdbId"), + ) + } +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/LibraryGridState.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/LibraryGridState.kt new file mode 100644 index 00000000..bd36f97f --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/LibraryGridState.kt @@ -0,0 +1,174 @@ +package org.justinvisser.wolfskin.design + +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import androidx.compose.runtime.derivedStateOf +import java.util.Locale +import androidx.compose.runtime.Immutable + +private val leadingArticle = Regex("^(the|a|an)\\s+", RegexOption.IGNORE_CASE) + +/** Art-only card data shared without per-card adapter allocations. */ +@Immutable +interface PosterContent { + val id: String + val posterTitle: String + val posterIsMovie: Boolean + val poster: String? + val ratings: List + val progress: Float + val badge: String? +} + +/** Immutable title facts cross the provider boundary without SDK objects. */ +data class LibraryTitle( + override val id: String, + val title: String, + val type: String, + val year: Int? = null, + val runtimeSeconds: Long? = null, + val seasons: Int? = null, + override val poster: String? = null, + val played: Boolean = false, + override val progress: Float = 0f, + val addedAt: String = "", + override val ratings: List = emptyList(), + val availability: String = "", + override val badge: String? = null, + val tmdbId: String? = null, +) : PosterContent { + override val posterTitle: String get() = title + override val posterIsMovie: Boolean get() = type == "movie" + val sortName: String = title.replace(leadingArticle, "").lowercase(Locale.ROOT) + val catalogueKey: String = "$type:${tmdbId ?: id}" + val letter: Char = sortName.firstOrNull()?.uppercaseChar()?.takeIf { it in 'A'..'Z' } ?: '#' + val leadScore: Double get() = ratings.firstOrNull()?.let { if (it.source.startsWith("rt")) it.score else it.score * 10 } ?: -1.0 + + fun facts(catalogue: Boolean): String = buildList { + year?.let { add(it.toString()) } + add(if (type == "movie") runtimeSeconds?.let { val minutes = (it + 30) / 60; if (minutes >= 60) "${minutes / 60}h ${minutes % 60}m" else "${minutes}m" } ?: "Movie" else seasons?.let { "$it season${if (it == 1) "" else "s"}" } ?: "Series") + if (catalogue) { if (availability.isNotEmpty()) add(availability) } + else if (played) add("Watched") + else if (progress > 0f && runtimeSeconds != null) add("${((runtimeSeconds * (1 - progress) + 30) / 60).toInt().coerceAtLeast(1)} min left") + }.joinToString(" ยท ") +} + +/** Ordered rating entries are formatted after the active TV locale is known. */ +@Immutable +data class LibraryRating(val source: String, val score: Double, val label: String? = null, val episode: Boolean = false) { + fun formatted(locale: Locale = Locale.getDefault()): String = if (source.startsWith("rt")) "${score.toInt()}%" else String.format(locale, "%.1f", score) +} + +enum class LibraryStatus { Ready, Loading, Unavailable } +enum class GridTail { None, Retry, ShowMore } + +/** A grid retains its exact card, toolbar choices and rail return point with the shell view. */ +class LibraryGridState( + val title: String, + items: List, + val catalogue: Boolean = false, + val onTitle: (LibraryTitle) -> Unit = {}, + val onRecover: () -> Unit = {}, + val onDiscover: () -> Unit = {}, + val onReadAhead: (Int) -> Unit = {}, + val observedRatings: MutableSet = mutableSetOf(), +) : ShellContentFocus { + var source by mutableStateOf(items) + var status by mutableStateOf(LibraryStatus.Ready) + var savedAt by mutableStateOf(null) + var sort by mutableStateOf(0) + var unwatched by mutableStateOf(false) + var mediaType by mutableStateOf("all") + var tail by mutableStateOf(GridTail.None) + var pagination: LibraryPagination? = null + var pageRevision by mutableStateOf(0) + var refreshRevision by mutableStateOf(0) + var pointerReentry: (() -> Int?)? = null + var index by mutableStateOf(0) + var toolbar by mutableStateOf(false) + var tool by mutableStateOf(0) + var inRail by mutableStateOf(false) + var railLetter by mutableStateOf('#') + private var railReturn = 0 + val columns = WolfskinTokens.Behaviour.gridColumns.toInt() + val mixed: Boolean get() = catalogue && source.any { it.type == "movie" } && source.any { it.type == "tv" } + val hasToolbar: Boolean get() = !catalogue || mixed + val items: List by derivedStateOf { + val filtered = source.filter { (!unwatched || !it.played) && (mediaType == "all" || it.type == mediaType) } + if (catalogue) filtered else when (sort) { + 1 -> filtered.sortedWith(compareByDescending { it.addedAt }.thenBy { it.sortName }) + 2 -> filtered.sortedWith(compareByDescending { it.leadScore }.thenBy { it.sortName }) + else -> filtered.sortedBy { it.sortName } + } + } + val railVisible: Boolean get() = !catalogue && sort == 0 && items.size >= WolfskinTokens.Behaviour.letterRailMin && status == LibraryStatus.Ready + val tailIndex: Int get() = ((items.size + columns - 1) / columns) * columns + override val hasContent: Boolean get() = status != LibraryStatus.Loading + override val cardKey: String? get() = if (toolbar || inRail || status != LibraryStatus.Ready || items.isEmpty()) null else items.getOrNull(index)?.id ?: "grid-tail" + val focusedTitle: LibraryTitle? get() = if (toolbar || inRail) null else items.getOrNull(index) + + override fun key(key: ShellKey): Boolean { + if (inRail) return railKey(key) + if (key == ShellKey.Back) return false + if (key == ShellKey.Up || key == ShellKey.Down || key == ShellKey.Left || key == ShellKey.Right) { + val reentry = pointerReentry + pointerReentry = null + reentry?.invoke()?.let { index = it; toolbar = false; return true } + } + if (status == LibraryStatus.Loading) return false + if (status == LibraryStatus.Unavailable || (items.isEmpty() && !toolbar)) { + when (key) { + ShellKey.Up -> if (status == LibraryStatus.Ready && hasToolbar) toolbar = true else return false + ShellKey.Ok -> if (status == LibraryStatus.Unavailable) onRecover() else if (unwatched) { unwatched = false; index = 0 } else onDiscover() + else -> Unit + } + return true + } + if (toolbar) return toolbarKey(key) + val currentItems = items + when (key) { + ShellKey.Up -> if (index >= columns) index -= columns else if (hasToolbar) toolbar = true else return false + ShellKey.Down -> when { + index / columns < currentItems.lastIndex / columns -> index = (index + columns).coerceAtMost(currentItems.lastIndex) + tail != GridTail.None && index < tailIndex -> index = tailIndex + } + ShellKey.Left -> if (index % columns > 0) index-- + ShellKey.Right -> if (index % columns < columns - 1 && index < currentItems.lastIndex) index++ else if (railVisible) { inRail = true; railReturn = index; railLetter = currentItems[index].letter } + ShellKey.Ok -> currentItems.getOrNull(index)?.let(onTitle) ?: if (pagination != null) pageRevision++ else onRecover() + } + onReadAhead(index) + return true + } + + private fun toolbarKey(key: ShellKey): Boolean { + val count = if (catalogue) 3 else 2 + when (key) { + ShellKey.Up -> return false + ShellKey.Down -> { toolbar = false; index = index.coerceIn(0, items.lastIndex.coerceAtLeast(0)) } + ShellKey.Left -> tool = (tool - 1).coerceAtLeast(0) + ShellKey.Right -> tool = (tool + 1).coerceAtMost(count - 1) + ShellKey.Ok -> { + if (catalogue) mediaType = listOf("all", "movie", "tv")[tool] + else if (tool == 0) sort = (sort + 1) % 3 else unwatched = !unwatched + index = 0 + } + else -> Unit + } + return true + } + + private fun railKey(key: ShellKey): Boolean { + val letters = items.map { it.letter }.distinct() + when (key) { + ShellKey.Up, ShellKey.Down -> { + val next = (letters.indexOf(railLetter) + if (key == ShellKey.Up) -1 else 1).coerceIn(0, letters.lastIndex) + railLetter = letters[next] + } + ShellKey.Left, ShellKey.Ok -> { index = items.indexOfFirst { it.letter == railLetter }; inRail = false } + ShellKey.Back -> { index = railReturn; inRail = false } + else -> Unit + } + return true + } +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/LibraryPagination.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/LibraryPagination.kt new file mode 100644 index 00000000..dc25fbed --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/LibraryPagination.kt @@ -0,0 +1,36 @@ +package org.justinvisser.wolfskin.design + +import kotlinx.coroutines.CancellationException + +/** Provider pages are merged by title identity; transport pagination is never displayed. */ +data class LibraryPage(val items: List, val hasMore: Boolean) + +/** Duplicate-only reads pause until Show more; failures pause until Try again. */ +class LibraryPagination(private val grid: LibraryGridState, private val load: suspend (Int) -> LibraryPage) { + private var nextPage = 2 + private var hasMore = true + private var reading = false + + suspend fun readAhead(force: Boolean = false) { + if (reading || !hasMore || !force && (grid.tail != GridTail.None || grid.index < grid.items.size - WolfskinTokens.Behaviour.nextPageCards)) return + reading = true + try { + val page = load(nextPage) + val known = grid.source.mapTo(mutableSetOf()) { it.catalogueKey } + val additional = page.items.filter { known.add(it.catalogueKey) } + nextPage++ + hasMore = page.hasMore + if (additional.isEmpty() && page.items.isNotEmpty() && hasMore) grid.tail = GridTail.ShowMore + else { + grid.source = grid.source + additional + grid.tail = GridTail.None + grid.index = grid.index.coerceAtMost(grid.items.lastIndex.coerceAtLeast(0)) + } + } catch (exception: Exception) { + if (exception is CancellationException) throw exception + grid.tail = GridTail.Retry + } finally { + reading = false + } + } +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/LibraryPoster.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/LibraryPoster.kt new file mode 100644 index 00000000..27374461 --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/LibraryPoster.kt @@ -0,0 +1,62 @@ +package org.justinvisser.wolfskin.design + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.ImageBitmap +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.testTag +import coil3.compose.AsyncImage +import org.justinvisser.wolfskin.design.WolfskinTokens.Color as C +import org.justinvisser.wolfskin.design.WolfskinTokens.Library as L + +/** Poster slots use exact requests and share the shell's draw-only focus treatment. */ +@Composable +fun LibraryPoster( + title: PosterContent, + focused: Boolean, + ratingsVisible: Boolean, + catalogue: Boolean, + modifier: Modifier = Modifier, + offlineArt: ((String) -> ImageBitmap?)? = null, +) { + val poster = title.poster + TitleCard(focused, modifier.testTag("poster-${title.id}")) { + val bitmap = remember(poster, offlineArt) { poster?.let { offlineArt?.invoke(it) } } + if (bitmap != null) Image(bitmap, title.posterTitle, Modifier.fillMaxSize(), contentScale = ContentScale.Crop) + else if (poster != null && offlineArt == null) { + var ready by remember(poster) { mutableStateOf(false) } + if (!ready) MediaArtworkFallback(title.posterTitle, title.posterIsMovie) + val context = LocalContext.current + val request = remember(poster, context) { WolfskinImages.request(context, poster, WolfskinTokens.Image.posterRequestWidth, WolfskinTokens.Image.posterRequestHeight, true) } + AsyncImage(request, title.posterTitle, imageLoader = WolfskinImages.loader(context), modifier = Modifier.fillMaxSize(), contentScale = ContentScale.Crop, + onSuccess = { ready = true }, onError = { ready = false }) + } else MediaArtworkFallback(title.posterTitle, title.posterIsMovie) + if (title.ratings.isNotEmpty()) LibraryRatingPlate(title.ratings, visible = ratingsVisible) + val progress = title.progress + if (progress > 0f && progress < 1f) { + Box(Modifier.align(Alignment.BottomCenter).padding(horizontal = WolfskinTokens.Layout.captionOffset, vertical = WolfskinTokens.Layout.navItemGap) + .fillMaxWidth().height(WolfskinTokens.Layout.progressBar).background(C.progressTrack, CircleShape)) { + Box(Modifier.fillMaxHeight().fillMaxWidth(progress).background(C.accent, CircleShape)) + } + } + if (catalogue && title.badge != null) { + val held = title.badge == "held" + val color = if (title.badge == "failed") C.fail else C.accent + Box(Modifier.align(Alignment.BottomEnd).padding(WolfskinTokens.Layout.badgeInset) + .size(WolfskinTokens.Layout.badge).background(if (held) C.ok else C.badgeRest, CircleShape) + .then(if (held) Modifier else Modifier.border(L.badgeRing, color, CircleShape)), contentAlignment = Alignment.Center) { + Glyph(if (held) "check" else if (title.badge == "failed") "alert" else "clock", + if (held) C.onFocus else color, Modifier.size(L.badgeIcon)) + } + } + } +} + + diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/LibraryScreen.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/LibraryScreen.kt new file mode 100644 index 00000000..5394ddf0 --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/LibraryScreen.kt @@ -0,0 +1,263 @@ +package org.justinvisser.wolfskin.design + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.text.buildAnnotatedString +import androidx.compose.ui.text.withStyle +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.ImageBitmap +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.input.pointer.* +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.semantics.stateDescription +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.zIndex +import androidx.tv.material3.Text +import kotlinx.coroutines.delay +import org.justinvisser.wolfskin.design.WolfskinTokens.Color as C +import org.justinvisser.wolfskin.design.WolfskinTokens.Layout as L +import org.justinvisser.wolfskin.design.WolfskinTokens.Library as G +import org.justinvisser.wolfskin.design.WolfskinTokens.Card as K + +/** One lazy frame owns headers, toolbar, continuous poster rows and recoverable tails. */ +@Composable +fun LibraryScreen( + shell: ShellState, + grid: LibraryGridState, + modifier: Modifier = Modifier, + ratingsSignedIn: Boolean = false, + cachedRatings: Set = emptySet(), + ratingsReachable: Boolean = true, + offlineArt: ((String) -> ImageBitmap?)? = null, + view: RememberedView = shell.view, + registerFocus: Boolean = true, +) { + val density = LocalDensity.current + val context = LocalContext.current + val active = !shell.navFocused && !shell.pickerVisible + val items = grid.items + val focused = grid.focusedTitle + val count = if (grid.catalogue) items.size else grid.source.size + var plateKey by remember { mutableStateOf(null) } + DisposableEffect(shell, grid, registerFocus) { + if (registerFocus) shell.contentFocus = grid + onDispose { if (registerFocus && shell.contentFocus === grid) shell.contentFocus = null } + } + LaunchedEffect(grid) { + var revision = grid.pageRevision + snapshotFlow { Triple(grid.index, grid.source.size, grid.pageRevision) }.collect { (_, _, nextRevision) -> + grid.pagination?.readAhead(force = nextRevision != revision) + revision = nextRevision + } + } + LaunchedEffect(grid.index / grid.columns, items, offlineArt) { + if (offlineArt == null) { + val start = (grid.index / grid.columns + 1) * grid.columns + for (index in start until (start + grid.columns).coerceAtMost(items.size)) { + items[index].poster?.let { WolfskinImages.loader(context).enqueue(WolfskinImages.request(context, it, (K.posterW.value * 2).toInt(), (K.posterH.value * 2).toInt(), true)) } + } + } + } + LaunchedEffect(focused?.id, active, ratingsSignedIn, ratingsReachable) { + plateKey = null + if (active && ratingsSignedIn && focused != null && (ratingsReachable || focused.id in cachedRatings || focused.id in grid.observedRatings)) { + if (focused.id !in cachedRatings && focused.id !in grid.observedRatings) delay(WolfskinTokens.Motion.ratingDwell.toLong()) + if (focused.ratings.isNotEmpty()) grid.observedRatings.add(focused.id) + plateKey = focused.id + } + } + LaunchedEffect(grid.savedAt) { view.savedAt = grid.savedAt } + LaunchedEffect(grid.status) { + if (grid.status == LibraryStatus.Loading) shell.focusNav(shell.currentTab) + } + val headerCount = if (grid.hasToolbar && grid.status != LibraryStatus.Loading && grid.status != LibraryStatus.Unavailable) 2 else 1 + val rowHeight = K.posterH + K.posterCaptionBand + L.gridRowGap + LaunchedEffect(grid.index, grid.toolbar, grid.inRail, grid.railLetter, shell.navFocused, view) { + val index = if (grid.inRail) items.indexOfFirst { it.letter == grid.railLetter } else grid.index + val row = index.coerceAtLeast(0) / grid.columns + if (grid.toolbar || row == 0 && active) { + animateLibraryScroll(view, headerCount, 0f, density) + } else if (row > 0) { + val target = with(density) { (L.row_lhead + (if (headerCount == 2) L.row_chips else WolfskinTokens.Shell.zero) + rowHeight * row - L.pinnedLine).toPx() } + animateLibraryScroll(view, headerCount, target, density) + } + } + Box(modifier.semantics { stateDescription = "${grid.title}:${if (grid.toolbar) "tool-${grid.tool}" else if (grid.inRail) "rail-${grid.railLetter}" else focused?.id ?: "recovery"}" }.testTag("library-grid")) { + LazyColumn(state = view.listState, modifier = Modifier.fillMaxSize().pointerInput(grid, headerCount) { + awaitPointerEventScope { + while (true) { + if (awaitPointerEvent().type == PointerEventType.Scroll) grid.pointerReentry = { + val visible = view.listState.layoutInfo.visibleItemsInfo + if (visible.none { it.index == headerCount + grid.index / grid.columns }) { + visible.firstOrNull { it.index >= headerCount }?.let { ((it.index - headerCount) * grid.columns).coerceAtMost(grid.items.lastIndex) } + } else null + } + } + } + }, contentPadding = PaddingValues(bottom = WolfskinTokens.Shell.stageHeight - L.pinnedLine - rowHeight)) { + item(key = "header", contentType = "header") { + LibraryHeader(shell.person, grid.title, + if (grid.status != LibraryStatus.Ready) "" else "$count ${if (grid.catalogue) "titles" else if (grid.title == "Movies") if (count == 1) "film" else "films" else "series"}", + grid.savedAt) + } + if (headerCount == 2) item(key = "toolbar", contentType = "chips") { LibraryToolbar(grid, active) } + when (grid.status) { + LibraryStatus.Loading -> items(3, key = { "skeleton-$it" }, contentType = { "grid" }) { + Box(Modifier.fillMaxWidth().height(rowHeight)) { + Row(Modifier.padding(start = L.safeSide), horizontalArrangement = Arrangement.spacedBy(K.posterGap)) { + repeat(grid.columns) { Box(Modifier.size(K.posterW, K.posterH).background(C.surface, RoundedCornerShape(WolfskinTokens.Radius.card))) } + } + } + } + LibraryStatus.Unavailable -> item(key = "unavailable", contentType = "state") { LibraryRecovery(grid, active) } + LibraryStatus.Ready -> if (items.isEmpty()) item(key = "empty", contentType = "state") { LibraryRecovery(grid, active && !grid.toolbar) } + else { + items((items.size + grid.columns - 1) / grid.columns, key = { row -> "grid-${items[row * grid.columns].id}" }, contentType = { "grid" }) { row -> + Box(Modifier.fillMaxWidth().height(rowHeight)) { + Row(Modifier.padding(start = L.safeSide), horizontalArrangement = Arrangement.spacedBy(K.posterGap)) { + for (column in 0 until grid.columns) { + val index = row * grid.columns + column + val title = items.getOrNull(index) ?: break + key(if (grid.catalogue) title.catalogueKey else title.id) { + val isFocused = active && !grid.toolbar && !grid.inRail && grid.index == index + LibraryPoster(title, isFocused, plateKey == title.id && isFocused, grid.catalogue, + Modifier.zIndex(if (isFocused) 1f else 0f).pointerInput(index, grid) { + awaitPointerEventScope { + while (true) { + val event = awaitPointerEvent() + if ((event.type == PointerEventType.Move || event.type == PointerEventType.Enter) && event.changes.any { it.type == PointerType.Mouse }) { + grid.index = index; grid.toolbar = false; shell.navFocused = false + } + } + } + }.clickable { grid.index = index; grid.toolbar = false; shell.navFocused = false; grid.onTitle(title) }, offlineArt) + } + } + } + if (active && !grid.toolbar && !grid.inRail && grid.index / grid.columns == row) { + val title = items.getOrNull(grid.index) + if (title != null) Caption(title.title, title.facts(grid.catalogue), true, + Modifier.offset(L.safeSide + K.posterPitch * (grid.index % grid.columns), K.posterH + L.captionOffset).width(G.captionWidth), + accentLastFact = if (grid.catalogue) title.availability.isNotEmpty() else title.played || title.progress > 0f) + } + } + } + if (grid.tail != GridTail.None) item(key = "tail", contentType = "grid") { + LibraryTail(grid, active && grid.index == grid.tailIndex) + } + } + } + } + if (grid.railVisible) LibraryRail(grid) + } +} + +/** Library, catalogue and service headers share one baseline and person treatment. */ +@Composable +fun LibraryHeader(person: ShellPerson, title: String, subtitle: String = "", savedAt: String? = null) { + Box(Modifier.fillMaxWidth().height(L.row_lhead)) { + Row(Modifier.offset(L.safeSide, L.navBand), horizontalArrangement = Arrangement.spacedBy(WolfskinTokens.Shell.settingsHeaderGap), verticalAlignment = Alignment.CenterVertically) { + Avatar(person, WolfskinTokens.Shell.settingsHeaderAvatar, WolfskinTokens.Type.avatarLetterLibHeader, letterColor = C.muted) + Text(title, modifier = Modifier.alignByBaseline(), color = C.fg, style = WolfskinTokens.Type.screenTitle) + if (subtitle.isNotEmpty()) Text(subtitle, modifier = Modifier.alignByBaseline(), color = C.muted, style = G.headerSubtitle) + savedAt?.let { SavedPill(it) } + } + } +} + +@Composable +private fun LibraryToolbar(grid: LibraryGridState, active: Boolean) { + Row(Modifier.fillMaxWidth().height(L.row_chips).padding(start = L.safeSide, top = G.chipTop), horizontalArrangement = Arrangement.spacedBy(G.chipGap)) { + val labels = if (grid.catalogue) listOf("All", "Movies", "Series") else listOf("Sort ${listOf("Aโ€“Z", "Recently added", "Rating")[grid.sort]}", if (grid.unwatched) "Unwatched" else "All") + labels.forEachIndexed { index, label -> + val focused = active && grid.toolbar && grid.tool == index + val selected = if (grid.catalogue) listOf("all", "movie", "tv")[index] == grid.mediaType else index == 1 && grid.unwatched + Row(Modifier.height(G.chipHeight).focusScale(focused, WolfskinTokens.Focus.scaleControl) + .background(if (focused) C.fg else if (selected) C.accentSoft else C.chipRest, CircleShape) + .then(if (selected && !focused) Modifier.border(G.borderWidth, C.accent, CircleShape) else Modifier) + .clickable { grid.toolbar = true; grid.tool = index; grid.key(ShellKey.Ok) } + .padding(horizontal = G.chipPadding), horizontalArrangement = Arrangement.spacedBy(G.chipContentGap), verticalAlignment = Alignment.CenterVertically) { + val color = if (focused) C.onFocus else if (selected) C.accentText else C.fg + if (!grid.catalogue) Glyph(if (index == 0) "advanced" else "eye", color, Modifier.size(G.chipIcon)) + if (!grid.catalogue && index == 0) Text(buildAnnotatedString { + withStyle(SpanStyle(color = color.copy(alpha = G.chipLabelOpacity), fontWeight = FontWeight.Medium)) { append("Sort") } + append(" ${listOf("Aโ€“Z", "Recently added", "Rating")[grid.sort]}") + }, color = color, style = WolfskinTokens.Type.label) + else Text(label, color = color, style = WolfskinTokens.Type.label) + } + } + } +} + +@Composable +private fun LibraryRecovery(grid: LibraryGridState, focused: Boolean) { + val lineBoxes = androidx.compose.ui.text.style.LineHeightStyle( + androidx.compose.ui.text.style.LineHeightStyle.Alignment.Center, + androidx.compose.ui.text.style.LineHeightStyle.Trim.None, + ) + val unavailable = grid.status == LibraryStatus.Unavailable + val title = if (unavailable) "Couldnโ€™t reach your library" else if (grid.unwatched) "Nothing unwatched in ${grid.title}" else "Nothing in ${grid.title} yet" + val text = if (unavailable) "Jellyfin isnโ€™t answering. Nothing here is lost; try again in a moment." else if (grid.unwatched) "Everything here has been watched." else "Titles you or others request for you land here." + val button = if (unavailable) "Try again" else if (grid.unwatched) "Show all" else "Open Discover" + Box(Modifier.fillMaxWidth().height(L.row_state).padding(start = L.safeSide, top = G.panelTop)) { + Column(Modifier.width(L.stateWidth).background(C.surface, RoundedCornerShape(WolfskinTokens.Radius.panel)) + .border(G.borderWidth, C.border, RoundedCornerShape(WolfskinTokens.Radius.panel)).padding(G.borderWidth) + .padding(horizontal = G.panelPaddingX, vertical = G.panelPaddingY)) { + Row(horizontalArrangement = Arrangement.spacedBy(G.panelIconGap), verticalAlignment = Alignment.CenterVertically) { + Glyph(if (unavailable) "alert" else if (grid.title == "Movies") "film" else "nextup", if (unavailable) C.warn else C.accentText, Modifier.size(WolfskinTokens.Shell.panelIcon)) + Text(title, color = C.fg, style = WolfskinTokens.Type.stateTitle.copy(fontWeight = FontWeight.Bold, lineHeightStyle = lineBoxes)) + } + Spacer(Modifier.height(G.panelTitleGap)) + Text(text, color = C.muted, style = WolfskinTokens.Type.body.copy(lineHeightStyle = lineBoxes)) + Spacer(Modifier.height(G.panelTextGap)) + PickerButton(button, focused, !unavailable) { grid.key(ShellKey.Ok) } + } + } +} + +@Composable +private fun LibraryTail(grid: LibraryGridState, focused: Boolean) { + val retry = grid.tail == GridTail.Retry + Box(Modifier.fillMaxWidth().height(K.posterH + K.posterCaptionBand + L.gridRowGap)) { + CatalogueRecoveryCard(retry, focused, { grid.index = grid.tailIndex; grid.key(ShellKey.Ok) }, Modifier.offset(L.safeSide)) + Caption(if (retry) "Try again" else "Show more", if (retry) "${grid.title} stopped loading" else "The last read only repeated titles", focused, + Modifier.offset(L.safeSide, K.posterH + L.captionOffset).width(G.captionWidth)) + } +} + +@Composable +private fun BoxScope.LibraryRail(grid: LibraryGridState) { + Column(Modifier.align(Alignment.TopEnd).padding(end = L.safeSide, top = L.navBand).width(G.railWidth)) { + val letters = remember(grid.items) { grid.items.map { it.letter }.toSet() } + for (letter in "#ABCDEFGHIJKLMNOPQRSTUVWXYZ") { + val current = if (grid.inRail) grid.railLetter == letter else grid.focusedTitle?.letter == letter + Box(Modifier.width(G.railWidth).height(if (current && grid.inRail) G.railFocusHeight else G.railLetterHeight) + .background(if (current && grid.inRail) C.fg else androidx.compose.ui.graphics.Color.Transparent, CircleShape) + .clickable(enabled = letter in letters) { grid.railLetter = letter; grid.inRail = true; grid.key(ShellKey.Ok) }, contentAlignment = Alignment.Center) { + Text(letter.toString(), color = if (current) if (grid.inRail) C.onFocus else C.accent else if (letter in letters) C.muted else C.railEmpty, + style = if (current && grid.inRail) G.railFocusedLetter else G.railLetter) + } + } + } +} + +private suspend fun animateLibraryScroll(view: RememberedView, headerCount: Int, target: Float, density: androidx.compose.ui.unit.Density) { + val rowHeight = K.posterH + K.posterCaptionBand + L.gridRowGap + val first = view.listState.firstVisibleItemIndex + val current = with(density) { + (if (first == 0) WolfskinTokens.Shell.zero else L.row_lhead + + if (first < headerCount) WolfskinTokens.Shell.zero else + (if (headerCount == 2) L.row_chips else WolfskinTokens.Shell.zero) + rowHeight * (first - headerCount)).toPx() + } + view.listState.firstVisibleItemScrollOffset + animateFrameScroll(view.listState, target - current) +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/LibrarySeeAllCard.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/LibrarySeeAllCard.kt new file mode 100644 index 00000000..0dabee9b --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/LibrarySeeAllCard.kt @@ -0,0 +1,30 @@ +package org.justinvisser.wolfskin.design + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.unit.Dp +import androidx.tv.material3.Text + +/** Shelves expose the full underlying list without displaying transport pagination. */ +@Composable +fun LibrarySeeAllCard(count: Int, focused: Boolean, onClick: () -> Unit, modifier: Modifier = Modifier, + width: Dp = WolfskinTokens.Card.posterW, height: Dp = WolfskinTokens.Card.posterH, + titleStyle: TextStyle = WolfskinTokens.Type.listTitle, countStyle: TextStyle = WolfskinTokens.Type.label) { + val shape = RoundedCornerShape(WolfskinTokens.Radius.card) + TitleCard(focused, modifier.clickable(onClick = onClick), width, height) { + Column(Modifier.fillMaxSize().background(WolfskinTokens.Color.surface, shape) + .border(WolfskinTokens.Library.borderWidth, WolfskinTokens.Color.border, shape), + verticalArrangement = Arrangement.spacedBy(WolfskinTokens.Library.seeAllGap, Alignment.CenterVertically), horizontalAlignment = Alignment.CenterHorizontally) { + Glyph("interface", WolfskinTokens.Color.accent, Modifier.size(WolfskinTokens.Layout.badge)) + Text("See all", modifier = Modifier.exactLineBox(titleStyle), color = WolfskinTokens.Color.fg, style = titleStyle) + Text(count.toString(), modifier = Modifier.exactLineBox(countStyle), color = WolfskinTokens.Color.muted, style = countStyle) + } + } +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/NavBar.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/NavBar.kt new file mode 100644 index 00000000..9042e3fe --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/NavBar.kt @@ -0,0 +1,119 @@ +package org.justinvisser.wolfskin.design + +import androidx.compose.animation.animateColorAsState +import androidx.compose.animation.core.animateFloatAsState +import androidx.compose.animation.core.CubicBezierEasing +import androidx.compose.animation.core.tween +import androidx.compose.animation.core.spring +import androidx.compose.foundation.Canvas +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.size +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.focusProperties +import androidx.compose.ui.geometry.CornerRadius +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.geometry.Size +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.unit.Dp +import androidx.tv.material3.Text +import org.justinvisser.wolfskin.design.WolfskinTokens.Color as C +import org.justinvisser.wolfskin.design.WolfskinTokens.Layout as L +import org.justinvisser.wolfskin.design.WolfskinTokens.Shell as S +import org.justinvisser.wolfskin.design.WolfskinTokens.SavedIndicator as V + +/** Blob bounds retain their measurement while their draw coordinates spring between targets. */ +data class NavBox(val left: Dp, val top: Dp, val width: Dp, val height: Dp) + +fun navBoxes(tabs: List): List { + var left = L.safeSide + S.wordmarkWidth + L.wordmarkGap + L.navItemGap + return tabs.map { tab -> + val width = when (tab) { + "home" -> S.navHomeWidth + "discover" -> S.navDiscoverWidth + "movies" -> S.navMoviesWidth + "shows" -> S.navShowsWidth + else -> S.navAnimeWidth + } + NavBox(left, S.navItemTop, width, L.navItemHeight).also { left += width + L.navItemGap } + } + NavBox(S.stageWidth - L.safeSide - L.navAvatar, S.navItemTop, L.navAvatar, L.navAvatar) +} + +/** There is one blob, including when focus wraps around the nav avatar. */ +@Composable +fun NavBar(state: ShellState, scrolled: Boolean, modifier: Modifier = Modifier) { + val boxes = remember(state.person.hasAnime) { navBoxes(state.tabs) } + val labelFade = remember { tween(S.navLabelFade, easing = CubicBezierEasing(0f, 0f, .58f, 1f)) } + val index = if (state.navFocused) state.navIndex else state.currentTab + val box = boxes[index] + val avatarFocused = state.navFocused && index == state.tabs.size + val pad = if (avatarFocused) L.navBlobAvatarPad else S.zero + val damping = WolfskinTokens.Motion.navBlobDampingRatio + val stiffness = WolfskinTokens.Motion.navBlobStiffness + val x by animateFloatAsState((box.left - pad).value, spring(damping, stiffness), label = "blob-x") + val y by animateFloatAsState((box.top - pad).value, spring(damping, stiffness), label = "blob-y") + val width by animateFloatAsState((box.width + pad * 2).value, spring(damping, stiffness), label = "blob-width") + val height by animateFloatAsState((box.height + pad * 2).value, spring(damping, stiffness), label = "blob-height") + val color by animateColorAsState(if (state.navFocused) C.fg else C.navBlobRest, spring(damping, stiffness), label = "blob-color") + val density = LocalDensity.current.density + val band = remember(scrolled) { + if (scrolled) Brush.verticalGradient(0f to C.bg, S.navSolidStop to C.bg, 1f to C.bg.copy(alpha = 0f)) + else Brush.verticalGradient(listOf(C.bg.copy(alpha = S.navBandOpacity), C.bg.copy(alpha = 0f))) + } + Box(modifier.fillMaxWidth().height(L.navBand)) { + Canvas(Modifier.matchParentSize()) { + drawRect(band) + drawRoundRect(color, Offset(x * density, y * density), Size(width * density, height * density), CornerRadius(height * density / 2)) + } + Wordmark(Modifier.offset(L.safeSide, S.wordmarkTop)) + state.tabs.forEachIndexed { itemIndex, tab -> + val item = boxes[itemIndex] + val focused = state.navFocused && state.navIndex == itemIndex + val labelColor by animateColorAsState( + if (focused) C.onFocus else if (itemIndex == state.currentTab) C.fg else C.muted, + animationSpec = labelFade, + label = "nav-label-$tab", + ) + Box(Modifier.offset(item.left, item.top).size(item.width, item.height) + .focusProperties { canFocus = false } + .clickable { + state.focusNav(itemIndex); state.key(ShellKey.Ok) + }, contentAlignment = Alignment.Center) { + Text(tab.replaceFirstChar { it.uppercase() }, style = WolfskinTokens.Type.nav, color = labelColor) + if (itemIndex == state.currentTab && !focused) { + Box(Modifier.align(Alignment.BottomCenter).offset(y = -L.navUnderline).size(item.width - L.navItemPaddingX * 2, L.navUnderline).background(C.accent)) + } + } + } + state.navSavedAt?.let { time -> + Row(Modifier.align(Alignment.TopEnd) + .offset(x = -(L.safeSide + L.navAvatar + L.navItemGap), y = S.navItemTop + (L.navAvatar - V.height) / 2) + .height(V.height).border(V.border, C.warn.copy(alpha = V.borderOpacity), RoundedCornerShape(WolfskinTokens.Radius.button)) + .padding(horizontal = V.side + V.border), horizontalArrangement = Arrangement.spacedBy(V.gap), verticalAlignment = Alignment.CenterVertically) { + Glyph("wifi", C.warn, Modifier.size(V.icon)) + Text("Saved $time", color = C.warn, style = WolfskinTokens.Type.caption) + } + } + val avatar = boxes.last() + Avatar(state.person, L.navAvatar, WolfskinTokens.Type.avatarLetterNav, + Modifier.offset(avatar.left, avatar.top) + .focusRing(avatarFocused, L.navAvatar / 2, WolfskinTokens.Focus.ringAvatarGap, WolfskinTokens.Focus.ringAvatarRing, C.fg) + .focusProperties { canFocus = false } + .clickable { state.focusNav(state.tabs.size); state.key(ShellKey.Ok) }) + } +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/PersonPage.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/PersonPage.kt new file mode 100644 index 00000000..011a1d70 --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/PersonPage.kt @@ -0,0 +1,158 @@ +package org.justinvisser.wolfskin.design + +import androidx.compose.foundation.background +import androidx.compose.foundation.focusable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.foundation.gestures.animateScrollBy +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.input.key.KeyEventType +import androidx.compose.ui.input.key.onPreviewKeyEvent +import androidx.compose.ui.input.key.type +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.semantics.stateDescription +import androidx.tv.material3.Text +import org.justinvisser.wolfskin.design.WolfskinTokens.Color as C +import org.justinvisser.wolfskin.design.WolfskinTokens.Layout as L +import org.justinvisser.wolfskin.design.WolfskinTokens.Title as D + +/** Filmography retains a real credit key and requests more credits before focus reaches the tail. */ +class PersonState(initialPerson: TitlePerson, initialCredits: List, private val onAction: (TitleAction) -> Unit, private val onReadMore: () -> Unit = {}) { + var person by mutableStateOf(initialPerson) + private set + var credits by mutableStateOf(initialCredits) + var savedAt by mutableStateOf(null) + var toast by mutableStateOf(null) + fun update(actor: TitlePerson, titles: List, saved: String? = null) { + person = actor; credits = titles; savedAt = saved + index = index.coerceAtMost((credits.size - 1).coerceAtLeast(0)) + } + var index by mutableStateOf(0) + private var armed: String? = null + + /** Pointer activation and remote key-up open the same selected credit. */ + fun click(position: Int) { index = position; onAction(TitleAction.OpenTitle(credits[index])) } + + /** The first grid row exits upward into the existing shell nav. */ + fun key(key: ShellKey, down: Boolean, repeat: Int, shell: ShellState): Boolean { + if (credits.isEmpty()) { + if (down && key == ShellKey.Back) onAction(TitleAction.Pop) + else if (down && key == ShellKey.Up) shell.focusNav(shell.currentTab) + return true + } + val columns = WolfskinTokens.Behaviour.gridColumns.toInt() + if (key == ShellKey.Ok) { + if (repeat > 0) return true + if (down) armed = credits[index].id else { if (armed == credits[index].id) click(index); armed = null } + return true + } + if (!down) return true + armed = null + when (key) { + ShellKey.Back -> onAction(TitleAction.Pop) + ShellKey.Up -> if (index < columns) shell.focusNav(shell.currentTab) else index -= columns + ShellKey.Down -> if (index / columns < credits.lastIndex / columns) index = (index + columns).coerceAtMost(credits.lastIndex) + ShellKey.Left -> if (index % columns > 0) index-- + ShellKey.Right -> if (index % columns < columns - 1 && index < credits.lastIndex) index++ + else -> Unit + } + if (index >= credits.size - WolfskinTokens.Behaviour.nextPageCards.toInt()) onReadMore() + return true + } +} + +/** Portrait, biography and the full continuous grid use the shell's remembered frame. */ +@Composable +fun PersonSurface(state: PersonState, shell: ShellState, modifier: Modifier = Modifier) { + val view = shell.view + LaunchedEffect(view, state.savedAt) { view.savedAt = state.savedAt } + val owner = androidx.compose.runtime.remember(shell) { { shell.navFocused = false } } + LaunchedEffect(state) { shell.navFocused = false } + Box(modifier.fillMaxSize().background(C.bg)) { + androidx.compose.runtime.CompositionLocalProvider(LocalTitleFocusOwner provides owner) { + ShellSurface(shell, handlesContentKeys = false) { PersonPage(state, shell, it) } + } + if (!shell.pickerVisible) TitleNotice(state.toast, Modifier.align(Alignment.TopEnd)) { state.toast = null } + } +} + +@Composable +private fun PersonPage(state: PersonState, shell: ShellState, modifier: Modifier = Modifier) { + val density = LocalDensity.current + val list = shell.view.listState + var wheelPending by remember { mutableStateOf(false) } + val columns = WolfskinTokens.Behaviour.gridColumns.toInt() + LaunchedEffect(state.index / columns, shell.navFocused) { + val target = if (shell.navFocused || state.index < columns) 0f + else with(density) { (L.row_phead + L.row_gh + D.gridHeight * (state.index / columns) - L.pinnedLine).toPx() } + val first = list.firstVisibleItemIndex + val before = when (first) { + 0 -> WolfskinTokens.Shell.zero + 1 -> L.row_phead + else -> L.row_phead + L.row_gh + D.gridHeight * (first - 2) + } + val current = with(density) { before.toPx() } + list.firstVisibleItemScrollOffset + if (target != current) list.animateScrollBy(target - current, titleFrameScrollSpec) + } + Box(modifier.testTag("person-page").semantics { stateDescription = "${state.person.id}:${state.index}" } + .titleWheel { wheelPending = true; shell.navFocused = false } + .onPreviewKeyEvent { event -> + val key = readShellKey(event) + if (key != null && key != ShellKey.Back && event.type == KeyEventType.KeyDown && wheelPending) { + val visible = list.layoutInfo.visibleItemsInfo.firstOrNull { it.index >= 2 && it.key != "end-padding" && it.offset + it.size > with(density) { L.pinnedLine.roundToPx() } } + state.index = ((visible?.index?.minus(2) ?: 0) * columns).coerceAtMost((state.credits.size - 1).coerceAtLeast(0)) + wheelPending = false + if (key != ShellKey.Ok) return@onPreviewKeyEvent true + } + key?.let { state.key(it, event.type == KeyEventType.KeyDown, event.nativeKeyEvent.repeatCount, shell) } ?: false + }.focusable()) { + LazyColumn(state = list, modifier = Modifier.fillMaxSize()) { + item(key = "person-header", contentType = "header") { + Box(Modifier.height(L.row_phead)) { + Row(Modifier.offset(L.safeSide, D.personTop), horizontalArrangement = Arrangement.spacedBy(D.personGap), verticalAlignment = Alignment.CenterVertically) { + PersonPortrait(state.person, Modifier.size(L.personPortrait).clip(CircleShape), true) + Column(Modifier.width(L.contentWidth - L.personPortrait - D.personGap)) { + Text(state.person.name, color = C.fg, style = TitleTextStyles.screenTitle, modifier = Modifier.padding(bottom = D.personNameBottom)) + Text("Acting ยท ${state.credits.size} credit${if (state.credits.size == 1) "" else "s"} among this householdโ€™s titles", color = C.muted, style = TitleTextStyles.body) + if (state.person.biography.isNotBlank()) Text(state.person.biography, color = C.dim, style = TitleTextStyles.caption, maxLines = 3) + } + } + } + } + item(key = "filmography", contentType = "header") { + Text("Filmography", color = C.fg, style = TitleTextStyles.rowHeading, modifier = Modifier.height(L.row_gh).padding(start = L.safeSide, top = D.gridHeadingTop)) + } + itemsIndexed(state.credits.chunked(columns), key = { _, row -> row.first().id }, contentType = { _, _ -> "grid" }) { rowIndex, row -> + Row(Modifier.height(D.gridHeight).padding(horizontal = L.safeSide), horizontalArrangement = Arrangement.spacedBy(WolfskinTokens.Card.posterGap)) { + row.forEachIndexed { column, item -> + val index = rowIndex * columns + column + TitlePoster(item, index == state.index && !shell.navFocused, Modifier.width(WolfskinTokens.Card.posterW), catalogue = true, onFocus = { state.index = index }) { state.click(index) } + } + } + } + item(key = "end-padding", contentType = "spacer") { Spacer(Modifier.height(WolfskinTokens.Shell.stageHeight - L.pinnedLine - D.gridHeight)) } + } + } +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/RecoveryToast.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/RecoveryToast.kt new file mode 100644 index 00000000..3e8dd23c --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/RecoveryToast.kt @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0-only +package org.justinvisser.wolfskin.design + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.dropShadow +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.shadow.Shadow +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.unit.DpOffset +import androidx.tv.material3.Text +import org.justinvisser.wolfskin.design.WolfskinTokens.Color as C +import org.justinvisser.wolfskin.design.WolfskinTokens.Home as H +import org.justinvisser.wolfskin.design.WolfskinTokens.Layout as L + +/** Recovery messages remain transient and never take focus from the action that failed. */ +@Composable +fun RecoveryToast(message: String, modifier: Modifier = Modifier) { + Box(modifier.fillMaxSize()) { + val shape = androidx.compose.runtime.remember { RoundedCornerShape(WolfskinTokens.Radius.panel) } + Row(Modifier.align(Alignment.TopEnd).offset(-L.safeSide, H.toastTop) + .widthIn(max = H.toastWidth) + .dropShadow(shape, Shadow(radius = H.toastShadowBlur, color = Color.Black.copy(alpha = H.toastShadowOpacity), + offset = DpOffset(WolfskinTokens.Shell.zero, H.toastShadowY))) + .background(C.surface2, shape) + .testTag("recovery-toast") + .padding(horizontal = H.toastPadding, vertical = H.toastPaddingY), + horizontalArrangement = Arrangement.spacedBy(H.toastGap), verticalAlignment = Alignment.CenterVertically) { + Glyph("alert", C.warn, Modifier.size(L.buttonIcon)) + Text(message, Modifier.weight(1f, fill = false).exactLineBox(HomeType.body), color = C.fg, style = HomeType.body) + } + } +} + +/** Shared wording is independent of transport details and never exposes exception text. */ +object RecoveryMessage { + const val StillUnreachable = "Still canโ€™t reach it. The last saved view stays on screen." + const val PlaybackUnavailable = "Canโ€™t reach Jellyfin to play. Check the network and try again." +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/RequestSheetState.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/RequestSheetState.kt new file mode 100644 index 00000000..6e9bd517 --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/RequestSheetState.kt @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: GPL-2.0-only +package org.justinvisser.wolfskin.design + +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue + +/** Overlay focus is independent of the screen below and never reaches the navigation bar. */ +sealed interface DiscoverOverlayState { + class Request(val state: RequestSheetState) : DiscoverOverlayState + class Hidden(val title: DiscoverTitle) : DiscoverOverlayState { var focus by mutableStateOf(0) } + class Restore(val title: DiscoverTitle) : DiscoverOverlayState { var focus by mutableStateOf(0) } +} + +/** Request selection cannot supply an actor and cannot submit an unknown-season series. */ +class RequestSheetState( + val title: DiscoverTitle, + val viewer: ShellPerson, + people: List, + other: Boolean, + initialPhase: RequestPhase = RequestPhase.Choose, +) { + val people = listOf(viewer) + people.filter { it.key != viewer.key } + val held = viewer.key in title.heldBy + val blocked = title.type == "tv" && !held && title.seasons.isNullOrEmpty() + val buttonIndex = this.people.size + var selected by mutableStateOf(if (other || held) this.people.indexOfFirst { it.key != viewer.key && it.key !in title.heldBy }.coerceAtLeast(0) else 0) + var phase by mutableStateOf(initialPhase) + var focus by mutableStateOf(if (initialPhase != RequestPhase.Choose || blocked || !other) buttonIndex else selected) + var result by mutableStateOf(null) + val selectedPerson: ShellPerson get() = people[selected] + val canSubmit: Boolean get() = phase == RequestPhase.Choose && !blocked && selectedPerson.key !in title.heldBy + val buttonLabel: String get() = when { + held -> "Add to ${selectedPerson.name}โ€™s library" + selectedPerson.key == viewer.key -> "Request" + else -> "Request for ${selectedPerson.name}" + } + + fun key(key: ShellKey, send: (RequestSheetState, Boolean) -> Unit, close: () -> Unit, retryRecipients: () -> Unit) { + if (key == ShellKey.Back) { close(); return } + when (phase) { + RequestPhase.Choose -> { + val order = people.indices.filter { people[it].key !in title.heldBy } + buttonIndex + val index = order.indexOf(focus) + when (key) { + ShellKey.Up -> focus = order[(index - 1).coerceAtLeast(0)] + ShellKey.Down -> focus = order[(index + 1).coerceAtMost(order.lastIndex)] + ShellKey.Ok -> if (focus == buttonIndex) { if (blocked) close() else if (canSubmit) send(this, false) } + else { selected = focus; focus = buttonIndex } + else -> Unit + } + } + RequestPhase.Sending -> Unit + RequestPhase.LoadingRecipients -> if (key == ShellKey.Ok) close() + RequestPhase.Receipt, RequestPhase.Refused -> if (key == ShellKey.Ok) close() + RequestPhase.NotConfirmed, RequestPhase.Pending, RequestPhase.RecipientsUnavailable -> { + when (key) { + ShellKey.Left, ShellKey.Up -> focus = buttonIndex + ShellKey.Right, ShellKey.Down -> focus = buttonIndex + 1 + ShellKey.Ok -> if (focus != buttonIndex) close() else if (phase == RequestPhase.RecipientsUnavailable) retryRecipients() else send(this, true) + else -> Unit + } + } + } + } +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/SavedPill.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/SavedPill.kt new file mode 100644 index 00000000..48cea4fa --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/SavedPill.kt @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0-only +package org.justinvisser.wolfskin.design + +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.tv.material3.Text +import org.justinvisser.wolfskin.design.WolfskinTokens.Color as C +import org.justinvisser.wolfskin.design.WolfskinTokens.Home as H +import org.justinvisser.wolfskin.design.WolfskinTokens.Shell as S + +/** Headers identify a retained copy without becoming a separate focus target. */ +@Composable +fun SavedPill(time: String, modifier: Modifier = Modifier) { + Box(modifier.height(S.settingsPillHeight) + .border(H.hairline, C.warn.copy(alpha = .45f), RoundedCornerShape(WolfskinTokens.Radius.pill)) + .padding(horizontal = S.settingsPillPadding + H.hairline), contentAlignment = Alignment.Center) { + Text("Saved $time", color = C.warn, style = HomeType.caption.copy(fontWeight = HomeType.label.fontWeight)) + } +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/SettingsList.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/SettingsList.kt new file mode 100644 index 00000000..48a8220b --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/SettingsList.kt @@ -0,0 +1,128 @@ +package org.justinvisser.wolfskin.design + +import androidx.compose.animation.core.CubicBezierEasing +import androidx.compose.animation.core.tween +import androidx.compose.foundation.gestures.animateScrollBy +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.drawWithCache +import androidx.compose.ui.geometry.CornerRadius +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.geometry.Size +import androidx.compose.ui.graphics.PathEffect +import androidx.compose.ui.graphics.drawscope.Stroke +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextOverflow +import androidx.tv.material3.Text +import org.justinvisser.wolfskin.design.WolfskinTokens.Color as C +import org.justinvisser.wolfskin.design.WolfskinTokens.Layout as L +import org.justinvisser.wolfskin.design.WolfskinTokens.Shell as S + +/** Settings routes identify real upstream destinations rather than stand-in panels. */ +data class SettingsGroup(val key: String, val title: String, val description: String, val wolfskin: Boolean = false) + +val SETTINGS_GROUPS = listOf( + SettingsGroup("requests", "Requests", "Coming in: what the household asked for, and how far each is"), + SettingsGroup("interface", "Interface", "Sign in automatically ยท Remember selected tabs ยท Theme music ยท Subtitle style ยท Application theme ยท Screensaver"), + SettingsGroup("playback", "Playback", "Skip forward ยท Skip back ยท Skip back when resuming"), + SettingsGroup("nextup", "Next up", "Show next up timing ยท Auto play next up ยท Delay ยท Passout protection"), + SettingsGroup("profile", "User profile settings", "Profile protection ยท Customize home page (Wolfskin presets: Default, Compact, Series thumbs, Episode thumbnails) ยท Navigation drawer items ยท Language", true), + SettingsGroup("about", "About", "Installed version ยท Update (Wolfskin releases on Forgejo) ยท Wolfskin about", true), + SettingsGroup("seerr", "Seerr integration", "Add, change or remove the Seerr server this TV asks for Discover and ratings", true), + SettingsGroup("advanced", "Advanced settings", "Ratings display ยท Backdrop style ยท Playback backend (ExoPlayer, MPV) ยท Max resolution and bitrate ยท Skip segments ยท Logs and image cache"), +) + +/** The household request count shares the sheet's snapshot and excludes Ready. */ +@Composable +fun SettingsList(state: ShellState, modifier: Modifier = Modifier, openRequests: Int? = null) { + val list = state.view.listState + val density = LocalDensity.current + LaunchedEffect(state.settingsRow, state.navFocused) { + if (state.navFocused) return@LaunchedEffect + val y = L.row_lhead + L.row_srow * state.settingsRow + val target = if (y >= L.windowAhead) y - L.pinnedLine else S.zero + val current = if (list.firstVisibleItemIndex == 0) S.zero else L.row_lhead + L.row_srow * (list.firstVisibleItemIndex - 1) + val distance = with(density) { (target - current).toPx() } - list.firstVisibleItemScrollOffset + list.animateScrollBy(distance, tween(WolfskinTokens.Motion.scroll, easing = CubicBezierEasing(.33f, 1f, .68f, 1f))) + } + LazyColumn(modifier.fillMaxSize(), state = list, + contentPadding = PaddingValues(bottom = S.stageHeight - L.pinnedLine - L.row_srow)) { + item(key = "settings-header") { + Row(Modifier.height(L.row_lhead).padding(start = L.safeSide, top = S.settingsHeaderTop), + verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(S.settingsHeaderGap)) { + Avatar(state.person, S.settingsHeaderAvatar, WolfskinTokens.Type.avatarLetterLibHeader, letterColor = C.muted) + Text("Settings", Modifier.alignByBaseline(), style = WolfskinTokens.Type.screenTitle, color = C.fg) + Text("Requests and Wholphin settings on this TV ยท ${state.person.name}", Modifier.alignByBaseline(), style = WolfskinTokens.Type.nav.copy(fontWeight = FontWeight.Normal), color = C.muted) + } + } + itemsIndexed(SETTINGS_GROUPS, key = { _, group -> group.key }) { index, group -> + Box(Modifier.height(L.row_srow)) { + SettingsRow(group, !state.navFocused && !state.requestsVisible && index == state.settingsRow, + if (group.key == "requests") openRequests else null, + Modifier.offset(L.safeSide, S.settingsRowTop)) { + state.navFocused = false; state.settingsRow = index; state.key(ShellKey.Ok) + } + } + } + } +} + +/** The inverse focus fill has no focus ring and never changes row layout. */ +@Composable +fun SettingsRow(group: SettingsGroup, focused: Boolean, openRequests: Int?, modifier: Modifier = Modifier, onClick: () -> Unit) { + val foreground = if (focused) C.onFocus else C.fg + Row(modifier.size(L.settingsRowWidth, L.settingsRowHeight).focusScale(focused, WolfskinTokens.Focus.scaleRow) + .background(if (focused) C.fg else C.listRowRest, RoundedCornerShape(WolfskinTokens.Radius.listRow)) + .clickable(onClick = onClick).padding(horizontal = S.settingsRowPadding), + verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(S.settingsRowGap)) { + Glyph(group.key, if (focused) C.onFocus else C.accentText, Modifier.size(S.settingsIcon)) + Column(Modifier.weight(1f)) { + val count = if (openRequests != null && openRequests > 0) " ยท $openRequests open" else "" + Text(group.title + count, color = foreground, style = WolfskinTokens.Type.listTitle, maxLines = 1) + Text(group.description, color = if (focused) C.onFocus else C.muted, style = WolfskinTokens.Type.caption, maxLines = 1, overflow = TextOverflow.Ellipsis) + } + if (group.wolfskin) SettingsPill("Wolfskin", focused) + SettingsPill(if (group.key == "requests") "Wolfskin screen" else "upstream screen", focused) + Glyph("right", if (focused) C.onFocus else C.accentText, Modifier.size(S.settingsChevron)) + } +} + +@Composable +private fun SettingsPill(label: String, focused: Boolean) { + val foreground = if (focused) C.onFocus else C.dim + val border = if (focused) S.settingsPillFocusedBorder else S.settingsPillBorder + Box(Modifier.height(S.settingsPillHeight).drawWithCache { + val stroke = S.settingsPillStroke.toPx() + val inset = Offset(stroke / 2, stroke / 2) + val bounds = Size(size.width - stroke, size.height - stroke) + val outline = Stroke(stroke, pathEffect = PathEffect.dashPathEffect( + floatArrayOf(stroke * S.settingsPillDashRatio, stroke * S.settingsPillDashGapRatio), + )) + val radius = CornerRadius(WolfskinTokens.Radius.pill.toPx()) + onDrawBehind { + drawRoundRect(border, topLeft = inset, size = bounds, cornerRadius = radius, style = outline) + } + }.padding(horizontal = S.settingsPillPadding + S.settingsPillStroke), contentAlignment = Alignment.Center) { + Text(label, color = foreground, style = WolfskinTokens.Type.caption.copy(fontWeight = WolfskinTokens.Type.label.fontWeight)) + } +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/ShellState.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/ShellState.kt new file mode 100644 index 00000000..3ea05c55 --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/ShellState.kt @@ -0,0 +1,287 @@ +package org.justinvisser.wolfskin.design + +import androidx.compose.foundation.lazy.LazyListState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateMapOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue + +/** Household identity data contains no credentials or server objects. */ +data class ShellPerson(val key: String, val name: String, val initial: String, val hasAnime: Boolean) + +/** The shell owns keys; the integration owns navigation and authenticated user changes. */ +sealed interface ShellAction { + data class Destination(val route: String) : ShellAction + data class Person(val person: ShellPerson) : ShellAction + data class HandOff(val group: String) : ShellAction + data object Pop : ShellAction + data object RetryPeople : ShellAction + data object RetryRequests : ShellAction + data class RequestTitle(val request: ComingInRequest) : ShellAction +} + +/** D-pad inputs are shared by Android events and deterministic JVM replays. */ +enum class ShellKey { Up, Down, Left, Right, Ok, Back } +enum class PeopleStatus { Ready, Loading, Unavailable } + +/** Screens participate in the shell's hold guard and Back ladder without a second key adapter. */ +interface ShellContentFocus { + val hasContent: Boolean get() = true + val cardKey: String? + fun key(key: ShellKey): Boolean +} + +/** A root destination retains focus, horizontal tracks and its actual Compose scroller. */ +class RememberedView { + val listState = LazyListState() + var row by mutableStateOf(0) + val cards = mutableStateMapOf() + var savedAt by mutableStateOf(null) + val home by lazy { HomeViewMemory() } + var library: LibraryGridState? = null +} + +/** Focus and Back transitions are independent of drawing and server availability. */ +class ShellState( + val people: List, + initialPerson: String, + private val onAction: (ShellAction) -> Unit = {}, +) { + var person by mutableStateOf(people.firstOrNull { it.key == initialPerson } ?: people.first()) + private set + var route by mutableStateOf("home") + private set + var pickerVisible by mutableStateOf(true) + var pickerLaunch by mutableStateOf(true) + var pickerIndex by mutableStateOf(people.indexOf(person)) + var gearFocused by mutableStateOf(false) + var navFocused by mutableStateOf(false) + var navIndex by mutableStateOf(0) + var peopleStatus by mutableStateOf(PeopleStatus.Ready) + var recoveryIndex by mutableStateOf(0) + var requestsVisible by mutableStateOf(false) + var toast by mutableStateOf(null) + private val personRequests = mutableMapOf() + val requests: ComingInState get() = personRequests.getOrPut(person.key) { ComingInState() } + private var requestReturnRoute: String? = null + var handOff by mutableStateOf(null) + var settingsRow by mutableStateOf(0) + var contentOverlayVisible by mutableStateOf(false) + private var rootRoute by mutableStateOf("home") + private var pickerReturnRoute = "home" + private val views = mutableStateMapOf, RememberedView>() + private var armedCard: String? = null + var contentFocus: ShellContentFocus? = null + var inputRevision = 0L + private set + val tabs: List get() = if (person.hasAnime) ANIME_TABS else BASE_TABS + val currentTab: Int get() = tabs.indexOf(rootRoute).coerceAtLeast(0) + val view: RememberedView get() = rememberedView(route) + val navSavedAt: String? get() = if (requestsVisible && requests.snapshot.status == ComingInStatus.Unavailable) requests.snapshot.savedAt ?: view.savedAt else view.savedAt + + /** Screen options share the same per-person memory as their root's focus and scroller. */ + fun rememberedView(destination: String): RememberedView = + views.getOrPut(person.key to destination) { RememberedView() } + + /** External intents and upstream pops remain authoritative over the screen. */ + fun enterDestination(destination: String) { + route = destination + if (destination in tabs) rootRoute = destination + handOff = null + if (requestReturnRoute == destination) { + requestsVisible = true + requestReturnRoute = null + } + } + + /** Pointer navigation uses the same transitions as D-pad selection. */ + fun focusNav(index: Int) { inputRevision++; navIndex = index; navFocused = true } + fun focusPerson(index: Int) { inputRevision++; pickerIndex = index; gearFocused = false } + + /** Repeats are consumed, and a row activation is cancelled when focus moves. */ + fun key(key: ShellKey, down: Boolean = true, repeat: Int = 0, card: String? = if (!pickerVisible && !navFocused && !requestsVisible && !contentOverlayVisible) contentFocus?.cardKey else null): Boolean { + if (down) inputRevision++ + if (key == ShellKey.Ok && repeat > 0) return true + if (!pickerVisible && !requestsVisible && contentOverlayVisible) { + if (down) contentFocus?.key(key) + return true + } + if (key == ShellKey.Ok) { + if (card != null) { + if (down) armedCard = card else { + if (armedCard == card) activate() + armedCard = null + } + return true + } + if (!down) return true + } else { + if (!down) return true + armedCard = null + } + if (requestsVisible) { + when { + key == ShellKey.Back -> closeRequests() + key == ShellKey.Ok && requests.snapshot.status == ComingInStatus.Unavailable && (requests.snapshot.items.isEmpty() || requests.recoveryFocused) -> retryRequests() + key == ShellKey.Ok && requests.snapshot.status == ComingInStatus.Loading && requests.snapshot.items.isEmpty() -> closeRequests() + requests.key(key) -> activateRequest() + } + return true + } + if (pickerVisible) pickerKey(key) else if (key == ShellKey.Back) back() else if (navFocused) navKey(key) else contentKey(key) + return true + } + + private fun pickerKey(key: ShellKey) { + if (peopleStatus != PeopleStatus.Ready) { + when (key) { + ShellKey.Left -> recoveryIndex = 0 + ShellKey.Right -> if (peopleStatus == PeopleStatus.Unavailable) recoveryIndex = 1 + ShellKey.Back -> closePicker() + ShellKey.Ok -> if (peopleStatus == PeopleStatus.Unavailable && recoveryIndex == 0) onAction(ShellAction.RetryPeople) else choosePerson(person) + else -> Unit + } + } else if (gearFocused) { + when (key) { + ShellKey.Up -> gearFocused = false + ShellKey.Ok -> { + pickerVisible = false + navFocused = false + settingsRow = 0 + route = "settings" + onAction(ShellAction.Destination(route)) + } + ShellKey.Back -> closePicker() + else -> Unit + } + } else { + when (key) { + ShellKey.Left -> pickerIndex = (pickerIndex - 1).coerceAtLeast(0) + ShellKey.Right -> pickerIndex = (pickerIndex + 1).coerceAtMost(people.lastIndex) + ShellKey.Down -> if (pickerIndex == people.lastIndex) gearFocused = true + ShellKey.Ok -> choosePerson(people[pickerIndex]) + ShellKey.Back -> closePicker() + else -> Unit + } + } + } + + private fun choosePerson(selected: ShellPerson) { + person = selected + pickerVisible = false + pickerLaunch = false + route = "home" + navFocused = false + navIndex = 0 + rootRoute = "home" + requestReturnRoute = null + requestsVisible = false + views[person.key to route] = RememberedView() + onAction(ShellAction.Person(selected)) + } + + private fun closePicker() { + if (!pickerLaunch) { pickerVisible = false; navFocused = true; navIndex = tabs.size } + } + + private fun navKey(key: ShellKey) { + when (key) { + ShellKey.Left -> navIndex = (navIndex + tabs.size) % (tabs.size + 1) + ShellKey.Right -> navIndex = (navIndex + 1) % (tabs.size + 1) + ShellKey.Down -> if (contentFocus?.hasContent != false) navFocused = false + ShellKey.Ok -> activate() + else -> Unit + } + } + + private fun contentKey(key: ShellKey) { + if (contentFocus?.key(key) == true) return + when (key) { + ShellKey.Up -> if (route == "settings" && settingsRow > 0) settingsRow-- else { navFocused = true; navIndex = currentTab } + ShellKey.Down -> if (route == "settings") settingsRow = (settingsRow + 1).coerceAtMost(SETTINGS_GROUPS.lastIndex) + ShellKey.Ok -> activate() + else -> Unit + } + } + + private fun activate() { + if (navFocused) { + if (navIndex == tabs.size) { + pickerReturnRoute = route + pickerVisible = true + pickerLaunch = false + pickerIndex = people.indexOf(person) + gearFocused = false + } else { + val target = tabs[navIndex] + requestReturnRoute = null + if (target == route) views[person.key to target] = RememberedView() + route = target + rootRoute = target + navFocused = false + onAction(ShellAction.Destination(target)) + } + } else if (route == "settings") { + val group = SETTINGS_GROUPS[settingsRow].key + if (group == "requests") openRequests() else { + handOff = group + onAction(ShellAction.HandOff(group)) + } + } + else contentFocus?.key(ShellKey.Ok) + } + + /** Requested buttons may name an existing request without changing its authenticated actor. */ + fun openRequests(requestId: String? = null) { + requests.focus(requestId ?: requests.snapshot.ordered.firstOrNull()?.id) + requestsVisible = true + navFocused = false + } + + fun closeRequests() { requestsVisible = false } + fun retryRequests() { onAction(ShellAction.RetryRequests) } + + fun activateRequest() { + val request = requests.focused ?: return + requestReturnRoute = route + requestsVisible = false + onAction(ShellAction.RequestTitle(request)) + } + + /** Back never discards a root view, including the card below a focused nav. */ + fun back() { + if (requestsVisible) { closeRequests(); return } + val returnRoute = requestReturnRoute + if (returnRoute != null && route != returnRoute) { + route = returnRoute + requestsVisible = true + requestReturnRoute = null + onAction(ShellAction.Pop) + return + } + if (!pickerVisible && !navFocused && contentFocus?.key(ShellKey.Back) == true) return + if (route == "settings") { + route = pickerReturnRoute + onAction(ShellAction.Pop) + pickerVisible = true + pickerLaunch = false + gearFocused = true + pickerIndex = people.lastIndex + } else if (route !in tabs) { + onAction(ShellAction.Pop) + } else if (!navFocused) { + navFocused = true + navIndex = currentTab + } else if (route != "home") { + route = "home" + rootRoute = "home" + navIndex = 0 + onAction(ShellAction.Destination(route)) + } + } + + companion object { + private val BASE_TABS = listOf("home", "discover", "movies", "shows") + private val ANIME_TABS = BASE_TABS + "anime" + } +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/ShellSurface.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/ShellSurface.kt new file mode 100644 index 00000000..5eca15da --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/ShellSurface.kt @@ -0,0 +1,111 @@ +package org.justinvisser.wolfskin.design + +import androidx.compose.foundation.background +import androidx.compose.foundation.focusable +import androidx.compose.foundation.focusGroup +import androidx.compose.ui.focus.focusRestorer +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.offset +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.FocusDirection +import androidx.compose.ui.focus.FocusRequester +import androidx.compose.ui.focus.focusRequester +import androidx.compose.ui.input.key.Key +import androidx.compose.ui.input.key.KeyEvent +import androidx.compose.ui.input.key.KeyEventType +import androidx.compose.ui.input.key.key +import androidx.compose.ui.input.key.onKeyEvent +import androidx.compose.ui.input.key.onPreviewKeyEvent +import androidx.compose.ui.input.key.type +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalFocusManager +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.semantics.stateDescription +import androidx.tv.material3.Text +import org.justinvisser.wolfskin.design.WolfskinTokens.Color as C +import org.justinvisser.wolfskin.design.WolfskinTokens.Layout as L + +/** Screens and the shell interpret the same Android directional and activation keys. */ +fun readShellKey(event: KeyEvent): ShellKey? = when (event.key) { + Key.DirectionUp -> ShellKey.Up + Key.DirectionDown -> ShellKey.Down + Key.DirectionLeft -> ShellKey.Left + Key.DirectionRight -> ShellKey.Right + Key.DirectionCenter, Key.Enter, Key.NumPadEnter -> ShellKey.Ok + Key.Back, Key.Escape -> ShellKey.Back + else -> null +} + +/** Map Android key events once, preserving repeat count and key-up semantics. */ +fun ShellState.handleKey(event: KeyEvent): Boolean { + val key = readShellKey(event) ?: return false + return this.key(key, event.type == KeyEventType.KeyDown, event.nativeKeyEvent.repeatCount) +} + +/** Content and nav share a single focus policy; upstream full-screen pages bypass this surface. */ +@Composable +fun ShellSurface( + state: ShellState, + modifier: Modifier = Modifier, + handlesContentKeys: Boolean = true, + settingsOpenRequests: Int? = null, + overlay: @Composable () -> Unit = {}, + content: @Composable (Modifier) -> Unit = { ShellPlaceholder(state.route) }, +) { + val focus = remember { FocusRequester() } + val contentFocus = remember { FocusRequester() } + val focusManager = LocalFocusManager.current + LaunchedEffect(state.toast) { + val message = state.toast + if (message != null) { + kotlinx.coroutines.delay(WolfskinTokens.Motion.toast.toLong()) + if (state.toast == message) state.toast = null + } + } + LaunchedEffect(state.pickerVisible, state.navFocused, handlesContentKeys) { + if (state.pickerVisible || state.navFocused || handlesContentKeys) focus.requestFocus() + else contentFocus.requestFocus() + } + Box(modifier.fillMaxSize().background(if (handlesContentKeys || state.pickerVisible) C.bg else Color.Transparent).testTag("wolfskin-shell") + .semantics { stateDescription = "${state.person.key}:${state.route}:${if (state.pickerVisible) "picker" else if (state.navFocused) "nav-${state.navIndex}" else "content-${state.settingsRow}"}" } + .focusRequester(focus) + .onPreviewKeyEvent { + if (state.pickerVisible || state.navFocused || state.requestsVisible || handlesContentKeys) state.handleKey(it) else false + } + .onKeyEvent { + if (it.key == Key.DirectionUp && it.type == KeyEventType.KeyDown) { + if (!focusManager.moveFocus(FocusDirection.Up)) { + state.navFocused = true + state.navIndex = state.currentTab + } + true + } else false + }.focusable()) { + if (state.pickerVisible) { + WhosWatching(state) + } else { + if (state.route == "settings") SettingsList(state, openRequests = settingsOpenRequests ?: state.requests.snapshot.openCount) else content(Modifier.fillMaxSize().focusRequester(contentFocus).focusRestorer().focusGroup()) + NavBar(state, state.view.listState.firstVisibleItemIndex > 0 || state.view.listState.firstVisibleItemScrollOffset > L.navSolidAfter.value * 2) + if (state.requestsVisible) ComingInSheet(state) + overlay() + } + state.toast?.let { RecoveryToast(it) } + } +} + +/** Future screens are explicitly out of scope, never simulated library or title data. */ +@Composable +fun ShellPlaceholder(route: String, modifier: Modifier = Modifier) { + Column(modifier.offset(L.safeSide, L.detailCopyTop), verticalArrangement = Arrangement.spacedBy(L.buttonGap)) { + Text(route.replaceFirstChar { it.uppercase() }, color = C.fg, style = WolfskinTokens.Type.screenTitle) + Text("Wolfskin screen โ€” not built in this slice", color = C.accentText, style = WolfskinTokens.Type.body) + Text("Home and Library remain available through the Wolfskin screens switch in Advanced settings.", color = C.muted, style = WolfskinTokens.Type.body) + } +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/SourceRatings.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/SourceRatings.kt new file mode 100644 index 00000000..018e4a4b --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/SourceRatings.kt @@ -0,0 +1,107 @@ +package org.justinvisser.wolfskin.design + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.BoxWithConstraints +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.runtime.getValue +import androidx.compose.animation.core.animateFloatAsState +import androidx.compose.animation.core.tween +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.graphics.ColorMatrix +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.rememberTextMeasurer +import androidx.compose.ui.unit.TextUnit +import androidx.compose.ui.unit.TextUnitType +import androidx.tv.material3.Text +import java.util.Locale +import org.justinvisser.wolfskin.design.WolfskinTokens.Color as C +import org.justinvisser.wolfskin.design.WolfskinTokens.Title as D +import org.justinvisser.wolfskin.design.WolfskinTokens.Library as P + +/** A full facts-line set never shrinks or waits for focused-card dwell. */ +@Composable +fun TitleRatings(ratings: List, modifier: Modifier = Modifier, style: TextStyle = WolfskinTokens.Type.ratingPlate, plate: Boolean = false) { + if (ratings.isEmpty()) return + val density = LocalDensity.current + val markHeight = with(density) { style.fontSize.toDp() } + val lineHeight = style.fontSize * (WolfskinTokens.Type.ratingPlate.lineHeight.value / WolfskinTokens.Type.ratingPlate.fontSize.value) + val textStyle = if (style.lineHeight == lineHeight) style else style.copy(lineHeight = lineHeight) + val numberStyle = remember(textStyle) { textStyle.copy(fontFeatureSettings = "tnum", fontWeight = FontWeight.Bold) } + val gap = if (plate) with(density) { (style.fontSize * P.plateGapEm).toDp() } else D.ratingGap + val markGap = if (plate) with(density) { (style.fontSize * P.markGapEm).toDp() } else D.ratingMarkGap + Row(modifier, horizontalArrangement = Arrangement.spacedBy(gap), verticalAlignment = Alignment.CenterVertically) { + ratings.forEach { rating -> + Row(horizontalArrangement = Arrangement.spacedBy(markGap), verticalAlignment = Alignment.CenterVertically) { + val resource = when (rating.source) { + "rtCritics" -> if (rating.label == "Rotten") R.drawable.ic_rotten_tomatoes_rotten else R.drawable.ic_rotten_tomatoes_fresh + "rtAudience" -> if (rating.label == "Spilled") R.drawable.ic_rt_spilled else R.drawable.ic_rt_upright + "imdb" -> R.drawable.ic_rating_imdb + else -> R.drawable.ic_rating_tmdb + } + val unknownCritic = rating.source == "rtCritics" && rating.label != "Fresh" && rating.label != "Certified Fresh" && rating.label != "Rotten" + val desaturated = if (unknownCritic) remember { ColorFilter.colorMatrix(ColorMatrix().apply { setToSaturation(0f) }) } else null + Image(painterResource(resource), rating.source, Modifier.size(markHeight * if (rating.source == "imdb" || rating.source == "tmdb") P.wordmarkRatio else 1f, markHeight), + alpha = if (unknownCritic) P.unknownCriticOpacity else 1f, colorFilter = desaturated) + if (rating.episode) Text("Ep", color = C.muted, style = textStyle.copy(fontWeight = WolfskinTokens.Type.label.fontWeight), modifier = Modifier.exactLineBox(textStyle)) + Text(rating.formatted(), color = C.fg, style = numberStyle, modifier = Modifier.exactLineBox(numberStyle), maxLines = 1) + } + } + } +} + +/** The plate keeps a prefix of the title set, shrinking to the caption floor before dropping its tail. */ +@Composable +fun LibraryRatingPlate(ratings: List, modifier: Modifier = Modifier, visible: Boolean = true) { + if (ratings.isEmpty()) return + val measurer = rememberTextMeasurer() + val density = LocalDensity.current + val alpha by animateFloatAsState(if (visible) 1f else 0f, tween(WolfskinTokens.Motion.base), label = "rating-plate") + BoxWithConstraints(modifier.fillMaxWidth().graphicsLayer { this.alpha = alpha } + .background(Brush.verticalGradient(0f to C.bg.copy(alpha = P.plateOpacity), P.plateMidStop to C.bg.copy(alpha = P.plateMidOpacity), 1f to C.bg.copy(alpha = 0f))) + .testTag("rating-plate").padding(horizontal = P.plateSide)) { + val width = with(density) { maxWidth.toPx() } + val fit = remember(ratings, width, density, Locale.getDefault()) { + var size = WolfskinTokens.Type.ratingPlate.fontSize.value + var count = ratings.size + val numbers = ratings.map { it.formatted() } + fun measured(): Float { + val fontSize = TextUnit(size, TextUnitType.Sp) + val style = WolfskinTokens.Type.ratingPlate.copy(fontSize = fontSize, fontFeatureSettings = "tnum") + val markGap = with(density) { (fontSize * P.markGapEm).toPx() } + val entryGap = with(density) { (fontSize * P.plateGapEm).toPx() } + var total = 0f + for (index in 0 until count) { + val rating = ratings[index] + total += measurer.measure(numbers[index], style, maxLines = 1).size.width + total += with(density) { fontSize.toPx() } * if (rating.source == "imdb" || rating.source == "tmdb") P.wordmarkRatio else 1f + total += markGap + if (rating.episode) total += measurer.measure("Ep", style.copy(fontWeight = WolfskinTokens.Type.label.fontWeight), maxLines = 1).size.width + markGap + if (index > 0) total += entryGap + } + return total + } + while (size > P.plateFloor.fontSize.value && measured() > width) size = (size - P.plateStep).coerceAtLeast(P.plateFloor.fontSize.value) + while (count > 1 && measured() > width) count-- + count to size + } + val fontSize = TextUnit(fit.second, TextUnitType.Sp) + val style = WolfskinTokens.Type.ratingPlate.copy(fontSize = fontSize, + lineHeight = WolfskinTokens.Type.ratingPlate.lineHeight * (fit.second / WolfskinTokens.Type.ratingPlate.fontSize.value)) + TitleRatings(ratings.take(fit.first), modifier = Modifier.exactLineBox(style, top = P.plateTop, bottom = P.plateBottom + P.plateInlineDescent), style = style, plate = true) + } +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/TextLineBox.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/TextLineBox.kt new file mode 100644 index 00000000..b21c4dcb --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/TextLineBox.kt @@ -0,0 +1,10 @@ +package org.justinvisser.wolfskin.design + +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.TextUnit + +/** Explicit CSS leading and margins share one fractional layout engine across Wolfskin screens. */ +fun Modifier.exactLineBox(style: TextStyle, top: Dp = WolfskinTokens.Shell.zero, bottom: Dp = WolfskinTokens.Shell.zero): Modifier = + if (style.lineHeight == TextUnit.Unspecified) this else then(CssLineBox(style.lineHeight, top, bottom)) diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/TitleArtwork.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/TitleArtwork.kt new file mode 100644 index 00000000..1ea37eb4 --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/TitleArtwork.kt @@ -0,0 +1,176 @@ +package org.justinvisser.wolfskin.design + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.size +import androidx.compose.runtime.Composable +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.compositionLocalOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.blur +import androidx.compose.ui.draw.clip +import androidx.compose.ui.draw.drawWithCache +import androidx.compose.ui.draw.dropShadow +import androidx.compose.ui.graphics.shadow.Shadow +import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.layout.layout +import androidx.compose.ui.unit.DpOffset +import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.graphics.ColorMatrix +import androidx.compose.ui.graphics.ShaderBrush +import androidx.compose.ui.graphics.toArgb +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.ImageBitmap +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.text.style.TextOverflow +import androidx.tv.material3.Text +import coil3.compose.AsyncImage +import org.justinvisser.wolfskin.design.WolfskinTokens.Color as C +import org.justinvisser.wolfskin.design.WolfskinTokens.Layout as L +import org.justinvisser.wolfskin.design.WolfskinTokens.Title as D + +/** Local decoded fixture art keeps screenshot tests deterministic and completely offline. */ +val LocalTitleBitmaps = compositionLocalOf> { emptyMap() } + +/** Decode at the slot size, with no crossfade or oversized poster allocations. */ +@Composable +fun TitleArtwork(path: String?, width: Int, height: Int, modifier: Modifier = Modifier, poster: Boolean = false, colorFilter: ColorFilter? = null, onError: () -> Unit = {}) { + val bitmap = LocalTitleBitmaps.current[path] + if (bitmap != null) Image(bitmap, null, modifier, contentScale = ContentScale.Crop, colorFilter = colorFilter) + else if (path != null) { + val context = LocalContext.current + val request = remember(context, path, width, height, poster) { + WolfskinImages.request(context, path, width, height, poster) + } + AsyncImage(model = request, imageLoader = WolfskinImages.loader(context), + contentDescription = null, modifier = modifier, contentScale = ContentScale.Crop, colorFilter = colorFilter, onError = { onError() }) + } +} + +/** Initials follow the same title-hashed hue as the locked art fallback. */ +@Composable +fun PersonPortrait(person: TitlePerson, modifier: Modifier = Modifier, large: Boolean = false) { + val initials = remember(person.name) { person.name.split(Regex("\\s+")).filter { it.isNotEmpty() }.take(2).joinToString("") { it.take(1) }.uppercase() } + val size = if (large) (L.personPortrait.value * 2).toInt() else WolfskinTokens.Image.castRequestWidth + Box(modifier.titleFallbackBackground(person.name, D.personFallbackGradient), contentAlignment = Alignment.Center) { + Text(initials, color = D.initialsColor, style = if (large) D.personInitialSize else D.initialSize, textAlign = TextAlign.Center) + if (person.portrait != null) TitleArtwork(person.portrait, size, size, Modifier.fillMaxSize()) + } +} + +/** The original gradient is parsed once so stops stay derived from the canonical token. */ +@Composable +fun TitleBackdrop(item: TitleItem, modifier: Modifier = Modifier) { + val horizontal = remember { + val stops = Regex("rgb\\(7 7 10 / ([.\\d]+)\\) (\\d+)%").findAll(WolfskinTokens.Gradient.detailScrim).take(3) + .map { it.groupValues[2].toFloat() / 100 to C.bg.copy(alpha = it.groupValues[1].toFloat()) }.toList() + Brush.horizontalGradient(*stops.toTypedArray()) + } + val vertical = remember { + val token = WolfskinTokens.Gradient.detailScrim.substringAfter("linear-gradient(0deg,") + val stops = mutableListOf(1f to C.bg) + Regex("rgb\\(7 7 10 / ([.\\d]+)\\) (\\d+)%").findAll(token).forEach { + stops.add(1f - it.groupValues[2].toFloat() / 100 to C.bg.copy(alpha = it.groupValues[1].toFloat())) + } + Brush.verticalGradient(*stops.sortedBy { it.first }.toTypedArray()) + } + Box(modifier.titleAmbientBackground()) { + if (item.backdrop != null && !item.isPosterBackdrop) { + TitleArtwork(item.backdrop, WolfskinTokens.Image.heroRequestWidth, WolfskinTokens.Image.heroRequestHeight, Modifier.fillMaxSize()) + } else if (item.poster != null) { + val filter = remember { + val token = WolfskinTokens.Gradient.heroAmbientFilter + Regex("blur\\(([\\d.]+)px\\).*saturate\\(([\\d.]+)\\).*brightness\\(([\\d.]+)\\)").find(token)!!.groupValues + } + val colorFilter = remember { + val matrix = ColorMatrix().apply { setToSaturation(filter[2].toFloat()) } + for (index in 0 until 15) matrix.values[index] *= filter[3].toFloat() + ColorFilter.colorMatrix(matrix) + } + TitleArtwork(item.poster, WolfskinTokens.Image.heroRequestWidth, WolfskinTokens.Image.heroRequestHeight, + Modifier.fillMaxSize().artOverscan(D.ambientInset).graphicsLayer { scaleX = D.ambientScale; scaleY = D.ambientScale } + .blur(Dp(filter[1].toFloat() / 2)), colorFilter = colorFilter) + val posterShape = remember { RoundedCornerShape(WolfskinTokens.Radius.heroSheet) } + val posterShadow = remember { Shadow(radius = D.posterShadowRadius, offset = DpOffset.Zero.copy(y = D.posterShadowY), color = Color.Black.copy(alpha = D.posterShadowOpacity)) } + TitleArtwork(item.poster, (L.heroSheetWidth.value * 2).toInt(), (L.heroSheetHeight.value * 2).toInt(), + Modifier.offset(WolfskinTokens.Shell.stageWidth - L.heroSheetWidth - D.heroSheetRight, D.heroSheetTop) + .size(L.heroSheetWidth, L.heroSheetHeight).dropShadow(posterShape, posterShadow).clip(posterShape)) + } + Box(Modifier.fillMaxSize().background(horizontal)) + Box(Modifier.fillMaxSize().background(vertical)) + } +} + +/** Library, related and person posters share the exact locked missing-art treatment. */ +@Composable +internal fun MediaArtworkFallback(name: String, movie: Boolean, showTitle: Boolean = true) { + Box(Modifier.fillMaxSize().titleFallbackBackground(name, D.cardFallbackGradient)) { + Glyph(if (movie) "film" else "tv", D.fallbackGlyphColor, Modifier.offset(D.fallbackInset, D.fallbackInset).size(D.fallbackGlyph)) + if (showTitle) Text(name, color = C.fg, style = D.fallbackTitle, maxLines = 4, overflow = TextOverflow.Ellipsis, + modifier = Modifier.align(Alignment.BottomStart).padding(D.fallbackInset)) + } +} + +/** Episode tiles use their backdrop, or the prototype's blurred poster and small one-sheet. */ +@Composable +fun TitleTileArtwork(item: TitleItem) { + Box(Modifier.fillMaxSize()) { + MediaArtworkFallback(item.seriesName ?: item.name, item.kind == "movie", showTitle = false) + if (item.isPosterBackdrop && item.poster != null) { + val filter = remember { ColorFilter.colorMatrix(ColorMatrix().apply { + for (index in 0 until 15) values[index] *= D.tileAmbientBrightness + }) } + TitleArtwork(item.poster, WolfskinTokens.Image.tileRequestWidth, WolfskinTokens.Image.tileRequestHeight, Modifier.fillMaxSize().artOverscan(D.tileAmbientInset).blur(D.tileAmbientBlur), colorFilter = filter) + val height = WolfskinTokens.Card.tileH - D.tileSheetInset * 2 + val shape = remember { RoundedCornerShape(D.tileSheetRadius) } + val shadow = remember { Shadow(radius = D.tileShadowRadius, offset = DpOffset.Zero.copy(y = D.tileShadowY), color = Color.Black.copy(alpha = D.tileShadowOpacity)) } + TitleArtwork(item.poster, (height.value * 2 * 2 / 3).toInt(), (height.value * 2).toInt(), + Modifier.offset(D.tileSheetLeft, D.tileSheetInset).size(height * (2f / 3), height).dropShadow(shape, shadow).clip(shape), poster = true) + } else TitleArtwork(item.backdrop, WolfskinTokens.Image.tileRequestWidth, WolfskinTokens.Image.tileRequestHeight, Modifier.fillMaxSize()) + } +} + +private fun Modifier.artOverscan(inset: Dp): Modifier = layout { measurable, constraints -> + val pixels = inset.roundToPx() + val width = constraints.maxWidth + pixels * 2 + val height = constraints.maxHeight + pixels * 2 + val placeable = measurable.measure(constraints.copy(minWidth = width, maxWidth = width, minHeight = height, maxHeight = height)) + layout(constraints.maxWidth, constraints.maxHeight) { placeable.place(-pixels, -pixels) } +} + +private fun Modifier.titleFallbackBackground(name: String, token: String): Modifier = drawWithCache { + var hue = 0 + name.forEach { hue = (hue * 31 + it.code) % 360 } + val values = Regex("([\\d.]+)%").findAll(token).map { it.groupValues[1].toFloat() / 100 }.toList() + val angle = Math.toRadians(Regex("(\\d+)deg").find(token)!!.groupValues[1].toDouble()) + val dx = kotlin.math.sin(angle).toFloat() + val dy = -kotlin.math.cos(angle).toFloat() + val half = (kotlin.math.abs(size.width * dx) + kotlin.math.abs(size.height * dy)) / 2 + val vector = Offset(dx * half, dy * half) + val middle = Offset(size.width / 2, size.height / 2) + val brush = Brush.linearGradient(listOf(Color.hsl(hue.toFloat(), values[0], values[1]), Color.hsl(hue.toFloat(), values[2], values[3])), + start = middle - vector, end = middle + vector) + onDrawBehind { drawRect(brush) } +} + +private fun Modifier.titleAmbientBackground(): Modifier = drawWithCache { + val values = Regex("([\\d.]+)%").findAll(D.heroAmbientBackground).map { it.groupValues[1].toFloat() / 100 }.toList() + val shader = android.graphics.RadialGradient(0f, 0f, 1f, intArrayOf(C.surface3.toArgb(), C.bg.toArgb()), null, android.graphics.Shader.TileMode.CLAMP) + shader.setLocalMatrix(android.graphics.Matrix().apply { + setScale(size.width * values[0], size.height * values[1]) + postTranslate(size.width * values[2], size.height * values[3]) + }) + val brush = ShaderBrush(shader) + onDrawBehind { drawRect(brush) } +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/TitleCard.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/TitleCard.kt new file mode 100644 index 00000000..81779ed3 --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/TitleCard.kt @@ -0,0 +1,23 @@ +package org.justinvisser.wolfskin.design + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.BoxScope +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.unit.Dp + +/** Shelf, grid and continuation cards share one fixed slot and draw-only focus surface. */ +@Composable +fun TitleCard(focused: Boolean, modifier: Modifier = Modifier, width: Dp = WolfskinTokens.Card.posterW, + height: Dp = WolfskinTokens.Card.posterH, content: @Composable BoxScope.() -> Unit) { + val shape = RoundedCornerShape(WolfskinTokens.Radius.card) + Box(modifier.size(width, height).focusScale(focused, WolfskinTokens.Focus.scaleCard) + .focusRing(focused, WolfskinTokens.Radius.card, WolfskinTokens.Focus.ringCardGap, WolfskinTokens.Focus.ringCardRing, WolfskinTokens.Color.accent, FocusLift.Card)) { + Box(Modifier.fillMaxSize().clip(shape).background(WolfskinTokens.Color.surface2), content = content) + } +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/TitleControl.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/TitleControl.kt new file mode 100644 index 00000000..4346eae2 --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/TitleControl.kt @@ -0,0 +1,59 @@ +package org.justinvisser.wolfskin.design + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.semantics.Role +import androidx.compose.ui.semantics.contentDescription +import androidx.compose.ui.semantics.role +import androidx.compose.ui.semantics.selected +import androidx.compose.ui.semantics.semantics +import androidx.tv.material3.Text +import org.justinvisser.wolfskin.design.WolfskinTokens.Color as C +import org.justinvisser.wolfskin.design.WolfskinTokens.Layout as L +import org.justinvisser.wolfskin.design.WolfskinTokens.Title as D + +/** Compact title controls reserve captions beneath the whole row, not inside an expanding button. */ +@Composable +fun TitleControl(option: TitleOption, focused: Boolean, modifier: Modifier = Modifier, onFocus: (() -> Unit)? = null, overArtwork: Boolean = true, onClick: () -> Unit) { + val focusOwner = LocalTitleFocusOwner.current + val background = if (option.primary) C.fg else if (overArtwork) { + if (focused) C.titleButtonSecondaryFocused else C.titleButtonSecondary + } else if (focused) C.buttonSecondaryFocused else C.buttonSecondary + val foreground = if (option.primary) C.onFocus else C.fg + val shape = RoundedCornerShape(WolfskinTokens.Radius.button) + val dimensions = if (option.icon) Modifier.size(L.iconButton) else Modifier.height(L.buttonHeight).padding(horizontal = L.buttonPaddingX) + Row(modifier.testTag("title-option-${option.id}").titlePointerFocus(onFocus).focusScale(focused, WolfskinTokens.Focus.scaleControl) + .semantics { if (option.icon) contentDescription = option.label; role = Role.Button; selected = option.on } + .focusRing(focused, WolfskinTokens.Radius.button, WolfskinTokens.Focus.ringButtonGap, WolfskinTokens.Focus.ringButtonRing, C.accent, FocusLift.Button) + .background(background, shape) + .then(if (option.on && !focused) Modifier.border(D.radioBorder, C.accent, shape) else Modifier) + .clickable { focusOwner?.invoke(); onClick() }.then(dimensions), + horizontalArrangement = Arrangement.spacedBy(D.iconGap, Alignment.CenterHorizontally), verticalAlignment = Alignment.CenterVertically) { + if (option.glyph.isNotEmpty()) Glyph(option.glyph, foreground, Modifier.size(if (option.icon) D.iconSize else L.buttonIcon)) + if (!option.icon) Text(option.label, color = foreground, style = WolfskinTokens.Type.button, maxLines = 1) + } +} + + +/** A radio remains visibly selected independently of the inverse focused row. */ +@Composable +fun TitleRadio(selected: Boolean, focused: Boolean) { + val color = if (focused) C.onFocus else C.fg + Box(Modifier.size(D.radioSize).background(if (selected) C.accent else androidx.compose.ui.graphics.Color.Transparent, CircleShape) + .then(if (focused || !selected) Modifier.border(D.radioBorder, color.copy(alpha = if (focused) .5f else .35f), CircleShape) else Modifier), contentAlignment = Alignment.Center) { + if (selected) Box(Modifier.size(D.radioDot).background(C.onFocus, CircleShape)) + } +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/TitleHeader.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/TitleHeader.kt new file mode 100644 index 00000000..6b31174e --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/TitleHeader.kt @@ -0,0 +1,117 @@ +package org.justinvisser.wolfskin.design + +import androidx.compose.ui.layout.onGloballyPositioned +import androidx.compose.ui.layout.boundsInRoot +import androidx.compose.ui.platform.testTag +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.wrapContentWidth +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.buildAnnotatedString +import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.text.withStyle +import androidx.compose.ui.text.style.TextOverflow +import androidx.tv.material3.Text +import org.justinvisser.wolfskin.design.WolfskinTokens.Color as C +import org.justinvisser.wolfskin.design.WolfskinTokens.Layout as L +import org.justinvisser.wolfskin.design.WolfskinTokens.Title as D + +/** Film, series and episode share one copy block and one fixed options-caption band. */ +@Composable +fun TitleHeader(state: TitleState, active: Boolean, modifier: Modifier = Modifier) { + if (state.data.status == TitleReadStatus.Loading) { TitleHeaderSkeleton(modifier); return } + val item = state.data.item + val type = if (item.kind == "movie") "Movie" else "Series" + CssColumn(modifier.offset(L.safeSide, L.detailCopyTop + D.lineLift).width(L.detailCopyWidth)) { + Row(Modifier.exactLineBox(TitleTextStyles.dLine, bottom = D.lineGap), horizontalArrangement = Arrangement.spacedBy(L.navItemGap), verticalAlignment = Alignment.CenterVertically) { + Glyph(if (item.held) "check" else "sparkle", C.accentText, Modifier.size(D.lineIcon)) + Text(buildString { + append("$type ยท ${if (item.held) "In your library" else "Not in your library"}") + if (item.held && state.watched) append(" ยท Watched") + if (!item.held && item.otherOwners.isNotEmpty()) append(" ยท In ${item.otherOwners.joinToString(" and ")}โ€™s library") + if (state.data.hidden) append(" ยท Hidden from your picks") + }, color = C.accentText, style = TitleTextStyles.dLine) + } + Text(item.name, color = C.fg, style = TitleTextStyles.displayDetail, maxLines = 2, overflow = TextOverflow.Ellipsis, modifier = Modifier.exactLineBox(TitleTextStyles.displayDetail, bottom = D.titleBottom).testTag("title-heading")) + Row(Modifier.padding(bottom = D.factsBottom).height(D.factsHeight).testTag("title-facts"), horizontalArrangement = Arrangement.spacedBy(D.factsGap), verticalAlignment = Alignment.CenterVertically) { + item.year?.let { Text(it.toString(), color = C.muted, style = TitleTextStyles.body, modifier = Modifier.exactLineBox(TitleTextStyles.body)) } + if (item.kind == "movie" && item.runtimeSeconds > 0) Text(item.runtime, color = C.muted, style = TitleTextStyles.body, modifier = Modifier.exactLineBox(TitleTextStyles.body)) + if (item.kind == "tv" && item.seasons > 0) Text("${item.seasons} season${if (item.seasons == 1) "" else "s"}", color = C.muted, style = TitleTextStyles.body, modifier = Modifier.exactLineBox(TitleTextStyles.body)) + if (state.data.connection != TitleConnection.SignedOut) TitleRatings(item.ratings) + if (item.genres.isNotEmpty()) Text(item.genres.take(3).joinToString(", "), color = C.muted, style = TitleTextStyles.body, modifier = Modifier.exactLineBox(TitleTextStyles.body)) + } + state.data.requestedStage?.let { stage -> + val color = when (stage) { "Ready" -> C.ok; "Failed" -> C.fail; "Downloading", "Almost ready" -> C.accent; else -> C.muted } + Row(Modifier.exactLineBox(TitleTextStyles.dLine, bottom = D.lineGap), horizontalArrangement = Arrangement.spacedBy(L.navItemGap), verticalAlignment = Alignment.CenterVertically) { + Glyph(titleStageGlyph(stage), color, Modifier.size(D.lineIcon)) + Text(stage, color = color, style = TitleTextStyles.label) + Text("for you ยท by ${state.data.requestActor.orEmpty()}", color = C.muted, style = TitleTextStyles.dLine) + } + } + Text(item.overview, color = C.muted, style = TitleTextStyles.body, maxLines = 3, overflow = TextOverflow.Ellipsis, modifier = Modifier.exactLineBox(TitleTextStyles.body, bottom = D.overviewGap).testTag("title-overview")) + if (!item.held && state.data.connection != TitleConnection.SignedIn) { + Text(if (state.data.connection == TitleConnection.SignedOut) "Requests need this TV to be signed in to Conductarr." else "Requests need Conductarr, and it canโ€™t be reached right now.", + color = C.warn, style = TitleTextStyles.body, modifier = Modifier.exactLineBox(TitleTextStyles.body, bottom = D.overviewGap)) + } + state.data.playTarget?.let { target -> + Row(Modifier.exactLineBox(TitleTextStyles.progress, top = D.progressLift, bottom = D.progressBottom).testTag("title-progress"), horizontalArrangement = Arrangement.spacedBy(D.progressGap), verticalAlignment = Alignment.CenterVertically) { + if (target.resumeSeconds > 0) { + Box(Modifier.size(D.progressWidth, L.progressBar).background(C.progressTrack, RoundedCornerShape(WolfskinTokens.Radius.progress))) { + val fraction = if (target.runtimeSeconds > 0) (target.resumeSeconds.toFloat() / target.runtimeSeconds).coerceIn(0f, 1f) else 0f + Box(Modifier.fillMaxWidth(fraction).fillMaxHeight().background(C.accent)) + } + Text((if (target.kind == "episode") "${target.episodeLabel} ยท " else "") + "${((target.runtimeSeconds - target.resumeSeconds + 30) / 60).coerceAtLeast(1)} min left", color = C.muted, style = TitleTextStyles.progress) + } else if (target.kind == "episode") Text("Up next: ${target.episodeLabel} ยท ${target.name}", color = C.muted, style = TitleTextStyles.progress) + if (state.data.connection != TitleConnection.SignedOut) TitleRatings(target.ratings, style = TitleTextStyles.progress) + } + } + Row(Modifier.wrapContentWidth(Alignment.Start, unbounded = true).testTag("title-actions"), horizontalArrangement = Arrangement.spacedBy(L.buttonGap)) { + state.options.forEachIndexed { index, option -> TitleControl(option, active && state.column == index, + Modifier.onGloballyPositioned { state.recordCenter("header", index, it.boundsInRoot().center.x) }, + onFocus = { state.focus("header", index) }) { state.click("header", index) } } + } + if (state.options.any { it.icon }) { + val option = state.options.getOrNull(state.column)?.takeIf { active && it.icon } + Text(buildAnnotatedString { + if (option != null) { + withStyle(SpanStyle(color = C.fg, fontWeight = WolfskinTokens.Type.label.fontWeight)) { append(option.label) } + if (option.note.isNotEmpty()) append(" ยท ${option.note}") + } + }, color = C.muted, style = D.iconCaption, modifier = Modifier.padding(top = D.captionTop).height(L.iconCaptionLine)) + } + } +} + +/** A no-copy load has no focusable content and never draws a spinner. */ +@Composable +fun TitleHeaderSkeleton(modifier: Modifier = Modifier) { + Column(modifier.offset(L.safeSide, L.detailCopyTop)) { + Box(Modifier.size(D.skeletonKickerWidth, D.skeletonKickerHeight).background(C.surface, RoundedCornerShape(WolfskinTokens.Radius.cardSheet))) + Spacer(Modifier.height(D.skeletonTitleGap)) + Box(Modifier.size(D.skeletonTitleWidth, D.skeletonTitleHeight).background(C.surface, RoundedCornerShape(WolfskinTokens.Radius.card))) + Spacer(Modifier.height(D.skeletonFactsGap)) + Box(Modifier.size(D.skeletonFactsWidth, D.skeletonKickerHeight).background(C.surface, RoundedCornerShape(WolfskinTokens.Radius.cardSheet))) + Spacer(Modifier.height(D.skeletonOverviewGap)) + Box(Modifier.size(D.skeletonOverviewWidth, D.skeletonOverviewHeight).background(C.surface, RoundedCornerShape(WolfskinTokens.Radius.card))) + Spacer(Modifier.height(D.overviewGap)) + Row(horizontalArrangement = Arrangement.spacedBy(L.buttonGap)) { + Box(Modifier.size(D.skeletonPlayWidth, L.buttonHeight).background(C.surface, RoundedCornerShape(WolfskinTokens.Radius.button))) + repeat(2) { Box(Modifier.size(L.iconButton).background(C.surface, RoundedCornerShape(WolfskinTokens.Radius.button))) } + } + } +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/TitleModel.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/TitleModel.kt new file mode 100644 index 00000000..052627dc --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/TitleModel.kt @@ -0,0 +1,112 @@ +package org.justinvisser.wolfskin.design + +import androidx.compose.runtime.Immutable + +/** Screen data is independent of Jellyfin and Conductarr wire objects. */ +@Immutable +data class TitleItem( + override val id: String, + val name: String, + val kind: String, + val year: Int? = null, + val runtimeSeconds: Long = 0, + val seasons: Int = 0, + val overview: String = "", + val genres: List = emptyList(), + override val poster: String? = null, + val backdrop: String? = null, + val held: Boolean = false, + val watched: Boolean = false, + val resumeSeconds: Long = 0, + val seriesId: String? = null, + val seriesName: String? = null, + val season: Int = 0, + val episode: Int = 0, + override val ratings: List = emptyList(), + val character: String? = null, + val otherOwners: List = emptyList(), + val isPosterBackdrop: Boolean = false, +) : PosterContent { + override val posterTitle: String get() = name + override val posterIsMovie: Boolean get() = kind == "movie" + override val progress: Float get() = if (runtimeSeconds > 0) resumeSeconds.toFloat() / runtimeSeconds else 0f + override val badge: String? get() = if (held) "held" else null + val episodeLabel: String get() = "S$season E$episode" + val runtime: String get() { + val minutes = (runtimeSeconds + 30) / 60 + return if (minutes >= 60) "${minutes / 60}h ${minutes % 60}m" else "${minutes}m" + } +} + +/** A cast identity can open a performer page without borrowing a title's identity. */ +@Immutable +data class TitlePerson(val id: String, val name: String, val character: String = "", val portrait: String? = null, val biography: String = "") + +/** Stream indexes remain the server's indexes, including non-contiguous track lists. */ +@Immutable +data class TitleTrack(val index: Int, val label: String, val isDefault: Boolean = false) + +/** Playback options describe the actual play target, not a season or recommendation stub. */ +@Immutable +data class TitleVersion( + val id: String, + val name: String, + val video: String, + val bitrate: String, + val size: String, + val container: String, + val audio: List, + val subtitles: List, +) + +enum class TitleReadStatus { Ready, Loading, Unavailable } +enum class TitleConnection { SignedIn, SignedOut, Offline } +enum class TitleSheet { Version, Tracks, MediaInfo, ConfirmWatched, HiddenReceipt } + +/** A title read includes related titles and the selected season; reads happen outside composition. */ +@Immutable +data class TitlePageData( + val item: TitleItem, + val playTarget: TitleItem? = null, + val watchTarget: TitleItem = item, + val versions: List = emptyList(), + val selectedVersion: String? = null, + val selectedAudio: Int? = null, + val selectedSubtitle: Int = -1, + val trailerUrl: String? = null, + val cast: List = emptyList(), + val castStatus: TitleReadStatus = TitleReadStatus.Ready, + val related: List = emptyList(), + val episodes: List = emptyList(), + val status: TitleReadStatus = TitleReadStatus.Ready, + val connection: TitleConnection = TitleConnection.SignedOut, + val requestedStage: String? = null, + val requestActor: String? = null, + val hidden: Boolean = false, + val pick: Boolean = false, + val savedAt: String? = null, + val seasonNumbers: List = List(item.seasons) { it + 1 }, + val selectedSeason: Int? = null, + val episodesStatus: TitleReadStatus = TitleReadStatus.Ready, +) + +/** Effects are handled by the app's authenticated facade and navigation layer. */ +sealed interface TitleAction { + data class Play(val item: TitleItem, val restart: Boolean = false) : TitleAction + data class Version(val item: TitleItem, val version: TitleVersion) : TitleAction + data class Track(val item: TitleItem, val version: TitleVersion, val audio: Int?, val subtitle: Int) : TitleAction + data class Watched(val item: TitleItem, val watched: Boolean) : TitleAction + data class Trailer(val url: String) : TitleAction + data class Person(val person: TitlePerson) : TitleAction + data class OpenTitle(val item: TitleItem) : TitleAction + data class Season(val number: Int) : TitleAction + data class Request(val item: TitleItem, val forSomeoneElse: Boolean) : TitleAction + data class Hide(val item: TitleItem, val hidden: Boolean) : TitleAction + data class Requests(val item: TitleItem) : TitleAction + data object Retry : TitleAction + data object Pop : TitleAction +} + +/** The options row distinguishes compact icons from labelled primary and secondary pills. */ +@Immutable +data class TitleOption(val id: String, val label: String, val glyph: String, val note: String = "", val primary: Boolean = false, val icon: Boolean = true, val on: Boolean = false) diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/TitleOptionsSheet.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/TitleOptionsSheet.kt new file mode 100644 index 00000000..3a87dcdd --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/TitleOptionsSheet.kt @@ -0,0 +1,170 @@ +package org.justinvisser.wolfskin.design + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.focusable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.FocusRequester +import androidx.compose.ui.focus.focusRequester +import androidx.compose.ui.input.key.KeyEventType +import androidx.compose.ui.input.key.onPreviewKeyEvent +import androidx.compose.ui.input.key.type +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.semantics.stateDescription +import androidx.tv.material3.Text +import androidx.compose.ui.draw.dropShadow +import androidx.compose.ui.graphics.RectangleShape +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.shadow.Shadow +import androidx.compose.ui.unit.DpOffset +import androidx.compose.ui.layout.layout +import org.justinvisser.wolfskin.design.WolfskinTokens.Color as C +import org.justinvisser.wolfskin.design.WolfskinTokens.Layout as L +import org.justinvisser.wolfskin.design.WolfskinTokens.Title as D + +/** Sheets sit above navigation and consume pointer and key input across the entire scrim. */ +@Composable +fun TitleOptionsSheet(state: TitleState, shell: ShellState) { + val focus = remember { FocusRequester() } + LaunchedEffect(state.sheet) { focus.requestFocus() } + val shadow = remember { Shadow(radius = D.sheetShadowRadius, offset = DpOffset.Zero.copy(x = D.sheetShadowX), color = Color.Black.copy(alpha = D.sheetShadowOpacity)) } + Box(Modifier.fillMaxSize().background(C.sheetScrim).clickable { } + .testTag("title-sheet").semantics { stateDescription = "${state.sheet}:${state.sheetIndex}" } + .focusRequester(focus).onPreviewKeyEvent { event -> + val key = readShellKey(event) + key != null && state.key(key, event.type == KeyEventType.KeyDown, event.nativeKeyEvent.repeatCount, shell) + }.focusable()) { + CssColumn(Modifier.align(Alignment.TopEnd).width(L.sheetWidth).fillMaxHeight().dropShadow(RectangleShape, shadow).background(C.surface) + .verticalScroll(rememberScrollState()).padding(horizontal = D.sheetPaddingSide, vertical = D.sheetPaddingTop), + gap = if (state.sheet == TitleSheet.Tracks) D.trackGap else if (state.sheet == TitleSheet.MediaInfo) D.infoGap else D.sheetGap) { + when (state.sheet) { + TitleSheet.Version -> VersionChoices(state) + TitleSheet.Tracks -> TrackChoices(state) + TitleSheet.MediaInfo -> MediaInformation(state) + TitleSheet.ConfirmWatched -> WatchedConfirmation(state) + TitleSheet.HiddenReceipt -> HiddenReceipt(state) + null -> Unit + } + } + } +} + +@Composable +private fun VersionChoices(state: TitleState) { + Text("Version", color = C.fg, style = TitleTextStyles.sheetTitle, modifier = Modifier.exactLineBox(TitleTextStyles.sheetTitle)) + SheetSubtitle("${state.target?.name ?: state.data.item.name} ยท ${state.data.versions.size} files") + state.data.versions.forEachIndexed { index, version -> + PlaybackChoice(version.name, listOf(version.video, version.bitrate, version.size).filter { it.isNotBlank() }.joinToString(" ยท "), version == state.version, state.sheetIndex == index, { state.sheetIndex = index }) { state.clickSheet(index) } + } + Text("Remembered for ${state.person.name} on this title.", color = C.dim, style = TitleTextStyles.caption, modifier = Modifier.exactLineBox(TitleTextStyles.caption)) +} + +@Composable +private fun TrackChoices(state: TitleState) { + val version = state.version ?: return + Text("Audio and subtitles", color = C.fg, style = TitleTextStyles.sheetTitle, modifier = Modifier.exactLineBox(TitleTextStyles.sheetTitle)) + SheetSubtitle("${state.target?.let { if (it.kind == "episode") "${it.seriesName} ยท ${it.episodeLabel}" else it.name } ?: state.data.item.name} ยท ${version.name}") + Text("Audio", color = C.dim, style = TitleTextStyles.label, modifier = Modifier.exactLineBox(TitleTextStyles.label, top = D.sheetLabelTop)) + version.audio.forEachIndexed { index, track -> + PlaybackChoice(track.label, null, track.index == state.audio?.index, state.sheetIndex == index, { state.sheetIndex = index }) { state.clickSheet(index) } + } + Text("Subtitles", color = C.dim, style = TitleTextStyles.label, modifier = Modifier.exactLineBox(TitleTextStyles.label, top = D.sheetLabelTop)) + val start = version.audio.size + PlaybackChoice("Off", null, state.subtitleIndex == -1, state.sheetIndex == start, { state.sheetIndex = start }) { state.clickSheet(start) } + version.subtitles.forEachIndexed { index, track -> + val position = start + index + 1 + PlaybackChoice(track.label, null, track.index == state.subtitleIndex, state.sheetIndex == position, { state.sheetIndex = position }) { state.clickSheet(position) } + } + val done = start + version.subtitles.size + 1 + TitleControl(TitleOption("done", "Done", "", primary = true, icon = false), state.sheetIndex == done, Modifier.padding(top = D.sheetButtonTop).sheetFocused(state.sheetIndex == done), onFocus = { state.sheetIndex = done }) { state.clickSheet(done) } +} + +@Composable +private fun PlaybackChoice(label: String, why: String?, selected: Boolean, focused: Boolean, onFocus: () -> Unit, onClick: () -> Unit) { + val foreground = if (focused) C.onFocus else C.fg + val sizing = if (why == null) Modifier.height(D.trackHeight) else Modifier.padding(vertical = D.versionRowVertical) + Row(Modifier.fillMaxWidth().sheetFocused(focused).titlePointerFocus(onFocus).focusScale(focused, WolfskinTokens.Focus.scaleRow) + .background(if (focused) C.fg else C.listRowRest, RoundedCornerShape(WolfskinTokens.Radius.listRow)) + .clickable(onClick = onClick).then(sizing).padding(horizontal = D.sheetRowSide), + horizontalArrangement = Arrangement.spacedBy(D.personGap), verticalAlignment = Alignment.CenterVertically) { + CssColumn(Modifier.weight(1f)) { + Text(label, color = foreground, style = TitleTextStyles.listTitle, modifier = Modifier.exactLineBox(TitleTextStyles.listTitle)) + if (why != null) Text(why, color = foreground.copy(alpha = .8f), style = TitleTextStyles.caption, modifier = Modifier.exactLineBox(TitleTextStyles.caption)) + } + TitleRadio(selected, focused) + } +} + +@Composable +private fun MediaInformation(state: TitleState) { + val version = state.version ?: return + Text("Media info", color = C.fg, style = TitleTextStyles.sheetTitle, modifier = Modifier.exactLineBox(TitleTextStyles.sheetTitle)) + SheetSubtitle(state.target?.let { if (it.kind == "episode") "${it.seriesName} ยท ${it.episodeLabel}" else it.name } ?: state.data.item.name) + MediaInfoSection("General", listOf("Container" to version.container, "Size" to version.size.ifEmpty { "not known" }, "Bitrate" to version.bitrate, "Runtime" to (state.target?.runtime ?: "not known"))) + MediaInfoSection("Video", listOf("Stream" to version.video)) + MediaInfoSection("Audio", version.audio.mapIndexed { index, track -> "Track ${index + 1}" to (track.label + if (track.isDefault) " (default)" else "") }) + MediaInfoSection("Subtitles", version.subtitles.mapIndexed { index, track -> "Track ${index + 1}" to track.label }) + TitleControl(TitleOption("close", "Close", "", primary = true, icon = false), true, Modifier.padding(top = D.sheetButtonTop).sheetFocused(true), onFocus = { state.sheetIndex = 0 }) { state.clickSheet(0) } +} + +@Composable +private fun MediaInfoSection(label: String, values: List>) { + Text(label, color = C.dim, style = TitleTextStyles.label, modifier = Modifier.exactLineBox(TitleTextStyles.label, top = D.sheetLabelTop)) + CssColumn(gap = D.infoRowGap) { values.forEach { (name, value) -> + Row(Modifier.fillMaxWidth().exactLineBox(TitleTextStyles.caption), horizontalArrangement = Arrangement.spacedBy(D.infoColumnGap)) { + Text(name, color = C.dim, style = TitleTextStyles.infoKey, modifier = Modifier.width(D.infoLabelWidth)) + Text(value, color = C.fg, style = TitleTextStyles.caption) + } + } } +} + +@Composable +private fun WatchedConfirmation(state: TitleState) { + val verb = if (state.watched) "unwatched" else "watched" + Text("Mark the whole series as $verb?", color = C.fg, style = TitleTextStyles.sheetTitle, modifier = Modifier.exactLineBox(TitleTextStyles.sheetTitle)) + SheetSubtitle("Every episode of ${state.data.item.name} changes for ${state.person.name}.") + Row(Modifier.padding(top = D.sheetButtonTop), horizontalArrangement = Arrangement.spacedBy(L.buttonGap)) { + TitleControl(TitleOption("confirm", "Mark as $verb", "", primary = true, icon = false), state.sheetIndex == 0, Modifier.sheetFocused(state.sheetIndex == 0), onFocus = { state.sheetIndex = 0 }) { state.clickSheet(0) } + TitleControl(TitleOption("cancel", "Cancel", "", icon = false), state.sheetIndex == 1, Modifier.sheetFocused(state.sheetIndex == 1), onFocus = { state.sheetIndex = 1 }, overArtwork = false) { state.clickSheet(1) } + } +} + +@Composable +private fun SheetSubtitle(text: String) { + Text(text, color = C.muted, style = TitleTextStyles.body, modifier = Modifier.exactLineBox(TitleTextStyles.body, top = D.sheetSubLift, bottom = D.sheetSubBottom)) +} + +@Composable +private fun HiddenReceipt(state: TitleState) { + Column(Modifier.fillMaxWidth().background(C.listRowRest, RoundedCornerShape(WolfskinTokens.Radius.panel)).padding(horizontal = D.receiptSide, vertical = D.receiptTop), + verticalArrangement = Arrangement.spacedBy(D.receiptGap)) { + Row(horizontalArrangement = Arrangement.spacedBy(D.iconGap), verticalAlignment = Alignment.CenterVertically) { + Glyph("check", C.fg, Modifier.size(D.receiptIcon)) + Text("Hidden from your picks", color = C.fg, style = TitleTextStyles.receiptTitle) + } + Text("${state.data.item.name} leaves every row of ${state.person.name}โ€™s picks. It waits under Hidden picks at the end of Discover.", color = C.muted, style = TitleTextStyles.body) + } + Row(Modifier.padding(top = D.sheetButtonTop), horizontalArrangement = Arrangement.spacedBy(L.buttonGap)) { + TitleControl(TitleOption("undo", "Undo", "", primary = true, icon = false), state.sheetIndex == 0, Modifier.sheetFocused(state.sheetIndex == 0), onFocus = { state.sheetIndex = 0 }) { state.clickSheet(0) } + TitleControl(TitleOption("done", "Done", "", icon = false), state.sheetIndex == 1, Modifier.sheetFocused(state.sheetIndex == 1), onFocus = { state.sheetIndex = 1 }, overArtwork = false) { state.clickSheet(1) } + } +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/TitlePage.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/TitlePage.kt new file mode 100644 index 00000000..85f847f5 --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/TitlePage.kt @@ -0,0 +1,209 @@ +package org.justinvisser.wolfskin.design + +import androidx.compose.ui.layout.onGloballyPositioned +import androidx.compose.ui.layout.boundsInRoot +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.focusable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import kotlinx.coroutines.delay +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.derivedStateOf +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import androidx.compose.foundation.gestures.animateScrollBy +import androidx.compose.animation.core.tween +import androidx.compose.animation.core.CubicBezierEasing +import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.Modifier +import androidx.compose.ui.Alignment +import androidx.compose.ui.focus.FocusRequester +import androidx.compose.ui.focus.focusRequester +import androidx.compose.ui.input.key.KeyEventType +import androidx.compose.ui.input.key.onPreviewKeyEvent +import androidx.compose.ui.input.key.type +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.semantics.stateDescription +import androidx.compose.ui.unit.Dp +import androidx.tv.material3.Text +import org.justinvisser.wolfskin.design.WolfskinTokens.Color as C +import org.justinvisser.wolfskin.design.WolfskinTokens.Layout as L +import org.justinvisser.wolfskin.design.WolfskinTokens.Title as D + +/** The shared shell remains authoritative; title sheets overlay it and trap all input. */ +@Composable +fun TitleSurface(state: TitleState, shell: ShellState, modifier: Modifier = Modifier) { + val view = shell.view + LaunchedEffect(view, state.data.savedAt) { view.savedAt = state.data.savedAt } + Box(modifier.fillMaxSize().onPreviewKeyEvent { event -> + // No content target exists during an initial load; nav Down must not enter a skeleton. + if (state.data.status != TitleReadStatus.Loading || shell.pickerVisible || shell.requestsVisible) false + else when (readShellKey(event)) { + ShellKey.Down -> true + ShellKey.Back -> { + if (event.type == KeyEventType.KeyDown && event.nativeKeyEvent.repeatCount == 0) state.back(shell) + true + } + else -> false + } + }) { + val focusOwner = remember(shell) { { shell.navFocused = false } } + androidx.compose.runtime.CompositionLocalProvider(LocalTitleFocusOwner provides focusOwner) { + ShellSurface(shell, handlesContentKeys = false) { TitlePage(state, shell, it) } + } + if (!shell.pickerVisible && state.sheet != null) TitleOptionsSheet(state, shell) + if (!shell.pickerVisible) TitleNotice(state.toast, Modifier.align(Alignment.TopEnd)) { state.toast = null } + } +} + +/** Playback and person reads share one calm, timed notice above the persistent nav. */ +@Composable +internal fun TitleNotice(message: String?, modifier: Modifier = Modifier, onDismiss: () -> Unit) { + LaunchedEffect(message) { + if (message != null) { delay(WolfskinTokens.Motion.toast.toLong()); onDismiss() } + } + if (message != null) RecoveryToast(message, modifier) +} + +/** One keyed vertical frame renders the exact header, season, cast and related order. */ +@Composable +fun TitlePage(state: TitleState, shell: ShellState, modifier: Modifier = Modifier) { + val density = LocalDensity.current + val list = shell.view.listState + var wheelPending by remember { mutableStateOf(false) } + val focus = remember { FocusRequester() } + LaunchedEffect(state.sheet, shell.navFocused, shell.pickerVisible) { + if (state.sheet == null && !shell.navFocused && !shell.pickerVisible) focus.requestFocus() + } + val displayedRows = remember(state.data) { + buildList { + add("header") + if (state.data.status != TitleReadStatus.Ready) return@buildList + if (state.data.item.held && state.data.item.kind == "tv" && state.data.item.seasons > 0) { + add("seasons") + if (state.data.episodesStatus == TitleReadStatus.Loading || state.data.episodes.isNotEmpty()) add("episodes") + } + if (state.data.castStatus == TitleReadStatus.Loading || state.data.cast.isNotEmpty()) add("cast") + if (state.data.related.isNotEmpty()) add("related") + } + } + val rowOffsets = remember(displayedRows, density) { + FloatArray(displayedRows.size + 1).apply { + displayedRows.forEachIndexed { index, row -> this[index + 1] = this[index] + with(density) { titleRowHeight(row).toPx() } } + } + } + val position by remember(list, rowOffsets) { derivedStateOf { + rowOffsets[list.firstVisibleItemIndex.coerceAtMost(rowOffsets.lastIndex)] + list.firstVisibleItemScrollOffset + } } + LaunchedEffect(state.row, shell.navFocused, state.data.status, displayedRows) { + if (state.data.status == TitleReadStatus.Loading) shell.focusNav(shell.currentTab) + val index = if (shell.navFocused) 0 else displayedRows.indexOf(state.row).coerceAtLeast(0) + val y = rowOffsets[index] + val height = with(density) { titleRowHeight(state.row).toPx() } + val target = if (index == 0 || (y < with(density) { L.windowAhead.toPx() } && y + height <= with(density) { (WolfskinTokens.Shell.stageHeight - L.safeTopPicker).toPx() })) 0f + else y - with(density) { L.pinnedLine.toPx() } + if (target != position) list.animateScrollBy(target - position, titleFrameScrollSpec) + } + val dim by remember(rowOffsets, list) { derivedStateOf { (position / D.dimScrollPx).coerceAtMost(D.dimMaximum) } } + val lastVisible by remember(list) { derivedStateOf { list.layoutInfo.visibleItemsInfo.lastOrNull()?.index ?: -1 } } + val nextArtRow = remember(displayedRows, lastVisible) { if (lastVisible < 0) null else displayedRows.drop(lastVisible + 1).firstOrNull { it == "cast" || it == "episodes" || it == "related" } } + TitleRowPrefetch(state.data, nextArtRow) + Box(modifier.focusRequester(focus).testTag("title-page").semantics { stateDescription = "${state.data.item.id}:${state.row}:${state.column}:${state.sheet}" } + .titleWheel { if (state.data.status == TitleReadStatus.Ready) { wheelPending = true; shell.navFocused = false } } + .onPreviewKeyEvent { event -> + val key = readShellKey(event) + if (key != null && key != ShellKey.Back && event.type == KeyEventType.KeyDown && wheelPending) { + val visible = list.layoutInfo.visibleItemsInfo.firstOrNull { + it.key in state.rows && it.offset + it.size > with(density) { L.pinnedLine.roundToPx() } + }?.key as? String ?: "header" + state.focus(visible, state.columns[visible] ?: 0) + wheelPending = false + if (key != ShellKey.Ok) return@onPreviewKeyEvent true + } + key != null && state.key(key, event.type == KeyEventType.KeyDown, event.nativeKeyEvent.repeatCount, shell) + }.focusable()) { + // This remains visible behind the scrolled rows; it is not an off-screen header image. + TitleBackdrop(state.data.item, Modifier.fillMaxSize()) + Box(Modifier.fillMaxSize().graphicsLayer { alpha = dim }.background(C.bg)) + if (state.data.status == TitleReadStatus.Unavailable) TitleReadError(state) + else LazyColumn(state = list, modifier = Modifier.fillMaxSize()) { + displayedRows.forEach { id -> item(key = id, contentType = if (id == "header") "header" else if (id == "seasons") "chips" else "shelf") { + val active = state.row == id && !shell.navFocused && state.sheet == null + when (id) { + "header" -> Box(Modifier.height(L.row_dhead)) { TitleHeader(state, active) } + "seasons" -> TitleSeasons(state, active) + "episodes" -> TitleMediaShelf(state, true, active) + "cast" -> TitleCast(state, active) + "related" -> TitleMediaShelf(state, false, active) + } + } } + item(key = "end-padding", contentType = "spacer") { + Spacer(Modifier.height((WolfskinTokens.Shell.stageHeight - L.pinnedLine - titleRowHeight(displayedRows.last())).coerceAtLeast(D.minimumEndPadding))) + } + } + } +} + +private fun titleRowHeight(row: String): Dp = when (row) { + "header" -> L.row_dhead + "seasons" -> L.row_chips + "episodes" -> L.rowHeadingBand + WolfskinTokens.Card.tileH + L.rowGapAfter + "cast" -> D.castHeight + else -> L.rowHeadingBand + WolfskinTokens.Card.posterH + WolfskinTokens.Card.posterCaptionBand + L.rowGapAfter +} + +@Composable +private fun TitleSeasons(state: TitleState, active: Boolean) { + val focusOwner = LocalTitleFocusOwner.current + androidx.compose.foundation.lazy.LazyRow(Modifier.height(L.row_chips).padding(top = D.chipTop), contentPadding = androidx.compose.foundation.layout.PaddingValues(horizontal = L.safeSide), horizontalArrangement = Arrangement.spacedBy(D.chipGap)) { + items(state.data.seasonNumbers.size, key = { "season-${state.data.seasonNumbers[it]}" }, contentType = { "chip" }) { index -> + val number = state.data.seasonNumbers[index] + val focused = active && state.column == index + val selected = state.season == number + val shape = RoundedCornerShape(WolfskinTokens.Radius.chip) + Box(Modifier.height(D.chipHeight).titlePointerFocus { state.focus("seasons", index) }.focusScale(focused, WolfskinTokens.Focus.scaleControl) + .onGloballyPositioned { state.recordCenter("seasons", index, it.boundsInRoot().center.x) } + .background(if (focused) C.fg else if (selected) C.accentSoft else C.chipRest, shape) + .then(if (selected && !focused) Modifier.border(D.chipBorder, C.accent, shape) else Modifier) + .clickable { focusOwner?.invoke(); state.click("seasons", index) }.padding(horizontal = D.chipPadding), contentAlignment = Alignment.Center) { + Text("Season $number", color = if (focused) C.onFocus else if (selected) C.accentText else C.fg, style = WolfskinTokens.Type.label) + } + } + } +} + +@Composable +private fun TitleReadError(state: TitleState) { + Column(Modifier.offset(L.safeSide, D.errorTop).width(L.stateWidth) + .background(C.surface, RoundedCornerShape(WolfskinTokens.Radius.panel)) + .border(WolfskinTokens.SavedIndicator.border, C.border, RoundedCornerShape(WolfskinTokens.Radius.panel)) + .padding(WolfskinTokens.SavedIndicator.border) + .padding(horizontal = D.errorSide, vertical = D.errorVertical)) { + Row(Modifier.padding(bottom = D.errorHeadingBottom), horizontalArrangement = Arrangement.spacedBy(D.iconGap), verticalAlignment = Alignment.CenterVertically) { + Glyph("alert", C.warn, Modifier.size(D.receiptIcon)) + Text(if (state.data.item.kind == "person") "This person canโ€™t be read" else "This title canโ€™t be read", color = C.fg, style = TitleTextStyles.errorTitle) + } + Text("${if (state.data.connection == TitleConnection.SignedOut) "Jellyfin" else "Conductarr"} didnโ€™t answer, and this TV has no saved copy of the page yet.", color = C.muted, style = TitleTextStyles.body, modifier = Modifier.padding(bottom = D.errorBodyBottom)) + Row(horizontalArrangement = Arrangement.spacedBy(L.buttonGap)) { state.options.forEachIndexed { index, option -> TitleControl(option, state.column == index, onFocus = { state.focus("header", index) }, overArtwork = false) { state.click("header", index) } } } + } +} + +internal val titleFrameScrollSpec = tween(WolfskinTokens.Motion.scroll, easing = CubicBezierEasing(.33f, 1f, .68f, 1f)) diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/TitlePointer.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/TitlePointer.kt new file mode 100644 index 00000000..ab763b8a --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/TitlePointer.kt @@ -0,0 +1,41 @@ +package org.justinvisser.wolfskin.design + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.compositionLocalOf +import androidx.compose.runtime.getValue +import androidx.compose.runtime.rememberUpdatedState +import androidx.compose.ui.Modifier +import androidx.compose.ui.input.pointer.PointerEventType +import androidx.compose.ui.input.pointer.pointerInput + +/** Pointing at owned content exits nav focus through the same shell state as a remote Down. */ +val LocalTitleFocusOwner = compositionLocalOf<(() -> Unit)?> { null } + +/** Hover changes logical focus without activating a button or arming an OK press. */ +@Composable +fun Modifier.titlePointerFocus(onFocus: (() -> Unit)?): Modifier { + if (onFocus == null) return this + val latest by rememberUpdatedState(onFocus) + val owner = LocalTitleFocusOwner.current + return pointerInput(owner) { + awaitPointerEventScope { + while (true) { + val event = awaitPointerEvent() + if (event.type == PointerEventType.Enter) { owner?.invoke(); latest() } + } + } + } +} + +/** Observe wheel input without consuming the frame's native scroll gesture. */ +@Composable +fun Modifier.titleWheel(onScroll: () -> Unit): Modifier { + val latest by rememberUpdatedState(onScroll) + return pointerInput(Unit) { + awaitPointerEventScope { + while (true) { + if (awaitPointerEvent().type == PointerEventType.Scroll) latest() + } + } + } +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/TitlePrefetch.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/TitlePrefetch.kt new file mode 100644 index 00000000..641fead0 --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/TitlePrefetch.kt @@ -0,0 +1,32 @@ +package org.justinvisser.wolfskin.design + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect +import androidx.compose.ui.platform.LocalContext +import coil3.request.Disposable + +/** Read the next hidden art row into the bounded loader, cancelling work when the window changes. */ +@Composable +internal fun TitleRowPrefetch(data: TitlePageData, row: String?) { + val context = LocalContext.current + if (row == null || data.status != TitleReadStatus.Ready) return + if (LocalTitleBitmaps.current.isNotEmpty()) return + val loader = WolfskinImages.loader(context) + DisposableEffect(loader, context, row, data.cast, data.episodes, data.related) { + val requests = ArrayList() + fun queue(path: String?, width: Int, height: Int, poster: Boolean = false) { + if (path != null) requests.add(loader.enqueue(WolfskinImages.request(context, path, width, height, poster))) + } + when (row) { + "cast" -> for (index in 0 until minOf(data.cast.size, WolfskinTokens.Card.personSlots)) + queue(data.cast[index].portrait, WolfskinTokens.Image.castRequestWidth, WolfskinTokens.Image.castRequestHeight) + "episodes" -> for (index in 0 until minOf(data.episodes.size, WolfskinTokens.Card.tileSlots)) { + val item = data.episodes[index] + queue(if (item.isPosterBackdrop) item.poster else item.backdrop, WolfskinTokens.Image.tileRequestWidth, WolfskinTokens.Image.tileRequestHeight) + } + "related" -> for (index in 0 until minOf(data.related.size, WolfskinTokens.Card.posterSlots)) + queue(data.related[index].poster, WolfskinTokens.Image.posterRequestWidth, WolfskinTokens.Image.posterRequestHeight, true) + } + onDispose { requests.forEach { it.dispose() } } + } +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/TitleSheetFocus.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/TitleSheetFocus.kt new file mode 100644 index 00000000..d6c46049 --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/TitleSheetFocus.kt @@ -0,0 +1,16 @@ +package org.justinvisser.wolfskin.design + +import androidx.compose.foundation.relocation.BringIntoViewRequester +import androidx.compose.foundation.relocation.bringIntoViewRequester +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier + +/** Logical remote focus must reveal its row even though Android focus stays on the modal owner. */ +@Composable +internal fun Modifier.sheetFocused(focused: Boolean): Modifier { + val request = remember { BringIntoViewRequester() } + LaunchedEffect(focused) { if (focused) request.bringIntoView() } + return bringIntoViewRequester(request) +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/TitleShelf.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/TitleShelf.kt new file mode 100644 index 00000000..dcfaadc7 --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/TitleShelf.kt @@ -0,0 +1,166 @@ +package org.justinvisser.wolfskin.design + +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.animation.core.tween +import androidx.compose.animation.core.CubicBezierEasing +import androidx.compose.foundation.gestures.animateScrollBy +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.wrapContentWidth +import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.foundation.lazy.LazyListState +import androidx.compose.ui.layout.onGloballyPositioned +import androidx.compose.ui.layout.boundsInRoot +import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.zIndex +import androidx.tv.material3.Text +import org.justinvisser.wolfskin.design.WolfskinTokens.Color as C +import org.justinvisser.wolfskin.design.WolfskinTokens.Layout as L +import org.justinvisser.wolfskin.design.WolfskinTokens.Title as D + +/** Cast occupies the first shelf after films, and follows season episodes on series. */ +@Composable +fun TitleCast(state: TitleState, active: Boolean) { + val track = rememberLazyListState() + val focusOwner = LocalTitleFocusOwner.current + val pitch = with(LocalDensity.current) { WolfskinTokens.Card.personPitch.toPx() } + LaunchedEffect(state.column, active) { if (active) track.keepColumnInWindow(state.column, WolfskinTokens.Card.personSlots, pitch) } + Column(Modifier.height(D.castHeight)) { + Text("Cast", color = C.fg, style = WolfskinTokens.Type.rowHeading, modifier = Modifier.padding(start = L.safeSide).height(L.rowHeadingBand)) + LazyRow(state = track, contentPadding = PaddingValues(horizontal = L.safeSide), horizontalArrangement = Arrangement.spacedBy(WolfskinTokens.Card.personGap)) { + if (state.data.castStatus == TitleReadStatus.Loading) { + items(WolfskinTokens.Card.personSlots, key = { "cast-skeleton-$it" }, contentType = { "skeleton" }) { + Box(Modifier.size(L.castCircle).background(C.surface, CircleShape)) + } + } else itemsIndexed(state.data.cast, key = { _, person -> person.id }, contentType = { _, _ -> "person" }) { index, person -> + val focused = active && state.column == index + Box(Modifier.size(WolfskinTokens.Card.personW, WolfskinTokens.Card.personH).zIndex(if (focused) 1f else 0f) + .onGloballyPositioned { state.recordCenter("cast", index, it.boundsInRoot().center.x) } + .titlePointerFocus { state.focus("cast", index) }.focusScale(focused, WolfskinTokens.Focus.scaleCard).clickable { focusOwner?.invoke(); state.click("cast", index) }.testTag("title-cast-${person.id}")) { + PersonPortrait(person, Modifier.size(L.castCircle).focusRing(focused, L.castCircle / 2, WolfskinTokens.Focus.ringCardGap, WolfskinTokens.Focus.ringCardRing, C.accent).clip(CircleShape)) + Column(Modifier.offset(x = -D.castNameSide, y = D.castNameTop).wrapContentWidth(Alignment.Start, unbounded = true).width(L.castCircle + D.castNameSide * 2), horizontalAlignment = Alignment.CenterHorizontally) { + Text(person.name, color = C.fg, style = TitleTextStyles.castName, modifier = Modifier.exactLineBox(TitleTextStyles.castName), maxLines = 1, overflow = TextOverflow.Ellipsis, textAlign = TextAlign.Center) + Text(person.character, color = C.muted, style = TitleTextStyles.caption, modifier = Modifier.exactLineBox(TitleTextStyles.caption), maxLines = 1, overflow = TextOverflow.Ellipsis, textAlign = TextAlign.Center) + } + } + } + } + } +} + +/** Episode and related shelves are lazy, keyed and keep their focused card above adjacent art. */ +@Composable +fun TitleMediaShelf(state: TitleState, episodes: Boolean, active: Boolean) { + val titles = if (episodes) state.data.episodes else state.data.related + val id = if (episodes) "episodes" else "related" + val width = if (episodes) WolfskinTokens.Card.tileW else WolfskinTokens.Card.posterW + val height = if (episodes) WolfskinTokens.Card.tileH else WolfskinTokens.Card.posterH + val track = rememberLazyListState() + val visible = if (episodes) WolfskinTokens.Card.tileSlots else WolfskinTokens.Card.posterSlots + val pitch = with(LocalDensity.current) { (if (episodes) WolfskinTokens.Card.tilePitch else WolfskinTokens.Card.posterPitch).toPx() } + LaunchedEffect(state.column, active) { if (active) track.keepColumnInWindow(state.column, visible, pitch) } + Column(Modifier.height(L.rowHeadingBand + height + L.rowGapAfter + if (episodes) WolfskinTokens.Shell.zero else WolfskinTokens.Card.posterCaptionBand)) { + Text(if (episodes) "Season ${state.season}" else "More like this", color = C.fg, style = WolfskinTokens.Type.rowHeading, modifier = Modifier.padding(start = L.safeSide).height(L.rowHeadingBand)) + LazyRow(state = track, contentPadding = PaddingValues(horizontal = L.safeSide), horizontalArrangement = Arrangement.spacedBy(WolfskinTokens.Card.posterGap)) { + if (episodes && state.data.episodesStatus == TitleReadStatus.Loading) { + items(visible, key = { "episode-skeleton-$it" }, contentType = { "skeleton" }) { + Box(Modifier.size(width, height).background(C.surface, RoundedCornerShape(WolfskinTokens.Radius.card))) + } + } else itemsIndexed(titles, key = { _, item -> item.id }, contentType = { _, _ -> if (episodes) "tile" else "poster" }) { index, item -> + TitlePoster(item, active && state.column == index, Modifier.width(width) + .onGloballyPositioned { state.recordCenter(id, index, it.boundsInRoot().center.x) }, + episodes, state.data.connection != TitleConnection.SignedOut, onFocus = { state.focus(id, index) }) { state.click(id, index) } + } + } + } +} + +/** Posters draw art at rest, with facts only in the reserved focused-caption band. */ +@Composable +fun TitlePoster(item: TitleItem, focused: Boolean, modifier: Modifier = Modifier, tile: Boolean = false, ratingsVisible: Boolean = true, catalogue: Boolean = false, onFocus: (() -> Unit)? = null, onClick: () -> Unit) { + val focusOwner = LocalTitleFocusOwner.current + Column(modifier.zIndex(if (focused) 1f else 0f)) { + if (!tile) { + val bitmaps = LocalTitleBitmaps.current + val offlineArt = androidx.compose.runtime.remember(bitmaps) { if (bitmaps.isEmpty()) null else { path: String -> bitmaps[path] } } + LibraryPoster(item, focused, focused && ratingsVisible, catalogue = catalogue, + modifier = Modifier.titlePointerFocus(onFocus).clickable { focusOwner?.invoke(); onClick() }, offlineArt = offlineArt) + } else Box(Modifier.size(WolfskinTokens.Card.tileW, WolfskinTokens.Card.tileH).titlePointerFocus(onFocus).focusScale(focused, WolfskinTokens.Focus.scaleCard) + .focusRing(focused, WolfskinTokens.Radius.card, WolfskinTokens.Focus.ringCardGap, WolfskinTokens.Focus.ringCardRing, C.accent) + .clip(RoundedCornerShape(WolfskinTokens.Radius.card)).background(C.surface2).clickable { focusOwner?.invoke(); onClick() }) { + TitleTileArtwork(item) + Column(Modifier.align(Alignment.BottomStart).fillMaxWidth().background(Brush.verticalGradient(listOf(C.bg.copy(alpha = 0f), C.bg.copy(alpha = D.cardOverlayOpacity)))) + .padding(start = D.tileOverlaySide, end = D.tileOverlaySide, top = D.tileOverlayTop, bottom = D.tileOverlayBottom)) { + Text(item.seriesName ?: item.name, color = C.fg, style = WolfskinTokens.Type.button, maxLines = 1, overflow = TextOverflow.Ellipsis) + Text("${item.episodeLabel} ยท ${item.name}", color = C.muted, style = WolfskinTokens.Type.caption, maxLines = 1, overflow = TextOverflow.Ellipsis) + } + val progress = item.progress + if (progress > 0f && progress < 1f) { + Box(Modifier.align(Alignment.BottomCenter).padding(start = D.cardProgressInset, end = D.cardProgressInset, bottom = D.tileProgressBottom) + .fillMaxWidth().height(L.progressBar).clip(RoundedCornerShape(WolfskinTokens.Radius.progress)).background(C.progressTrack)) { + Box(Modifier.fillMaxWidth(progress).fillMaxHeight().background(C.accent)) + } + } + androidx.compose.animation.AnimatedVisibility(focused && ratingsVisible, enter = fadeIn(tween(WolfskinTokens.Motion.base)), exit = fadeOut(tween(WolfskinTokens.Motion.base))) { + LibraryRatingPlate(item.ratings, Modifier.fillMaxWidth()) + } + } + if (!tile) { + val availability = androidx.compose.runtime.remember(item, catalogue) { + if (catalogue) { + if (item.held) "In your library" else item.otherOwners.takeIf { it.isNotEmpty() }?.let { "In ${it.joinToString(" and ")}โ€™s library" } + } else if (item.watched) "Watched" + else if (item.resumeSeconds > 0) "${((item.runtimeSeconds - item.resumeSeconds + 30) / 60).coerceAtLeast(1)} min left" + else null + } + val facts = androidx.compose.runtime.remember(item, availability) { + listOfNotNull(item.character?.takeIf { it.isNotBlank() }?.let { "as $it" }, item.year?.toString(), + if (item.kind == "movie") { if (item.runtimeSeconds > 0) item.runtime else "Movie" } else if (item.seasons > 0) "${item.seasons} season${if (item.seasons == 1) "" else "s"}" else "Series", + availability).joinToString(" ยท ") + } + Box(Modifier.height(WolfskinTokens.Card.posterCaptionBand)) { + Caption(item.name, facts, focused, Modifier.offset(y = L.captionOffset).wrapContentWidth(Alignment.Start, unbounded = true).width(D.captionWidth), + accentLastFact = availability != null, accentFirstFact = !item.character.isNullOrBlank()) + } + } + } +} + +/** Keep a full lookahead card, but do not recenter a row when reversing direction. */ +private suspend fun LazyListState.keepColumnInWindow(column: Int, slots: Int, pitch: Float) { + val first = firstVisibleItemIndex + val next = when { + column < first -> column + column >= first + slots - 1 -> (column - slots + 2).coerceAtLeast(0) + else -> first + } + if (next != first) animateScrollBy((next - first) * pitch - firstVisibleItemScrollOffset, titleTrackScrollSpec) +} + +private val titleTrackScrollSpec = tween(WolfskinTokens.Motion.base, easing = CubicBezierEasing(.25f, .1f, .25f, 1f)) diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/TitleSlotArtwork.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/TitleSlotArtwork.kt new file mode 100644 index 00000000..242e0e6b --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/TitleSlotArtwork.kt @@ -0,0 +1,60 @@ +package org.justinvisser.wolfskin.design + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.requiredSize +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.wrapContentSize +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.blur +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.graphics.ColorMatrix +import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.unit.Dp +import org.justinvisser.wolfskin.design.WolfskinTokens.Color as C +import org.justinvisser.wolfskin.design.WolfskinTokens.Home as H + +/** Slot dimensions adapt to the shared exact-pixel artwork request, never another image loader. */ +@Composable +private fun SlotImage(source: String, width: Dp, height: Dp, modifier: Modifier = Modifier, poster: Boolean = false, colorFilter: ColorFilter? = null, onError: () -> Unit = {}) { + TitleArtwork(source, (width.value * 2).toInt(), (height.value * 2).toInt(), modifier, poster, colorFilter, onError) +} + +/** Poster-only landscapes retain the upright one-sheet above the same dimmed image wash. */ +@Composable +fun TitleArtwork(title: String, type: String, poster: String?, width: Dp, height: Dp, modifier: Modifier = Modifier, + backdrop: String? = null, posterOnly: Boolean = false, landscape: Boolean = false, hero: Boolean = false) { + val source = if (landscape) backdrop ?: poster else poster + val failed = remember(source) { androidx.compose.runtime.mutableStateOf(false) } + val missing = source == null || failed.value + Box(modifier.background(C.surface2)) { + if (!missing) { + if (landscape && (posterOnly || backdrop == null) && poster != null) { + val wash = remember(hero) { + val matrix = ColorMatrix().apply { setToSaturation(if (hero) 1.2f else 1f) } + val brightness = if (hero) .55f else .5f + for (index in 0 until 15) matrix.values[index] *= brightness + ColorFilter.colorMatrix(matrix) + } + val inset = if (hero) H.heroWashInset else H.cardWashInset + val washModifier = Modifier.wrapContentSize(Alignment.Center, unbounded = true) + .requiredSize(width + inset * 2, height + inset * 2) + .blur(if (hero) H.heroBlur else H.cardBlur) + .graphicsLayer { if (hero) { scaleX = 1.1f; scaleY = 1.1f } } + SlotImage(poster, width, height, washModifier, colorFilter = wash, onError = { failed.value = true }) + val sheetHeight = if (hero) WolfskinTokens.Layout.heroSheetHeight else height - H.cardSheetInset + val sheetWidth = if (hero) WolfskinTokens.Layout.heroSheetWidth else sheetHeight * (2f / 3f) + val sheetModifier = if (hero) Modifier.align(Alignment.TopEnd).offset(-H.heroSheetRight, H.heroSheetTop) else Modifier.offset(H.cardSheetLeft, H.cardSheetTop) + SlotImage(poster, sheetWidth, sheetHeight, sheetModifier.size(sheetWidth, sheetHeight).clip(RoundedCornerShape(if (hero) WolfskinTokens.Radius.heroSheet else WolfskinTokens.Radius.cardSheet)), poster = true, onError = { failed.value = true }) + } else SlotImage(source, if (hero) WolfskinTokens.Card.posterW * 5 else width, if (hero) WolfskinTokens.Card.posterW * 5 * (9f / 16f) else height, Modifier.fillMaxSize(), poster = !landscape, onError = { failed.value = true }) + } else if (!hero) MediaArtworkFallback(title, type == "movie", showTitle = !landscape) + else HomeAmbient(Modifier.fillMaxSize()) + } +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/TitleState.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/TitleState.kt new file mode 100644 index 00000000..c122ec9f --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/TitleState.kt @@ -0,0 +1,291 @@ +package org.justinvisser.wolfskin.design + +import androidx.compose.runtime.getValue +import androidx.compose.runtime.derivedStateOf +import androidx.compose.runtime.mutableStateMapOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue + +/** One focus controller drives the drawn screen and Android key-event replays. */ +class TitleState( + initial: TitlePageData, + val person: ShellPerson, + private val onAction: (TitleAction) -> Unit, +) { + var data by mutableStateOf(initial) + private set + var row by mutableStateOf("header") + var column by mutableStateOf(0) + val columns = mutableStateMapOf() + private val centers = HashMap>() + fun recordCenter(row: String, index: Int, x: Float) { centers.getOrPut(row) { HashMap() }[index] = x } + fun showSeasonLoading() { if (data.episodesStatus != TitleReadStatus.Loading) data = data.copy(episodesStatus = TitleReadStatus.Loading) } + fun restoreSeason() { season = data.selectedSeason ?: season; data = data.copy(episodesStatus = TitleReadStatus.Ready) } + var sheet by mutableStateOf(null) + private set + var sheetIndex by mutableStateOf(0) + var season by mutableStateOf(initial.selectedSeason ?: initial.playTarget?.season?.takeIf { it in initial.seasonNumbers } ?: initial.seasonNumbers.firstOrNull() ?: 1) + var versionId by mutableStateOf(initial.selectedVersion) + var audioIndex by mutableStateOf(initial.selectedAudio) + var subtitleIndex by mutableStateOf(initial.selectedSubtitle) + var watched by mutableStateOf(initial.watchTarget.watched) + var toast by mutableStateOf(null) + private var armedCard: String? = null + private var okHeld = false + val target: TitleItem? get() = data.playTarget ?: data.item.takeIf { it.kind == "movie" && it.held } + val version: TitleVersion? get() = data.versions.firstOrNull { it.id == versionId } ?: data.versions.firstOrNull() + val audio: TitleTrack? get() = version?.audio?.firstOrNull { it.index == audioIndex } ?: version?.audio?.firstOrNull { it.isDefault } ?: version?.audio?.firstOrNull() + val subtitle: TitleTrack? get() = version?.subtitles?.firstOrNull { it.index == subtitleIndex } + val rows: List by derivedStateOf { buildList { + add("header") + if (data.status != TitleReadStatus.Ready) return@buildList + if (data.item.held && data.item.kind == "tv" && data.item.seasons > 0) { + add("seasons") + if (data.episodesStatus == TitleReadStatus.Ready && data.episodes.isNotEmpty()) add("episodes") + } + if (data.castStatus == TitleReadStatus.Ready && data.cast.isNotEmpty()) add("cast") + if (data.related.isNotEmpty()) add("related") + } } + val options: List by derivedStateOf { titleOptions(this) } + + /** Refresh keeps the selected row and file when they still exist. */ + fun update(value: TitlePageData) { + val wasLoading = data.status == TitleReadStatus.Loading + val pendingWatched = watched != data.watchTarget.watched + val pendingVersion = versionId != data.selectedVersion + val pendingAudio = audioIndex != data.selectedAudio + val pendingSubtitle = subtitleIndex != data.selectedSubtitle + data = value + if (wasLoading || season !in value.seasonNumbers) season = value.selectedSeason ?: value.playTarget?.season?.takeIf { it in value.seasonNumbers } ?: value.seasonNumbers.firstOrNull() ?: 1 + if (!pendingWatched) watched = value.watchTarget.watched + if (!pendingVersion) versionId = value.selectedVersion + if (!pendingAudio) audioIndex = value.selectedAudio + if (!pendingSubtitle) subtitleIndex = value.selectedSubtitle + if (row !in rows) { row = "header"; column = 0 } + column = column.coerceAtMost(rowSize(row).minus(1).coerceAtLeast(0)) + } + + /** Pointer focus and D-pad use the same row memory. */ + fun focus(targetRow: String, targetColumn: Int) { + columns[row] = column + row = targetRow + column = targetColumn + columns[row] = column + } + /** Pointer clicks activate the same state transition as a completed remote press. */ + fun click(targetRow: String, targetColumn: Int) { + focus(targetRow, targetColumn) + activate() + } + + + /** Keep the last confirmed selections separate from immediate, optimistic UI feedback. */ + fun confirmPlayback(action: TitleAction) { + data = when (action) { + is TitleAction.Version -> data.copy(selectedVersion = action.version.id, selectedAudio = null, selectedSubtitle = -1) + is TitleAction.Track -> data.copy(selectedVersion = action.version.id, selectedAudio = action.audio, selectedSubtitle = action.subtitle) + is TitleAction.Watched -> data.copy(watchTarget = data.watchTarget.copy(watched = action.watched)) + else -> data + } + } + + /** A failed older write cannot undo a newer selection still waiting to save. */ + fun rejectPlayback(action: TitleAction) { + when (action) { + is TitleAction.Version -> if (versionId == action.version.id) { + versionId = data.selectedVersion; audioIndex = data.selectedAudio; subtitleIndex = data.selectedSubtitle + } + is TitleAction.Track -> if (audioIndex == action.audio && subtitleIndex == action.subtitle) { + audioIndex = data.selectedAudio; subtitleIndex = data.selectedSubtitle + } + is TitleAction.Watched -> if (watched == action.watched) watched = data.watchTarget.watched + else -> Unit + } + } + + /** Key-up can only activate the same card that armed the first key-down. */ + fun key(key: ShellKey, down: Boolean, repeat: Int, shell: ShellState): Boolean { + if (key == ShellKey.Ok) { + if (!down) { + okHeld = false + val card = "$row:$column" + if (armedCard == card && sheet == null && !shell.navFocused) activate() + armedCard = null + return true + } + if (repeat > 0 || okHeld) return true + okHeld = true + if (sheet == null && (row == "cast" || row == "related" || row == "episodes")) { + armedCard = "$row:$column" + return true + } + } else { + if (!down) return true + armedCard = null + } + if (sheet != null) { sheetKey(key); return true } + when (key) { + ShellKey.Back -> back(shell) + ShellKey.Up -> if (row == "header") { shell.focusNav(shell.currentTab) } else moveRow(-1) + ShellKey.Down -> moveRow(1) + ShellKey.Left -> focus(row, (column - 1).coerceAtLeast(0)) + ShellKey.Right -> focus(row, (column + 1).coerceAtMost((rowSize(row) - 1).coerceAtLeast(0))) + ShellKey.Ok -> activate() + } + return true + } + + /** Sheets and shell overlays close first; a pushed title/person pops from content or nav. */ + fun back(shell: ShellState) { + when { + sheet != null -> sheet = null + shell.pickerVisible || shell.requestsVisible -> shell.key(ShellKey.Back) + else -> onAction(TitleAction.Pop) + } + } + + /** Pointer selection stays inside the modal's row order. */ + fun clickSheet(index: Int) { sheetIndex = index; sheetKey(ShellKey.Ok) } + + private fun moveRow(delta: Int) { + val index = (rows.indexOf(row) + delta).coerceIn(0, rows.lastIndex) + val next = rows[index] + val x = centers[row]?.get(column) + val nearest = if (x != null) centers[next]?.entries?.minByOrNull { kotlin.math.abs(it.value - x) }?.key else null + focus(next, (columns[next] ?: nearest ?: column).coerceAtMost((rowSize(next) - 1).coerceAtLeast(0))) + } + + private fun rowSize(id: String): Int = when (id) { + "header" -> options.size + "seasons" -> data.seasonNumbers.size + "episodes" -> data.episodes.size + "cast" -> data.cast.size + "related" -> data.related.size + else -> 0 + } + + private fun activate() { + when (row) { + "cast" -> data.cast.getOrNull(column)?.let { onAction(TitleAction.Person(it)) } + "related" -> data.related.getOrNull(column)?.let { onAction(TitleAction.OpenTitle(it)) } + "episodes" -> data.episodes.getOrNull(column)?.let { onAction(TitleAction.OpenTitle(it)) } + "seasons" -> { season = data.seasonNumbers[column]; onAction(TitleAction.Season(season)) } + "header" -> options.getOrNull(column)?.let { activateOption(it.id) } + } + } + + private fun activateOption(id: String) { + when (id) { + "play", "restart" -> target?.let { onAction(TitleAction.Play(it, id == "restart")) } + "version" -> { sheetIndex = data.versions.indexOf(version).coerceAtLeast(0); sheet = TitleSheet.Version } + "tracks" -> { sheetIndex = 0; sheet = TitleSheet.Tracks } + "more" -> { sheetIndex = 0; sheet = TitleSheet.MediaInfo } + "watched" -> if (data.watchTarget.kind == "tv") { sheetIndex = 0; sheet = TitleSheet.ConfirmWatched } else toggleWatched() + "trailer" -> data.trailerUrl?.let { onAction(TitleAction.Trailer(it)) } + "seasons" -> focus("seasons", data.seasonNumbers.indexOf(season).coerceAtLeast(0)) + "retry" -> onAction(TitleAction.Retry) + "back" -> onAction(TitleAction.Pop) + "request", "other", "add" -> onAction(TitleAction.Request(data.item, id != "request")) + "status" -> onAction(TitleAction.Requests(data.item)) + "hide", "unhide" -> { + val hidden = id == "hide" + data = data.copy(hidden = hidden) + onAction(TitleAction.Hide(data.item, hidden)) + if (hidden) { sheetIndex = 0; sheet = TitleSheet.HiddenReceipt } else toast = "Back in your picks." + } + } + } + + private fun toggleWatched() { + watched = !watched + onAction(TitleAction.Watched(data.watchTarget, watched)) + } + + private fun sheetKey(key: ShellKey) { + if (key == ShellKey.Back) { sheet = null; return } + val current = version + val size = when (sheet) { + TitleSheet.Version -> data.versions.size + TitleSheet.Tracks -> (current?.audio?.size ?: 0) + (current?.subtitles?.size ?: 0) + 2 + TitleSheet.ConfirmWatched, TitleSheet.HiddenReceipt -> 2 + else -> 1 + } + when (key) { + ShellKey.Up, ShellKey.Left -> sheetIndex = (sheetIndex - 1).coerceAtLeast(0) + ShellKey.Down, ShellKey.Right -> sheetIndex = (sheetIndex + 1).coerceAtMost(size - 1) + ShellKey.Ok -> when (sheet) { + TitleSheet.Version -> { + val selected = data.versions[sheetIndex] + versionId = selected.id + audioIndex = null + subtitleIndex = -1 + target?.let { onAction(TitleAction.Version(it, selected)) } + sheet = null + } + TitleSheet.Tracks -> if (current != null) selectTrack(current) + TitleSheet.ConfirmWatched -> { if (sheetIndex == 0) toggleWatched(); sheet = null } + TitleSheet.HiddenReceipt -> { + sheet = null + if (sheetIndex == 0) { + data = data.copy(hidden = false) + onAction(TitleAction.Hide(data.item, false)) + } else onAction(TitleAction.Pop) + } + else -> sheet = null + } + } + } + + private fun selectTrack(current: TitleVersion) { + when { + sheetIndex < current.audio.size -> audioIndex = current.audio[sheetIndex].index + sheetIndex == current.audio.size -> subtitleIndex = -1 + sheetIndex <= current.audio.size + current.subtitles.size -> subtitleIndex = current.subtitles[sheetIndex - current.audio.size - 1].index + else -> { sheet = null; return } + } + target?.let { onAction(TitleAction.Track(it, current, audio?.index, subtitleIndex)) } + } +} + +/** Button order follows the file, resume, ownership and authentication facts, never synthetic availability. */ +fun titleOptions(state: TitleState): List = buildList { + val data = state.data + val item = data.item + val target = state.target + if (data.status != TitleReadStatus.Ready) { + if (data.status == TitleReadStatus.Unavailable) { + add(TitleOption("retry", "Try again", "", primary = true, icon = false)) + add(TitleOption("back", "Back", "", icon = false)) + } + return@buildList + } + if (item.held) { + if (target != null) { + val verb = if (target.resumeSeconds > 0) "Resume" else "Play" + add(TitleOption("play", verb + if (target.kind == "episode") " ${target.episodeLabel}" else "", "play", primary = true, icon = false)) + if (target.resumeSeconds > 0) add(TitleOption("restart", "Restart", "restart", "play from the beginning")) + if (data.versions.size > 1) add(TitleOption("version", "Version", "version", state.version?.name.orEmpty())) + add(TitleOption("tracks", "Audio and subtitles", "tracks", "${state.audio?.label.orEmpty()} ยท subtitles ${state.subtitle?.label ?: "off"}")) + } + val series = data.watchTarget.kind == "tv" + add(TitleOption("watched", "Mark ${if (series) "series " else ""}as ${if (state.watched) "unwatched" else "watched"}", if (state.watched) "eye" else "eyeoff", if (data.watchTarget.kind == "episode") data.watchTarget.episodeLabel else "", on = state.watched)) + if (data.trailerUrl != null) add(TitleOption("trailer", "Play trailer", "trailer")) + if (target != null) add(TitleOption("more", "More", "more", "Media info")) + if (item.kind == "tv" && item.seasons > 0) add(TitleOption("seasons", "Seasons", "tv", icon = false)) + if (data.connection == TitleConnection.SignedIn) add(TitleOption("add", "Add for someone", "users", icon = false)) + } else if (data.connection != TitleConnection.SignedIn) { + add(TitleOption("retry", "Try again", "wifi", primary = true, icon = false)) + } else { + add(TitleOption(if (data.requestedStage == null) "request" else "status", data.requestedStage?.let { "Requested ยท $it" } ?: "Request", data.requestedStage?.let(::titleStageGlyph) ?: "plus", primary = true, icon = false)) + add(TitleOption("other", "For someone else", "users", icon = false)) + if (data.hidden) add(TitleOption("unhide", "Show again", "undo", icon = false)) + else if (data.pick) add(TitleOption("hide", "Not interested", "eyeoff", icon = false)) + } +} + +internal fun titleStageGlyph(stage: String): String = when (stage) { + "Ready" -> "check" + "Failed" -> "alert" + "Downloading", "Almost ready" -> "download" + else -> "clock" +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/TitleTextStyles.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/TitleTextStyles.kt new file mode 100644 index 00000000..69465238 --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/TitleTextStyles.kt @@ -0,0 +1,25 @@ +package org.justinvisser.wolfskin.design + +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.style.LineHeightStyle + +/** Explicit styles retain CSS leading without changing shared nav or library typography. */ +internal object TitleTextStyles { + private val lineBoxes = LineHeightStyle(LineHeightStyle.Alignment.Center, LineHeightStyle.Trim.None) + private fun TextStyle.withLineBoxes() = copy(lineHeightStyle = lineBoxes) + + val displayDetail = WolfskinTokens.Type.displayDetail.withLineBoxes() + val dLine = WolfskinTokens.Title.dLine.withLineBoxes() + val progress = WolfskinTokens.Title.dLine.withLineBoxes() + val castName = WolfskinTokens.Title.castName.withLineBoxes() + val body = WolfskinTokens.Type.body.withLineBoxes() + val caption = WolfskinTokens.Type.caption.withLineBoxes() + val label = WolfskinTokens.Type.label.withLineBoxes() + val sheetTitle = WolfskinTokens.Type.sheetTitle.withLineBoxes() + val listTitle = WolfskinTokens.Type.listTitle.withLineBoxes() + val screenTitle = WolfskinTokens.Type.screenTitle.withLineBoxes() + val rowHeading = WolfskinTokens.Type.rowHeading.withLineBoxes() + val errorTitle = WolfskinTokens.Title.errorTitle.withLineBoxes() + val receiptTitle = WolfskinTokens.Title.receiptTitle.withLineBoxes() + val infoKey = WolfskinTokens.Title.infoKey.withLineBoxes() +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/WhosWatching.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/WhosWatching.kt new file mode 100644 index 00000000..1911e346 --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/WhosWatching.kt @@ -0,0 +1,118 @@ +package org.justinvisser.wolfskin.design + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.requiredWidth +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.tv.material3.Text +import org.justinvisser.wolfskin.design.WolfskinTokens.Color as C +import org.justinvisser.wolfskin.design.WolfskinTokens.Layout as L +import org.justinvisser.wolfskin.design.WolfskinTokens.Shell as S + +/** The picker covers the nav and exposes Settings only below the final person. */ +@Composable +fun WhosWatching(state: ShellState, modifier: Modifier = Modifier) { + Box(modifier.fillMaxSize().background(C.bg)) { + Wordmark(Modifier.offset(L.safeSide, L.safeTopPicker)) + if (state.peopleStatus == PeopleStatus.Ready) PeoplePicker(state) else RecoveryPicker(state) + } +} + +@Composable +private fun PeoplePicker(state: ShellState) { + Box(Modifier.fillMaxWidth().offset(y = S.pickerTitleTop), contentAlignment = Alignment.TopCenter) { + Text("Whoโ€™s watching?", color = C.fg, style = WolfskinTokens.Type.screenTitle) + } + Row(Modifier.fillMaxWidth().offset(y = S.pickerPeopleTop), horizontalArrangement = Arrangement.spacedBy(L.pickerGap, Alignment.CenterHorizontally)) { + state.people.forEachIndexed { index, person -> + val focused = !state.gearFocused && state.pickerIndex == index + Column(Modifier.width(L.pickerAvatar).focusScale(focused, WolfskinTokens.Focus.scaleCard).clickable { + state.focusPerson(index); state.key(ShellKey.Ok) + }, horizontalAlignment = Alignment.CenterHorizontally) { + Avatar(person, L.pickerAvatar, WolfskinTokens.Type.avatarLetterPicker, + Modifier.focusRing(focused, L.pickerAvatar / 2, WolfskinTokens.Focus.ringPickerGap, WolfskinTokens.Focus.ringPickerRing, C.fg)) + Spacer(Modifier.height(S.pickerNameGap)) + Text(person.name, color = if (focused) C.fg else C.muted, style = WolfskinTokens.Type.pickerName) + } + } + } + val total = L.pickerAvatar * state.people.size + L.pickerGap * (state.people.size - 1) + val left = (S.stageWidth - total) / 2 + (L.pickerAvatar + L.pickerGap) * state.people.lastIndex + (L.pickerAvatar - L.gear) / 2 + Box(Modifier.offset(left, S.pickerGearTop).size(L.gear).focusScale(state.gearFocused, WolfskinTokens.Focus.scaleCard) + .focusRing(state.gearFocused, L.gear / 2, WolfskinTokens.Focus.ringAvatarGap, WolfskinTokens.Focus.ringAvatarRing, C.fg) + .clickable { state.gearFocused = true; state.key(ShellKey.Ok) }, contentAlignment = Alignment.Center) { + Glyph("gear", if (state.gearFocused) C.fg else C.dim.copy(alpha = C.dim.alpha * S.gearOpacity), Modifier.size(L.buttonIcon)) + if (state.gearFocused) { + Box(Modifier.align(Alignment.TopCenter).offset(y = S.pickerGearCaptionTop).requiredWidth(L.pickerAvatar), contentAlignment = Alignment.TopCenter) { + Text("Settings", color = C.muted, style = WolfskinTokens.Type.caption, maxLines = 1, softWrap = false) + } + } + } +} + +@Composable +private fun RecoveryPicker(state: ShellState) { + val loading = state.peopleStatus == PeopleStatus.Loading + val titleTop = if (loading) S.pickerLoadingTitleTop else S.pickerErrorTitleTop + Box(Modifier.fillMaxWidth().offset(y = titleTop), contentAlignment = Alignment.TopCenter) { + Text("Whoโ€™s watching?", color = C.fg, style = WolfskinTokens.Type.screenTitle) + } + if (loading) { + Row(Modifier.fillMaxWidth().offset(y = S.pickerLoadingPeopleTop), horizontalArrangement = Arrangement.spacedBy(L.pickerGap, Alignment.CenterHorizontally)) { + repeat(state.people.size) { + Column(horizontalAlignment = Alignment.CenterHorizontally) { + Box(Modifier.size(L.pickerAvatar).background(C.surface2, CircleShape)) + Spacer(Modifier.height(S.pickerNameGap)) + Box(Modifier.size(S.pickerSkeletonNameWidth, S.pickerSkeletonNameHeight).background(C.surface, RoundedCornerShape(S.skeletonRadius))) + } + } + } + } else { + Column(Modifier.offset((S.stageWidth - S.pickerErrorPanelWidth) / 2, S.pickerErrorPanelTop) + .size(S.pickerErrorPanelWidth, S.pickerErrorPanelHeight).background(C.listRowRest, RoundedCornerShape(WolfskinTokens.Radius.panel)) + .padding(horizontal = S.panelPaddingX, vertical = S.panelPaddingY), verticalArrangement = Arrangement.spacedBy(S.panelGap)) { + Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(S.panelHeadingGap)) { + Glyph("alert", C.warn, Modifier.size(S.panelIcon)) + Text("Canโ€™t read whoโ€™s here", color = C.warn, style = WolfskinTokens.Type.stateTitle.copy(fontWeight = androidx.compose.ui.text.font.FontWeight.Bold)) + } + Text("Conductarr didnโ€™t answer. You can continue as the last person on\nthis TV.", color = C.muted, style = WolfskinTokens.Type.body) + } + } + Row(Modifier.fillMaxWidth().offset(y = if (loading) S.pickerLoadingButtonTop else S.pickerErrorButtonTop), horizontalArrangement = Arrangement.spacedBy(L.buttonGap, Alignment.CenterHorizontally)) { + if (!loading) PickerButton("Try again", state.recoveryIndex == 0, true) { state.recoveryIndex = 0; state.key(ShellKey.Ok) } + PickerButton("Continue as ${state.person.name}", loading || state.recoveryIndex == 1, false) { state.recoveryIndex = 1; state.key(ShellKey.Ok) } + } +} + +/** Recovery actions remain focusable while profiles cannot be read. */ +@Composable +fun PickerButton(label: String, focused: Boolean, primary: Boolean, icon: String? = null, onFocus: (() -> Unit)? = null, + textStyle: androidx.compose.ui.text.TextStyle = WolfskinTokens.Type.button, onClick: () -> Unit) { + val background = if (primary) C.fg else if (focused) C.buttonSecondaryFocused else C.buttonSecondary + Box(Modifier.height(L.buttonHeight).focusScale(focused, WolfskinTokens.Focus.scaleControl) + .focusRing(focused, WolfskinTokens.Radius.button, WolfskinTokens.Focus.ringButtonGap, WolfskinTokens.Focus.ringButtonRing, C.accent, FocusLift.Button) + .then(if (onFocus != null) Modifier.focusOnPointerEnter(onFocus) else Modifier) + .background(background, RoundedCornerShape(WolfskinTokens.Radius.button)).clickable(onClick = onClick) + .padding(horizontal = L.buttonPaddingX), contentAlignment = Alignment.Center) { + Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(WolfskinTokens.Home.plateTop)) { + if (icon != null) Glyph(icon, if (primary) C.onFocus else C.fg, Modifier.size(L.buttonIcon)) + Text(label, modifier = Modifier.exactLineBox(textStyle), color = if (primary) C.onFocus else C.fg, style = textStyle) + } + } +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/WolfskinImages.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/WolfskinImages.kt new file mode 100644 index 00000000..d89254f9 --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/WolfskinImages.kt @@ -0,0 +1,54 @@ +package org.justinvisser.wolfskin.design + +import android.content.Context +import coil3.ImageLoader +import coil3.disk.DiskCache +import coil3.intercept.Interceptor +import coil3.disk.directory +import coil3.imageLoader +import coil3.request.crossfade +import coil3.memory.MemoryCache +import coil3.request.ImageRequest +import coil3.request.allowRgb565 +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.sync.Semaphore +import kotlinx.coroutines.sync.withPermit + +/** Wolfskin screens share one bounded loader; hidden-switch screens retain the upstream loader. */ +object WolfskinImages { + private var application: Context? = null + private var loader: ImageLoader? = null + private const val MEBIBYTE = 1024L * 1024L + private const val IMAGE_READS = 4 + private val readPermits = Semaphore(IMAGE_READS) + + @Synchronized + fun loader(context: Context): ImageLoader { + val owner = context.applicationContext + if (application !== owner) { + loader?.shutdown() + application = owner + val reads = Dispatchers.IO.limitedParallelism(IMAGE_READS) + loader = owner.imageLoader.newBuilder() + .memoryCache { MemoryCache.Builder().maxSizeBytes((WolfskinTokens.Image.memoryCacheMB * MEBIBYTE).toLong()).build() } + .diskCache { DiskCache.Builder().directory(owner.cacheDir.resolve("wolfskin-images")).maxSizeBytes((WolfskinTokens.Image.diskCacheMB * MEBIBYTE).toLong()).build() } + .components { add(Interceptor { chain -> readPermits.withPermit { chain.proceed() } }) } + .fetcherCoroutineContext(reads).decoderCoroutineContext(reads).crossfade(false).build() + } + return loader!! + } + + fun request(context: Context, source: Any, width: Int, height: Int, poster: Boolean): ImageRequest = + ImageRequest.Builder(context).data(source).size(width, height).allowRgb565(poster).build() + + fun prefetch(context: Context, row: HomeRow) { + val count = when (row.cardKind) { HomeCardKind.Poster -> 7; HomeCardKind.Tile -> 5; HomeCardKind.Wide -> 4 } + val width = (row.cardWidth.value * 2).toInt() + val height = (row.cardHeight.value * 2).toInt() + row.cards.take(count).forEach { title -> + val poster = row.cardKind == HomeCardKind.Poster + val source = if (poster) title.poster else title.backdrop ?: title.poster + if (source != null) loader(context).enqueue(request(context, source, width, height, poster)) + } + } +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/WolfskinTheme.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/WolfskinTheme.kt new file mode 100644 index 00000000..d3e155a8 --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/WolfskinTheme.kt @@ -0,0 +1,41 @@ +package org.justinvisser.wolfskin.design + +import androidx.compose.runtime.Composable +import androidx.tv.material3.MaterialTheme +import androidx.tv.material3.darkColorScheme + +/** Both Compose Material families use the same opaque TV palette for hand-offs. */ +object WolfskinColors { + private val c = WolfskinTokens.Color + val darkScheme = darkColorScheme( + primary = c.accent, onPrimary = c.onFocus, + primaryContainer = c.accentSoft, onPrimaryContainer = c.accentText, + secondary = c.accent, onSecondary = c.onFocus, + secondaryContainer = c.accentSoft, onSecondaryContainer = c.accentText, + tertiary = c.accent, onTertiary = c.onFocus, + tertiaryContainer = c.accentSoft, onTertiaryContainer = c.accentText, + background = c.bg, onBackground = c.fg, + surface = c.bg, onSurface = c.fg, + surfaceVariant = c.surface2, onSurfaceVariant = c.fg, + border = c.accent, + ) + val darkSchemeMaterial = androidx.compose.material3.darkColorScheme( + primary = c.accent, onPrimary = c.onFocus, + primaryContainer = c.accentSoft, onPrimaryContainer = c.accentText, + secondary = c.accent, onSecondary = c.onFocus, + secondaryContainer = c.accentSoft, onSecondaryContainer = c.accentText, + tertiary = c.accent, onTertiary = c.onFocus, + tertiaryContainer = c.accentSoft, onTertiaryContainer = c.accentText, + background = c.bg, onBackground = c.fg, + surface = c.bg, onSurface = c.fg, + surfaceVariant = c.surface2, onSurfaceVariant = c.fg, + ) +} + +/** Upstream content inherits tokens without a fork-specific theme enum. */ +@Composable +fun WolfskinTheme(content: @Composable () -> Unit) { + androidx.compose.material3.MaterialTheme(colorScheme = WolfskinColors.darkSchemeMaterial) { + MaterialTheme(colorScheme = WolfskinColors.darkScheme, content = content) + } +} diff --git a/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/WolfskinTokens.kt b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/WolfskinTokens.kt new file mode 100644 index 00000000..9cf06f03 --- /dev/null +++ b/wolfskin-design/src/main/java/org/justinvisser/wolfskin/design/WolfskinTokens.kt @@ -0,0 +1,671 @@ +// Generated by generate_tokens.py; edit the JSON sources instead. +package org.justinvisser.wolfskin.design + +import androidx.compose.ui.graphics.Color as ComposeColor +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.em +import androidx.compose.ui.unit.sp + +/** The locked TV design, converted at the source density. */ +object WolfskinTokens { + object Color { + val bg = ComposeColor(0xFF07070A) + val surface = ComposeColor(0xFF13131A) + val surface2 = ComposeColor(0xFF1B1B25) + val surface3 = ComposeColor(0xFF252532) + val fg = ComposeColor(0xFFF4F4F6) + val muted = ComposeColor(0xBDF4F4F6) + val dim = ComposeColor(0x8FF4F4F6) + val border = ComposeColor(0x1AFFFFFF) + val accent = ComposeColor(0xFFCC9FFF) + val accentSoft = ComposeColor(0xFF2C1A3F) + val accentText = ComposeColor(0xFFE4CBFF) + val ok = ComposeColor(0xFF89DA9B) + val warn = ComposeColor(0xFFF4C26A) + val fail = ComposeColor(0xFFF97770) + val onFocus = ComposeColor(0xFF0B0B10) + val buttonSecondary = ComposeColor(0x24FFFFFF) + val buttonSecondaryFocused = ComposeColor(0x42FFFFFF) + val titleButtonSecondary = ComposeColor(0xC72C2C38) + val titleButtonSecondaryFocused = ComposeColor(0xE6464654) + val chipRest = ComposeColor(0x1AFFFFFF) + val navBlobRest = ComposeColor(0x1AFFFFFF) + val listRowRest = ComposeColor(0x0DFFFFFF) + val sheetScrim = ComposeColor(0x9E000000) + val badgeRest = ComposeColor(0xBF07070A) + val badgeWatched = ComposeColor(0xD9F4F4F6) + val progressTrack = ComposeColor(0x38FFFFFF) + val railEmpty = ComposeColor(0x38F4F4F6) + } + object PersonColor { + val justin = ComposeColor(0xFF62C4FF) + val mindel = ComposeColor(0xFFFF9D72) + val shared = ComposeColor(0xFF9BE38F) + } + object Gradient { + const val heroScrim = "linear-gradient(90deg,rgb(7 7 10 / .92) 0%,rgb(7 7 10 / .55) 42%,rgb(7 7 10 / 0) 70%),linear-gradient(0deg,var(--bg) 0%,rgb(7 7 10 / .6) 26%,rgb(7 7 10 / 0) 48%)" + const val detailScrim = "linear-gradient(90deg,rgb(7 7 10 / .94) 0%,rgb(7 7 10 / .6) 46%,rgb(7 7 10 / .05) 75%),linear-gradient(0deg,var(--bg) 0%,rgb(7 7 10 / .35) 34%,rgb(7 7 10 / 0) 55%)" + const val navBand = "linear-gradient(180deg,rgb(7 7 10 / .72),rgb(7 7 10 / 0))" + const val navBandSolid = "linear-gradient(180deg,var(--bg) 0%,var(--bg) 84%,rgb(7 7 10 / 0) 100%)" + const val ratingPlate = "linear-gradient(180deg,rgb(7 7 10 / .9) 0%,rgb(7 7 10 / .72) 52%,rgb(7 7 10 / 0) 100%)" + const val tileOverlay = "linear-gradient(0deg,rgb(7 7 10 / .92),rgb(7 7 10 / 0))" + const val fallbackArt = "linear-gradient(160deg,hsl(var(--h,260) 22% 22%),hsl(var(--h,260) 26% 10%))" + const val entryTile = "linear-gradient(150deg,hsl(var(--h) 30% 26%),hsl(var(--h) 30% 12%))" + const val initialsCircle = "linear-gradient(160deg,hsl(var(--h) 24% 30%),hsl(var(--h) 26% 14%))" + const val heroAmbientFilter = "blur(60px) saturate(1.2) brightness(.55)" + const val cardAmbientFilter = "blur(26px) brightness(.5)" + } + object Type { + val displayDetail = TextStyle(fontSize = 44.0.sp, fontWeight = FontWeight(800), lineHeight = 44.88.sp, letterSpacing = -0.02.em) + val displayHero = TextStyle(fontSize = 42.0.sp, fontWeight = FontWeight(800), lineHeight = 42.84.sp, letterSpacing = -0.02.em) + val screenTitle = TextStyle(fontSize = 32.0.sp, fontWeight = FontWeight(800), lineHeight = 41.6.sp, letterSpacing = -0.02.em) + val sectionTitle = TextStyle(fontSize = 28.0.sp, fontWeight = FontWeight(800), lineHeight = 36.4.sp, letterSpacing = -0.02.em) + val sheetTitle = TextStyle(fontSize = 22.0.sp, fontWeight = FontWeight(800), lineHeight = 28.6.sp, letterSpacing = -0.01.em) + val wordmark = TextStyle(fontSize = 18.0.sp, fontWeight = FontWeight(800), lineHeight = 23.400000000000002.sp, letterSpacing = -0.02.em) + val stateTitle = TextStyle(fontSize = 18.0.sp, fontWeight = FontWeight(400), lineHeight = 23.400000000000002.sp, letterSpacing = 0.0.em) + val rowHeading = TextStyle(fontSize = 17.0.sp, fontWeight = FontWeight.Bold, lineHeight = 22.1.sp, letterSpacing = -0.01.em) + val pickerName = TextStyle(fontSize = 17.0.sp, fontWeight = FontWeight.Bold, lineHeight = 22.1.sp, letterSpacing = 0.0.em) + val nav = TextStyle(fontSize = 15.0.sp, fontWeight = FontWeight.Bold, lineHeight = 19.5.sp, letterSpacing = 0.0.em) + val listTitle = TextStyle(fontSize = 15.0.sp, fontWeight = FontWeight.Bold, lineHeight = 19.5.sp, letterSpacing = 0.0.em) + val body = TextStyle(fontSize = 14.0.sp, fontWeight = FontWeight(400), lineHeight = 18.2.sp, letterSpacing = 0.0.em) + val button = TextStyle(fontSize = 14.0.sp, fontWeight = FontWeight.Bold, lineHeight = 18.2.sp, letterSpacing = 0.0.em) + val label = TextStyle(fontSize = 13.0.sp, fontWeight = FontWeight.Bold, lineHeight = 16.900000000000002.sp, letterSpacing = 0.0.em) + val caption = TextStyle(fontSize = 12.0.sp, fontWeight = FontWeight(400), lineHeight = 15.600000000000001.sp, letterSpacing = 0.0.em) + val ratingPlate = TextStyle(fontSize = 14.0.sp, fontWeight = FontWeight.Bold, lineHeight = 16.8.sp, letterSpacing = 0.0.em) + val avatarLetterPicker = TextStyle(fontSize = 50.0.sp, fontWeight = FontWeight(800)) + val avatarLetterNav = TextStyle(fontSize = 15.0.sp, fontWeight = FontWeight(800)) + val avatarLetterSheetRow = TextStyle(fontSize = 14.0.sp, fontWeight = FontWeight(800)) + val avatarLetterShelfHead = TextStyle(fontSize = 12.0.sp, fontWeight = FontWeight(800)) + val avatarLetterChip = TextStyle(fontSize = 12.0.sp, fontWeight = FontWeight(800)) + val avatarLetterLibHeader = TextStyle(fontSize = 13.0.sp, fontWeight = FontWeight(800)) + val avatarLetterSectionHeader = TextStyle(fontSize = 14.0.sp, fontWeight = FontWeight(800)) + const val stageLineHeight = 1.3f + } + object Radius { + val card = 8.0.dp + val button = 19.0.dp + val chip = 17.0.dp + val navItem = 16.0.dp + val listRow = 12.0.dp + val panel = 11.0.dp + val menu = 13.0.dp + val heroSheet = 9.0.dp + val cardSheet = 5.0.dp + val thumb = 6.0.dp + val pill = 11.0.dp + val progress = 2.0.dp + } + object Layout { + val safeSide = 48.0.dp + val contentWidth = 864.0.dp + val safeTopPicker = 27.0.dp + val navBand = 75.0.dp + val navPaddingTop = 22.0.dp + val navItemHeight = 32.0.dp + val navItemPaddingX = 13.0.dp + val navItemGap = 6.0.dp + val wordmarkGap = 20.0.dp + val navUnderline = 2.0.dp + val navBlobAvatarPad = 4.0.dp + val navSolidAfter = 20.0.dp + val pinnedLine = 84.0.dp + val windowAhead = 350.0.dp + val rowHeadingBand = 30.0.dp + val rowGapAfter = 22.0.dp + val gridRowGap = 14.0.dp + val row_hero = 410.0.dp + val row_phero = 370.0.dp + val row_section = 75.0.dp + val row_chips = 52.0.dp + val row_note = 42.0.dp + val row_state = 150.0.dp + val row_lhead = 118.0.dp + val row_dhead = 450.0.dp + val row_phead = 235.0.dp + val row_gh = 42.0.dp + val row_endcta = 100.0.dp + val row_srow = 62.0.dp + val heroCopyLeft = 48.0.dp + val heroCopyBottom = 55.0.dp + val heroCopyWidth = 500.0.dp + val heroOverviewMax = 480.0.dp + val detailCopyTop = 100.0.dp + val detailCopyWidth = 530.0.dp + val heroSheetWidth = 210.0.dp + val heroSheetHeight = 315.0.dp + val buttonHeight = 38.0.dp + val buttonPaddingX = 19.0.dp + val buttonGap = 10.0.dp + val buttonIcon = 15.0.dp + val iconButton = 38.0.dp + val iconCaptionLine = 19.0.dp + val sheetWidth = 400.0.dp + val sheetRow = 50.0.dp + val settingsRowWidth = 650.0.dp + val settingsRowHeight = 52.0.dp + val stateWidth = 550.0.dp + val captionOffset = 9.0.dp + val badge = 24.0.dp + val badgeInset = 7.0.dp + val progressBar = 4.0.dp + val pickerAvatar = 110.0.dp + val pickerGap = 45.0.dp + val pickerStackGap = 35.0.dp + val gear = 28.0.dp + val navAvatar = 32.0.dp + val castCircle = 100.0.dp + val personPortrait = 120.0.dp + val thumbWidth = 48.0.dp + val thumbHeight = 72.0.dp + } + object Card { + val posterW = 128.0.dp + val posterH = 192.0.dp + val posterGap = 12.0.dp + val posterPitch = 140.0.dp + val posterCaptionBand = 38.0.dp + const val posterSlots = 6 + val tileW = 208.0.dp + val tileH = 117.0.dp + val tileGap = 12.0.dp + val tilePitch = 220.0.dp + val tileCaptionBand = 0.0.dp + const val tileSlots = 4 + val wideW = 280.0.dp + val wideH = 157.5.dp + val wideGap = 12.0.dp + val widePitch = 292.0.dp + val wideCaptionBand = 0.0.dp + const val wideSlots = 3 + val entryW = 128.0.dp + val entryH = 72.0.dp + val entryGap = 12.0.dp + val entryPitch = 140.0.dp + val entryCaptionBand = 0.0.dp + const val entrySlots = 6 + val personW = 100.0.dp + val personH = 145.0.dp + val personGap = 14.0.dp + val personPitch = 114.0.dp + val personCaptionBand = 0.0.dp + const val personSlots = 7 + } + object Focus { + const val scaleCard = 1.08f + const val scaleControl = 1.05f + const val scaleRow = 1.02f + val ringCardGap = 2.0.dp + val ringCardRing = 2.0.dp + val ringButtonGap = 2.0.dp + val ringButtonRing = 2.0.dp + val ringAvatarGap = 2.0.dp + val ringAvatarRing = 2.0.dp + val ringPickerGap = 3.0.dp + val ringPickerRing = 3.0.dp + const val fillInverse = "background color.fg, text color.onFocus" + } + object Motion { + const val fast = 140 + const val base = 160 + const val scroll = 180 + const val navBlobDampingRatio = 1.0f + const val navBlobStiffness = 650.0f + const val ratingDwell = 350 + const val toast = 3200 + const val reducedMotion = "all transitions instant" + } + object Image { + const val posterRequestWidth = 256 + const val posterRequestHeight = 384 + const val tileRequestWidth = 416 + const val tileRequestHeight = 234 + const val wideRequestWidth = 560 + const val wideRequestHeight = 315 + const val heroRequestWidth = 1280 + const val heroRequestHeight = 720 + const val castRequestWidth = 200 + const val castRequestHeight = 200 + const val memoryCacheMB = 64.0f + const val diskCacheMB = 128.0f + const val concurrentReadsCatalogue = 2 + const val concurrentReadsImage = 4 + } + object Behaviour { + const val rowLimit = 20.0f + const val letterRailMin = 200.0f + const val gridColumns = 6.0f + const val libraryChunk = 200.0f + const val laneLoadRows = 2.0f + const val nextPageCards = 10.0f + const val heroSlides = 5.0f + const val cacheRatingsHours = 6.0f + const val laneCacheMinutes = 30.0f + const val libraryRefreshMinutes = 10.0f + const val requestsPollSeconds = 30.0f + const val comingInVisibleRows = 5.0f + } + object Requests { + val sheetPaddingY = 40.0.dp + val sheetPaddingX = 32.0.dp + val sheetGap = 9.0.dp + val sheetTitleLineHeight = 28.0.dp + val sheetTitleBaseline = 22.0.dp + val titleLineHeight = 19.5.dp + val titleBaseline = 15.5.dp + val factsLineHeight = 15.6.dp + val factsBaseline = 12.0.dp + val stageLineHeight = 19.8.dp + val stageLabelLineHeight = 16.9.dp + val stageBaseline = 12.0.dp + val emptyMargin = 10.0.dp + val rowPaddingY = 7.0.dp + val rowPaddingX = 9.0.dp + val rowGap = 12.0.dp + val listGap = 3.0.dp + val stageMargin = 2.0.dp + val stageGlyph = 14.0.dp + val stageGap = 5.0.dp + val readinessGapX = 11.0.dp + val readinessGapY = 5.0.dp + val readinessMargin = 4.0.dp + val readinessGlyph = 13.0.dp + val chevron = 15.0.dp + const val chevronAlpha = 0.6f + val receiptPaddingY = 14.0.dp + val receiptPaddingX = 15.0.dp + val receiptGap = 5.0.dp + val receiptGlyph = 18.0.dp + val buttonMargin = 6.0.dp + val skeletonTitleWidth = 180.0.dp + val skeletonTitleHeight = 17.0.dp + val skeletonSubtitleWidth = 120.0.dp + val skeletonSubtitleHeight = 13.0.dp + val skeletonGap = 6.0.dp + val ratingsGap = 10.0.dp + val ratingsEntryGap = 4.0.dp + val shadowBlur = 40.0.dp + val shadowOffset = -15.0.dp + val shadowColor = ComposeColor(0x80000000) + const val ratingsWordmarkRatio = 1.8f + } + object Shell { + const val navLabelFade = 200 + val zero = 0.0.dp + val stageWidth = 960.0.dp + val stageHeight = 540.0.dp + val wordmarkWidth = 84.5.dp + val wordmarkTop = 36.8.dp + val navHomeWidth = 74.5.dp + val navDiscoverWidth = 99.0.dp + val navMoviesWidth = 85.5.dp + val navShowsWidth = 80.5.dp + val navAnimeWidth = 79.0.dp + val navItemTop = 32.5.dp + val pickerTitleTop = 136.15.dp + val pickerPeopleTop = 212.75.dp + val pickerNameGap = 13.0.dp + val pickerGearTop = 375.85.dp + val pickerGearCaptionTop = 36.0.dp + val pickerLetter = 50.0.dp + val pickerSkeletonNameWidth = 70.0.dp + val pickerSkeletonNameHeight = 20.0.dp + val pickerLoadingTitleTop = 123.7.dp + val pickerLoadingPeopleTop = 200.3.dp + val pickerLoadingButtonTop = 378.3.dp + val pickerErrorTitleTop = 148.8.dp + val pickerErrorPanelTop = 225.4.dp + val pickerErrorPanelWidth = 490.0.dp + val pickerErrorPanelHeight = 92.8.dp + val pickerErrorButtonTop = 353.2.dp + val settingsHeaderTop = 75.0.dp + val settingsHeaderAvatar = 26.0.dp + val settingsHeaderGap = 12.0.dp + val settingsRowTop = 5.0.dp + val settingsRowPadding = 15.0.dp + val settingsRowGap = 12.0.dp + val settingsIcon = 18.0.dp + val settingsPillHeight = 20.0.dp + val settingsPillStroke = 1.0.dp + const val settingsPillDashRatio = 3.0f + const val settingsPillDashGapRatio = 2.0f + val settingsPillBorder = ComposeColor(0x38FFFFFF) + val settingsPillFocusedBorder = ComposeColor(0x660B0B10) + val settingsPillPadding = 8.0.dp + val settingsPillGap = 6.0.dp + val settingsChevron = 15.0.dp + val settingsEndPadding = 310.0.dp + val panelPaddingX = 15.0.dp + val panelPaddingY = 14.0.dp + val panelGap = 5.0.dp + val panelHeadingGap = 7.0.dp + val panelIcon = 18.0.dp + val skeletonRadius = 5.0.dp + const val gearOpacity = 0.7f + const val navBandOpacity = 0.72f + const val navSolidStop = 0.84f + } + object Library { + val chipHeight = 34.0.dp + val chipPadding = 14.0.dp + val chipGap = 8.0.dp + val chipTop = 8.0.dp + val chipIcon = 13.0.dp + val captionWidth = 320.0.dp + const val captionSeparatorOpacity = 0.4f + val captionFactsGap = 9.0.dp + val badgeIcon = 14.0.dp + val plateTop = 7.0.dp + val plateSide = 8.0.dp + val plateBottom = 23.0.dp + val plateInlineDescent = 3.3.dp + val plateFloor = TextStyle(fontSize = 12.0.sp, fontWeight = FontWeight.Bold, lineHeight = 15.600000000000001.sp, letterSpacing = 0.0.em) + const val plateStep = 0.25f + const val plateGapEm = 0.64f + const val markGapEm = 0.29f + const val wordmarkRatio = 1.8f + const val plateOpacity = 0.9f + const val plateMidOpacity = 0.72f + const val plateMidStop = 0.52f + val railWidth = 26.0.dp + val railLetterHeight = 15.0.dp + val railFocusHeight = 22.0.dp + val railLetter = TextStyle(fontSize = 12.0.sp, fontWeight = FontWeight.Bold, lineHeight = 15.600000000000001.sp, letterSpacing = 0.0.em) + val railFocusedLetter = TextStyle(fontSize = 14.0.sp, fontWeight = FontWeight.Bold, lineHeight = 18.2.sp, letterSpacing = 0.0.em) + val panelPaddingX = 20.0.dp + val panelPaddingY = 17.0.dp + val panelTextGap = 12.0.dp + val panelTitleGap = 4.0.dp + val panelIconGap = 7.0.dp + val panelTop = 10.0.dp + val borderWidth = 1.0.dp + val chipContentGap = 6.0.dp + const val chipLabelOpacity = 0.7f + val tailIcon = 22.0.dp + val tailPadding = 10.0.dp + val tailGap = 5.0.dp + val badgeRing = 1.5.dp + val seeAllGap = 4.0.dp + val tailDescription = TextStyle(fontSize = 12.0.sp, fontWeight = FontWeight(500), lineHeight = 15.600000000000001.sp, letterSpacing = 0.0.em) + val headerSubtitle = TextStyle(fontSize = 15.0.sp, fontWeight = FontWeight(400), lineHeight = 19.5.sp, letterSpacing = 0.0.em) + const val imageReads = 4.0f + const val unknownCriticOpacity = 0.55f + val fallbackPadding = 11.0.dp + val fallbackIcon = 22.0.dp + const val fallbackHueMultiplier = 31.0f + const val fallbackSaturationTop = 0.22f + const val fallbackLightnessTop = 0.22f + const val fallbackSaturationBottom = 0.26f + const val fallbackLightnessBottom = 0.1f + const val fallbackIconOpacity = 0.45f + } + object Lift { + val cardBlur = 25.0.dp + val cardY = 9.0.dp + const val cardOpacity = 0.65f + val buttonBlur = 20.0.dp + val buttonY = 6.0.dp + const val buttonOpacity = 0.5f + val heroBlur = 40.0.dp + val heroY = 15.0.dp + const val heroOpacity = 0.6f + val sheetBlur = 40.0.dp + val sheetX = -15.0.dp + const val sheetOpacity = 0.5f + } + object Title { + val lineGap = 11.0.dp + val lineLift = -2.0.dp + val overviewGap = 17.0.dp + val factsGap = 11.0.dp + val factsBottom = 7.0.dp + val factsHeight = 19.0.dp + val titleBottom = 8.0.dp + val iconGap = 7.0.dp + val iconSize = 16.0.dp + val captionTop = 8.0.dp + val progressWidth = 160.0.dp + val progressBottom = 15.0.dp + val progressGap = 9.0.dp + val progressLift = -7.0.dp + val castHeight = 197.0.dp + val castNameTop = 108.0.dp + val castNameSide = 6.0.dp + val personTop = 85.0.dp + val personGap = 24.0.dp + val personNameBottom = 5.0.dp + val personNoteBottom = 3.0.dp + val captionWidth = 320.0.dp + val sheetPaddingTop = 40.0.dp + val sheetPaddingSide = 32.0.dp + val sheetGap = 9.0.dp + val sheetSubLift = -4.0.dp + val sheetSubBottom = 7.0.dp + val sheetLabelTop = 4.0.dp + val sheetButtonTop = 6.0.dp + val sheetRowSide = 13.0.dp + val versionRowVertical = 10.0.dp + val trackHeight = 42.0.dp + val trackGap = 6.0.dp + val radioSize = 20.0.dp + val radioDot = 8.0.dp + val radioBorder = 1.5.dp + val infoGap = 7.0.dp + val infoLabelWidth = 100.0.dp + val infoRowGap = 3.0.dp + val infoColumnGap = 10.0.dp + val infoKey = TextStyle(fontSize = 12.0.sp, fontWeight = FontWeight.Bold, lineHeight = 15.600000000000001.sp, letterSpacing = 0.0.em) + val gridHeight = 244.0.dp + val minimumEndPadding = 40.0.dp + val ratingGap = 10.0.dp + val ratingMarkGap = 4.0.dp + val initialSize = TextStyle(fontSize = 32.0.sp, fontWeight = FontWeight(800), lineHeight = 41.6.sp, letterSpacing = 0.0.em) + val personInitialSize = TextStyle(fontSize = 48.0.sp, fontWeight = FontWeight(800), lineHeight = 62.400000000000006.sp, letterSpacing = 0.0.em) + const val fallbackHue = 260.0f + val skeletonKickerWidth = 210.0.dp + val skeletonKickerHeight = 17.0.dp + val skeletonTitleGap = 13.0.dp + val skeletonFactsGap = 12.0.dp + val skeletonOverviewGap = 15.0.dp + val skeletonTitleWidth = 380.0.dp + val skeletonTitleHeight = 46.0.dp + val skeletonFactsWidth = 280.0.dp + val skeletonOverviewWidth = 490.0.dp + val skeletonOverviewHeight = 55.0.dp + val skeletonPlayWidth = 110.0.dp + val dLine = TextStyle(fontSize = 13.0.sp, fontWeight = FontWeight(400), lineHeight = 16.900000000000002.sp, letterSpacing = 0.0.em) + val iconCaption = TextStyle(fontSize = 13.0.sp, fontWeight = FontWeight(400), lineHeight = 16.900000000000002.sp, letterSpacing = 0.0.em) + val lineIcon = 14.0.dp + val chipHeight = 34.0.dp + val chipPadding = 14.0.dp + val chipGap = 8.0.dp + val chipTop = 8.0.dp + val chipBorder = 1.0.dp + val heroSheetRight = 90.0.dp + val heroSheetTop = 75.0.dp + val gridHeadingTop = 12.0.dp + val castName = TextStyle(fontSize = 13.0.sp, fontWeight = FontWeight.Bold, lineHeight = 16.900000000000002.sp, letterSpacing = 0.0.em) + val receiptSide = 15.0.dp + val receiptTop = 14.0.dp + val receiptGap = 5.0.dp + val receiptIcon = 18.0.dp + val receiptTitle = TextStyle(fontSize = 18.0.sp, fontWeight = FontWeight.Bold, lineHeight = 23.400000000000002.sp, letterSpacing = 0.0.em) + val toastMaxWidth = 380.0.dp + val toastSide = 14.0.dp + val toastTop = 11.0.dp + const val heroAmbientBackground = "radial-gradient(120% 90% at 70% 20%,var(--surface3),var(--bg))" + const val dimScrollPx = 1400.0f + const val dimMaximum = 0.7f + val errorTop = 85.0.dp + val errorSide = 20.0.dp + val errorVertical = 17.0.dp + val errorHeadingBottom = 4.0.dp + val errorBodyBottom = 12.0.dp + val errorTitle = TextStyle(fontSize = 18.0.sp, fontWeight = FontWeight.Bold, lineHeight = 23.400000000000002.sp, letterSpacing = 0.0.em) + val fallbackGlyph = 22.0.dp + val fallbackInset = 11.0.dp + val tileSheetInset = 9.0.dp + val tileSheetLeft = 11.0.dp + val tileSheetRadius = 5.0.dp + val tileAmbientBlur = 13.0.dp + val tileAmbientInset = 15.0.dp + val tileShadowRadius = 15.0.dp + val tileShadowY = 5.0.dp + const val tileShadowOpacity = 0.5f + const val tileAmbientBrightness = 0.5f + const val cardFallbackGradient = "linear-gradient(160deg,hsl(var(--h) 22% 22%),hsl(var(--h) 26% 10%))" + const val personFallbackGradient = "linear-gradient(160deg,hsl(var(--h) 24% 30%),hsl(var(--h) 26% 14%))" + val initialsColor = ComposeColor(0xD1FFFFFF) + val fallbackGlyphColor = ComposeColor(0x73FFFFFF) + val fallbackTitle = TextStyle(fontSize = 14.0.sp, fontWeight = FontWeight.Bold, lineHeight = 16.099999999999998.sp, letterSpacing = 0.0.em) + val tileOverlayTop = 27.0.dp + val tileOverlaySide = 11.0.dp + val tileOverlayBottom = 9.0.dp + const val cardOverlayOpacity = 0.92f + val cardProgressInset = 9.0.dp + val tileProgressBottom = 5.0.dp + val ambientInset = 40.0.dp + const val ambientScale = 1.1f + val posterShadowRadius = 40.0.dp + val posterShadowY = 15.0.dp + const val posterShadowOpacity = 0.6f + val sheetShadowRadius = 40.0.dp + val sheetShadowX = -15.0.dp + const val sheetShadowOpacity = 0.5f + } + object SavedIndicator { + val height = 26.0.dp + val side = 10.0.dp + val gap = 5.0.dp + val icon = 14.0.dp + val border = 1.0.dp + const val borderOpacity = 0.5f + } + object Home { + val kickerGap = 6.0.dp + val kickerBottom = 5.0.dp + val titleBottom = 8.0.dp + val factsHeight = 19.0.dp + val factsBottom = 7.0.dp + val factsGap = 11.0.dp + val overviewBottom = 15.0.dp + val cardPadding = 11.0.dp + val cardOverlayTop = 27.0.dp + val cardOverlayBottom = 9.0.dp + val sectionTop = 20.0.dp + val sectionAvatar = 28.0.dp + val sectionGap = 11.0.dp + val stateTextBottom = 12.0.dp + val stateTop = 10.0.dp + val statePaddingX = 20.0.dp + val statePaddingY = 17.0.dp + val stateGap = 4.0.dp + val stateIcon = 18.0.dp + val captionWidth = 320.0.dp + val plateTop = 7.0.dp + val plateSide = 8.0.dp + val plateFade = 23.0.dp + val ratingGap = 10.0.dp + val ratingMarkGap = 4.0.dp + val heroSkeletonWidth = 320.0.dp + val heroSkeletonHeight = 42.0.dp + val heroSkeletonFactsWidth = 230.0.dp + val heroSkeletonFactsHeight = 17.0.dp + val heroSkeletonButtonWidth = 130.0.dp + val heroSkeletonGap = 11.0.dp + val heroSkeletonButtonGap = 20.0.dp + val artGlyph = 22.0.dp + val cardSheetLeft = 11.0.dp + val cardSheetTop = 9.0.dp + val cardSheetInset = 18.0.dp + val heroSheetRight = 90.0.dp + val heroSheetTop = 75.0.dp + val cardBlur = 13.0.dp + val heroBlur = 30.0.dp + val progressInset = 9.0.dp + val progressBottom = 5.0.dp + val endTop = 20.0.dp + val frameBottom = 40.0.dp + val toastPadding = 14.0.dp + val toastTop = 75.0.dp + val toastWidth = 380.0.dp + val toastPaddingY = 11.0.dp + val toastGap = 7.0.dp + val toastShadowBlur = 30.0.dp + val toastShadowY = 10.0.dp + const val toastShadowOpacity = 0.5f + val cardWashInset = 15.0.dp + val heroWashInset = 40.0.dp + val noteTop = 7.0.dp + val noteGap = 8.0.dp + val hairline = 1.0.dp + val savedHeight = 26.0.dp + val savedPadding = 10.0.dp + val savedGap = 5.0.dp + val savedIcon = 14.0.dp + val savedRadius = 14.0.dp + val posterProgressBottom = 6.0.dp + } + object Discover { + val sheetPaddingX = 32.0.dp + val sheetPaddingY = 40.0.dp + val sheetGap = 9.0.dp + val sheetSubGap = 7.0.dp + val sheetRowPadding = 13.0.dp + val sheetAvatar = 30.0.dp + val sheetRadio = 20.0.dp + val sheetRadioDot = 8.0.dp + val sheetPersonGap = 12.0.dp + val sheetButtonTop = 6.0.dp + val chipTop = 8.0.dp + val chipHeight = 34.0.dp + val chipPadding = 14.0.dp + val chipGap = 8.0.dp + val heroTitleGap = 8.0.dp + val heroKickerGap = 5.0.dp + val heroMetaGap = 7.0.dp + val heroOverviewGap = 15.0.dp + val heroFactsGap = 11.0.dp + val heroFactsHeight = 19.0.dp + val heroSheetRight = 90.0.dp + val heroSheetTop = 70.0.dp + val heroSheetWidth = 180.0.dp + val heroSheetHeight = 270.0.dp + val dotSize = 7.0.dp + val dotActive = 22.0.dp + val dotGap = 7.0.dp + val dotMargin = 9.0.dp + val dotChevron = 20.0.dp + val stateTop = 10.0.dp + val statePaddingX = 20.0.dp + val statePaddingY = 17.0.dp + val stateTextGap = 12.0.dp + val noteTop = 7.0.dp + val headerTop = 75.0.dp + val headerGap = 12.0.dp + val entryPaddingX = 11.0.dp + val entryPaddingY = 10.0.dp + val entryText = TextStyle(fontSize = 15.0.sp, fontWeight = FontWeight(800), lineHeight = 19.5.sp, letterSpacing = -0.01.em) + val sheetRadioRing = 1.5.dp + val skeletonNameWidth = 130.0.dp + val skeletonNameHeight = 17.0.dp + val sheetSubTop = -4.0.dp + val sheetRatingTop = -5.0.dp + val sheetRatingBottom = 3.0.dp + val sheetLabelTop = 4.0.dp + val noteIcon = 15.0.dp + val noteGap = 8.0.dp + val frameBottomMin = 40.0.dp + val anchorFitTop = 350.0.dp + val anchorBottomClearance = 20.0.dp + const val reasonOpacity = 0.8f + val stageGap = 5.0.dp + const val entryBorderOpacity = 0.08f + val ambientInset = 40.0.dp + val ambientBlur = 30.0.dp + const val ambientScale = 1.1f + const val ambientSaturation = 1.2f + const val ambientBrightness = 0.55f + } +} diff --git a/wolfskin-design/src/main/res/drawable-nodpi/coming_in_rating_fresh.png b/wolfskin-design/src/main/res/drawable-nodpi/coming_in_rating_fresh.png new file mode 100644 index 00000000..ef0a98a6 Binary files /dev/null and b/wolfskin-design/src/main/res/drawable-nodpi/coming_in_rating_fresh.png differ diff --git a/wolfskin-design/src/main/res/drawable-nodpi/coming_in_rating_imdb.png b/wolfskin-design/src/main/res/drawable-nodpi/coming_in_rating_imdb.png new file mode 100644 index 00000000..bb7becf5 Binary files /dev/null and b/wolfskin-design/src/main/res/drawable-nodpi/coming_in_rating_imdb.png differ diff --git a/wolfskin-design/src/main/res/drawable-nodpi/coming_in_rating_rotten.png b/wolfskin-design/src/main/res/drawable-nodpi/coming_in_rating_rotten.png new file mode 100644 index 00000000..678af063 Binary files /dev/null and b/wolfskin-design/src/main/res/drawable-nodpi/coming_in_rating_rotten.png differ diff --git a/wolfskin-design/src/main/res/drawable-nodpi/coming_in_rating_spilled.png b/wolfskin-design/src/main/res/drawable-nodpi/coming_in_rating_spilled.png new file mode 100644 index 00000000..988d6554 Binary files /dev/null and b/wolfskin-design/src/main/res/drawable-nodpi/coming_in_rating_spilled.png differ diff --git a/wolfskin-design/src/main/res/drawable-nodpi/coming_in_rating_tmdb.png b/wolfskin-design/src/main/res/drawable-nodpi/coming_in_rating_tmdb.png new file mode 100644 index 00000000..48a14150 Binary files /dev/null and b/wolfskin-design/src/main/res/drawable-nodpi/coming_in_rating_tmdb.png differ diff --git a/wolfskin-design/src/main/res/drawable-nodpi/coming_in_rating_upright.png b/wolfskin-design/src/main/res/drawable-nodpi/coming_in_rating_upright.png new file mode 100644 index 00000000..2a2bfa89 Binary files /dev/null and b/wolfskin-design/src/main/res/drawable-nodpi/coming_in_rating_upright.png differ diff --git a/wolfskin-design/src/main/res/drawable/ic_rating_imdb.xml b/wolfskin-design/src/main/res/drawable/ic_rating_imdb.xml new file mode 100644 index 00000000..6725d42f --- /dev/null +++ b/wolfskin-design/src/main/res/drawable/ic_rating_imdb.xml @@ -0,0 +1,22 @@ + + + + + + + diff --git a/wolfskin-design/src/main/res/drawable/ic_rating_tmdb.xml b/wolfskin-design/src/main/res/drawable/ic_rating_tmdb.xml new file mode 100644 index 00000000..31c0be7d --- /dev/null +++ b/wolfskin-design/src/main/res/drawable/ic_rating_tmdb.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + diff --git a/wolfskin-design/src/main/res/drawable/ic_rotten_tomatoes_fresh.xml b/wolfskin-design/src/main/res/drawable/ic_rotten_tomatoes_fresh.xml new file mode 100644 index 00000000..5dbfb65e --- /dev/null +++ b/wolfskin-design/src/main/res/drawable/ic_rotten_tomatoes_fresh.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/wolfskin-design/src/main/res/drawable/ic_rotten_tomatoes_rotten.xml b/wolfskin-design/src/main/res/drawable/ic_rotten_tomatoes_rotten.xml new file mode 100644 index 00000000..1e3dc568 --- /dev/null +++ b/wolfskin-design/src/main/res/drawable/ic_rotten_tomatoes_rotten.xml @@ -0,0 +1,9 @@ + + + diff --git a/wolfskin-design/src/main/res/drawable/ic_rt_spilled.xml b/wolfskin-design/src/main/res/drawable/ic_rt_spilled.xml new file mode 100644 index 00000000..fea81f97 --- /dev/null +++ b/wolfskin-design/src/main/res/drawable/ic_rt_spilled.xml @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wolfskin-design/src/main/res/drawable/ic_rt_upright.xml b/wolfskin-design/src/main/res/drawable/ic_rt_upright.xml new file mode 100644 index 00000000..e7166b39 --- /dev/null +++ b/wolfskin-design/src/main/res/drawable/ic_rt_upright.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + diff --git a/wolfskin-design/src/main/res/drawable/title_eyeoff.xml b/wolfskin-design/src/main/res/drawable/title_eyeoff.xml new file mode 100644 index 00000000..2e70993e --- /dev/null +++ b/wolfskin-design/src/main/res/drawable/title_eyeoff.xml @@ -0,0 +1,3 @@ + + + diff --git a/wolfskin-design/src/main/res/drawable/title_more.xml b/wolfskin-design/src/main/res/drawable/title_more.xml new file mode 100644 index 00000000..5a0c05ff --- /dev/null +++ b/wolfskin-design/src/main/res/drawable/title_more.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/wolfskin-design/src/main/res/drawable/title_restart.xml b/wolfskin-design/src/main/res/drawable/title_restart.xml new file mode 100644 index 00000000..56b12c0e --- /dev/null +++ b/wolfskin-design/src/main/res/drawable/title_restart.xml @@ -0,0 +1,4 @@ + + + + diff --git a/wolfskin-design/src/main/res/drawable/title_tracks.xml b/wolfskin-design/src/main/res/drawable/title_tracks.xml new file mode 100644 index 00000000..2bd8d4ea --- /dev/null +++ b/wolfskin-design/src/main/res/drawable/title_tracks.xml @@ -0,0 +1,4 @@ + + + + diff --git a/wolfskin-design/src/main/res/drawable/title_trailer.xml b/wolfskin-design/src/main/res/drawable/title_trailer.xml new file mode 100644 index 00000000..b81fba2c --- /dev/null +++ b/wolfskin-design/src/main/res/drawable/title_trailer.xml @@ -0,0 +1,4 @@ + + + + diff --git a/wolfskin-design/src/main/res/drawable/title_version.xml b/wolfskin-design/src/main/res/drawable/title_version.xml new file mode 100644 index 00000000..2d6a9570 --- /dev/null +++ b/wolfskin-design/src/main/res/drawable/title_version.xml @@ -0,0 +1,4 @@ + + + + diff --git a/wolfskin-design/src/main/res/drawable/wolfskin_alert.xml b/wolfskin-design/src/main/res/drawable/wolfskin_alert.xml new file mode 100644 index 00000000..ff7d9894 --- /dev/null +++ b/wolfskin-design/src/main/res/drawable/wolfskin_alert.xml @@ -0,0 +1,4 @@ + + + + diff --git a/wolfskin-design/src/main/res/drawable/wolfskin_check.xml b/wolfskin-design/src/main/res/drawable/wolfskin_check.xml new file mode 100644 index 00000000..948e1e20 --- /dev/null +++ b/wolfskin-design/src/main/res/drawable/wolfskin_check.xml @@ -0,0 +1,4 @@ + + + + diff --git a/wolfskin-design/src/main/res/drawable/wolfskin_clock.xml b/wolfskin-design/src/main/res/drawable/wolfskin_clock.xml new file mode 100644 index 00000000..be066ab9 --- /dev/null +++ b/wolfskin-design/src/main/res/drawable/wolfskin_clock.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/wolfskin-design/src/main/res/drawable/wolfskin_down.xml b/wolfskin-design/src/main/res/drawable/wolfskin_down.xml new file mode 100644 index 00000000..e55cd1cb --- /dev/null +++ b/wolfskin-design/src/main/res/drawable/wolfskin_down.xml @@ -0,0 +1,4 @@ + + + + diff --git a/wolfskin-design/src/main/res/drawable/wolfskin_download.xml b/wolfskin-design/src/main/res/drawable/wolfskin_download.xml new file mode 100644 index 00000000..4df16c9e --- /dev/null +++ b/wolfskin-design/src/main/res/drawable/wolfskin_download.xml @@ -0,0 +1,3 @@ + + + diff --git a/wolfskin-design/src/main/res/drawable/wolfskin_eye.xml b/wolfskin-design/src/main/res/drawable/wolfskin_eye.xml new file mode 100644 index 00000000..221d9b5e --- /dev/null +++ b/wolfskin-design/src/main/res/drawable/wolfskin_eye.xml @@ -0,0 +1 @@ + diff --git a/wolfskin-design/src/main/res/drawable/wolfskin_film.xml b/wolfskin-design/src/main/res/drawable/wolfskin_film.xml new file mode 100644 index 00000000..45648655 --- /dev/null +++ b/wolfskin-design/src/main/res/drawable/wolfskin_film.xml @@ -0,0 +1,4 @@ + + + + diff --git a/wolfskin-design/src/main/res/drawable/wolfskin_gear.xml b/wolfskin-design/src/main/res/drawable/wolfskin_gear.xml new file mode 100644 index 00000000..b823a403 --- /dev/null +++ b/wolfskin-design/src/main/res/drawable/wolfskin_gear.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/wolfskin-design/src/main/res/drawable/wolfskin_grid.xml b/wolfskin-design/src/main/res/drawable/wolfskin_grid.xml new file mode 100644 index 00000000..e19e2857 --- /dev/null +++ b/wolfskin-design/src/main/res/drawable/wolfskin_grid.xml @@ -0,0 +1,3 @@ + + + diff --git a/wolfskin-design/src/main/res/drawable/wolfskin_hide.xml b/wolfskin-design/src/main/res/drawable/wolfskin_hide.xml new file mode 100644 index 00000000..fe20e18d --- /dev/null +++ b/wolfskin-design/src/main/res/drawable/wolfskin_hide.xml @@ -0,0 +1,4 @@ + + + + diff --git a/wolfskin-design/src/main/res/drawable/wolfskin_info.xml b/wolfskin-design/src/main/res/drawable/wolfskin_info.xml new file mode 100644 index 00000000..7bcf471d --- /dev/null +++ b/wolfskin-design/src/main/res/drawable/wolfskin_info.xml @@ -0,0 +1,4 @@ + + + + diff --git a/wolfskin-design/src/main/res/drawable/wolfskin_left.xml b/wolfskin-design/src/main/res/drawable/wolfskin_left.xml new file mode 100644 index 00000000..62060544 --- /dev/null +++ b/wolfskin-design/src/main/res/drawable/wolfskin_left.xml @@ -0,0 +1,4 @@ + + + + diff --git a/wolfskin-design/src/main/res/drawable/wolfskin_play.xml b/wolfskin-design/src/main/res/drawable/wolfskin_play.xml new file mode 100644 index 00000000..96af58e1 --- /dev/null +++ b/wolfskin-design/src/main/res/drawable/wolfskin_play.xml @@ -0,0 +1,3 @@ + + + diff --git a/wolfskin-design/src/main/res/drawable/wolfskin_plus.xml b/wolfskin-design/src/main/res/drawable/wolfskin_plus.xml new file mode 100644 index 00000000..dc780c85 --- /dev/null +++ b/wolfskin-design/src/main/res/drawable/wolfskin_plus.xml @@ -0,0 +1,4 @@ + + + + diff --git a/wolfskin-design/src/main/res/drawable/wolfskin_right.xml b/wolfskin-design/src/main/res/drawable/wolfskin_right.xml new file mode 100644 index 00000000..7a1835b2 --- /dev/null +++ b/wolfskin-design/src/main/res/drawable/wolfskin_right.xml @@ -0,0 +1,3 @@ + + + diff --git a/wolfskin-design/src/main/res/drawable/wolfskin_sort.xml b/wolfskin-design/src/main/res/drawable/wolfskin_sort.xml new file mode 100644 index 00000000..fd08bb9f --- /dev/null +++ b/wolfskin-design/src/main/res/drawable/wolfskin_sort.xml @@ -0,0 +1,3 @@ + + + diff --git a/wolfskin-design/src/main/res/drawable/wolfskin_sparkle.xml b/wolfskin-design/src/main/res/drawable/wolfskin_sparkle.xml new file mode 100644 index 00000000..aa2679ce --- /dev/null +++ b/wolfskin-design/src/main/res/drawable/wolfskin_sparkle.xml @@ -0,0 +1,3 @@ + + + diff --git a/wolfskin-design/src/main/res/drawable/wolfskin_tray.xml b/wolfskin-design/src/main/res/drawable/wolfskin_tray.xml new file mode 100644 index 00000000..b902f2fd --- /dev/null +++ b/wolfskin-design/src/main/res/drawable/wolfskin_tray.xml @@ -0,0 +1,4 @@ + + + + diff --git a/wolfskin-design/src/main/res/drawable/wolfskin_tv.xml b/wolfskin-design/src/main/res/drawable/wolfskin_tv.xml new file mode 100644 index 00000000..52f1c851 --- /dev/null +++ b/wolfskin-design/src/main/res/drawable/wolfskin_tv.xml @@ -0,0 +1,4 @@ + + + + diff --git a/wolfskin-design/src/main/res/drawable/wolfskin_undo.xml b/wolfskin-design/src/main/res/drawable/wolfskin_undo.xml new file mode 100644 index 00000000..a600fb81 --- /dev/null +++ b/wolfskin-design/src/main/res/drawable/wolfskin_undo.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/wolfskin-design/src/main/res/drawable/wolfskin_users.xml b/wolfskin-design/src/main/res/drawable/wolfskin_users.xml new file mode 100644 index 00000000..adbd06d3 --- /dev/null +++ b/wolfskin-design/src/main/res/drawable/wolfskin_users.xml @@ -0,0 +1,4 @@ + + + + diff --git a/wolfskin-design/src/main/res/drawable/wolfskin_wifi.xml b/wolfskin-design/src/main/res/drawable/wolfskin_wifi.xml new file mode 100644 index 00000000..f43ded04 --- /dev/null +++ b/wolfskin-design/src/main/res/drawable/wolfskin_wifi.xml @@ -0,0 +1,4 @@ + + + + diff --git a/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/ComingInRatingsGateTest.kt b/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/ComingInRatingsGateTest.kt new file mode 100644 index 00000000..c79d10db --- /dev/null +++ b/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/ComingInRatingsGateTest.kt @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: GPL-2.0-only +package org.justinvisser.wolfskin.design + +import java.util.Locale +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.launch +import kotlinx.coroutines.test.advanceTimeBy +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Assert.* +import org.junit.Test + +/** The fake coroutine clock proves the production dwell/cache decision without a Compose scheduler. */ +@OptIn(ExperimentalCoroutinesApi::class) +class ComingInRatingsGateTest { + private val first = ComingInRequest("first", "movie", 1, "First", "justin", "Justin", "justin", "Justin", ComingInStage.Waiting, + ratings = listOf(ComingInRating("imdb", 6.0))) + private val second = first.copy(id = "second", tmdbId = 2, title = "Second", ratings = listOf(ComingInRating("tmdb", 7.2))) + + @Test fun uncachedDwellCancelsOnLeaveAndReentryStartsAFreshRead() = runTest { + val state = ComingInState() + state.update(ComingInSnapshot(listOf(first, second), ComingInStatus.Ready, signedIn = true)) + val abandoned = launch { state.awaitFocusedRatings() } + runCurrent() + advanceTimeBy(100) + assertFalse(state.ratingsVisible) + abandoned.cancel() + state.focus(second.id) + val next = launch { state.awaitFocusedRatings() } + runCurrent() + advanceTimeBy(349) + runCurrent() + assertFalse(state.ratingsVisible) + advanceTimeBy(1) + runCurrent() + assertTrue(state.ratingsVisible) + next.join() + state.focus(first.id) + assertFalse(state.ratingsVisible) + launch { state.awaitFocusedRatings() } + runCurrent() + advanceTimeBy(350) + runCurrent() + assertTrue("Returning to the abandoned uncached title must complete a new dwell", state.ratingsVisible) + state.focus(second.id) + assertTrue("A previously read title must be visible on the focus transition itself", state.ratingsVisible) + } + + @Test fun signOutClearsCachedVisibilityAndSignInUsesFreshRatingAndLocale() = runTest { + val state = ComingInState() + val snapshot = ComingInSnapshot(listOf(first), ComingInStatus.Ready, signedIn = true) + state.update(snapshot) + launch { state.awaitFocusedRatings() } + runCurrent(); advanceTimeBy(350); runCurrent() + assertTrue(state.ratingsVisible) + state.update(snapshot.copy(signedIn = false)) + assertFalse(state.ratingsVisible) + val refreshed = first.copy(ratings = listOf(ComingInRating("imdb", 7.6))) + state.update(snapshot.copy(items = listOf(refreshed))) + assertFalse("Sign-out invalidates the previous session's rating gate", state.ratingsVisible) + launch { state.awaitFocusedRatings() } + runCurrent(); advanceTimeBy(350); runCurrent() + assertTrue(state.ratingsVisible) + val rating = state.focused!!.ratings.single() + assertEquals("7,6", formatComingInRating(rating, Locale.forLanguageTag("nl-NL"))) + assertEquals("7.6", formatComingInRating(rating, Locale.ENGLISH)) + assertEquals("87%", formatComingInRating(ComingInRating("fresh", 87.9, true), Locale.forLanguageTag("nl-NL"))) + } + + @Test fun savedOfflineRowsOnlyShowPreviouslyReadRatingsAcrossHouseholdRequests() = runTest { + val state = ComingInState() + val sharedCopy = first.copy(id = "other-request", requesterKey = "shared", requesterName = "Shared") + val online = ComingInSnapshot(listOf(first, second, sharedCopy), ComingInStatus.Ready, signedIn = true) + state.update(online) + launch { state.awaitFocusedRatings() } + runCurrent(); advanceTimeBy(350); runCurrent() + state.update(online.copy(status = ComingInStatus.Unavailable)) + state.focus(second.id) + state.awaitFocusedRatings() + assertFalse("An unread title cannot acquire ratings while offline", state.ratingsVisible) + state.focus(sharedCopy.id) + assertTrue("The title cache is shared across request rows for the same media type and TMDB id", state.ratingsVisible) + } +} diff --git a/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/DiscoverCaptureTest.kt b/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/DiscoverCaptureTest.kt new file mode 100644 index 00000000..a913391e --- /dev/null +++ b/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/DiscoverCaptureTest.kt @@ -0,0 +1,184 @@ +// SPDX-License-Identifier: GPL-2.0-only +package org.justinvisser.wolfskin.design + +import android.app.Application +import android.graphics.BitmapFactory +import android.view.View +import android.view.WindowManager +import androidx.activity.ComponentActivity +import androidx.compose.foundation.layout.requiredSize +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.asImageBitmap +import androidx.compose.ui.graphics.ImageBitmap +import androidx.compose.ui.test.junit4.createAndroidComposeRule +import androidx.compose.ui.test.onRoot +import androidx.compose.ui.test.SemanticsMatcher +import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.onAllNodesWithText +import androidx.compose.ui.semantics.SemanticsProperties +import androidx.compose.ui.semantics.SemanticsActions +import androidx.compose.ui.text.TextLayoutResult +import org.json.JSONArray +import org.json.JSONObject +import com.github.takahirom.roborazzi.captureRoboImage +import java.io.File +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.Assert.assertTrue +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config +import org.robolectric.annotation.GraphicsMode + +/** Captures execute the shipped Compose surface with offline fixture artwork and actual shell focus. */ +@RunWith(RobolectricTestRunner::class) +@Config(sdk = [34], application = Application::class, qualifiers = "w960dp-h540dp-xhdpi") +@GraphicsMode(GraphicsMode.Mode.NATIVE) +class DiscoverCaptureTest { + @get:Rule val rule = createAndroidComposeRule() + private val fixture = discoverTestFixture() + + @Before fun fullscreen() { + rule.activity.window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN) + @Suppress("DEPRECATION") + rule.activity.window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_FULLSCREEN or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY + } + + private fun capture(name: String, person: String = "justin", snapshotTransform: (DiscoverSnapshot) -> DiscoverSnapshot = { it }, configure: (DiscoverState) -> Unit = {}) { + val titleState = name.substringAfter("st-").toInt() in setOf(58, 59, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 87, 110) + val shell = ShellState(fixturePeople(), person).apply { pickerVisible = false; enterDestination(if (titleState) "home" else "discover") } + val snapshot = snapshotTransform(fixture.snapshot(person)) + val state = DiscoverState(shell, snapshot, RecordingDiscoverOperations(snapshot, person), CoroutineScope(Dispatchers.Main.immediate), + onPush = shell::enterDestination, onPop = { shell.enterDestination("discover") }, serviceLanes = fixture::service) + configure(state) + val painters = mutableMapOf() + rule.setContent { + WolfskinTheme { + CompositionLocalProvider(LocalDiscoverArt provides { path -> painters.getOrPut(path) { BitmapFactory.decodeFile(path).asImageBitmap() } }) { + ShellSurface(shell, Modifier.requiredSize(WolfskinTokens.Shell.stageWidth, WolfskinTokens.Shell.stageHeight), overlay = { DiscoverOverlay(state) }) { DiscoverScreen(state, it) } + } + } + } + rule.mainClock.advanceTimeBy(1000) + rule.waitForIdle() + val directory = File(requireNotNull(System.getProperty("wolfskin.captureDirectory")), "discover").apply { mkdirs() } + rule.onRoot().captureRoboImage(File(directory, "$name.png").absolutePath) + recordTypography(directory, name) + } + + private fun recordTypography(directory: File, name: String) { + val rows = JSONArray() + rule.onAllNodes(SemanticsMatcher.keyIsDefined(SemanticsProperties.Text), useUnmergedTree = true).fetchSemanticsNodes().forEach { node -> + val layouts = mutableListOf() + if (SemanticsActions.GetTextLayoutResult in node.config) node.config[SemanticsActions.GetTextLayoutResult].action?.invoke(layouts) + layouts.forEach { layout -> + val text = layout.layoutInput.text.text + val lines = JSONArray() + repeat(layout.lineCount) { index -> lines.put(text.substring(layout.getLineStart(index), layout.getLineEnd(index, visibleEnd = true))) } + rows.put(JSONObject().put("text", text).put("lines", layout.lineCount).put("lineTexts", lines) + .put("fontSizeSp", layout.layoutInput.style.fontSize.value).put("fontWeight", layout.layoutInput.style.fontWeight?.weight) + .put("lineHeightSp", layout.layoutInput.style.lineHeight.value.takeIf { it.isFinite() } ?: JSONObject.NULL).put("trim", layout.layoutInput.style.lineHeightStyle?.trim.toString()) + .put("density", layout.layoutInput.density.density).put("fontScale", layout.layoutInput.density.fontScale) + .put("left", node.boundsInRoot.left).put("top", node.boundsInRoot.top).put("width", node.boundsInRoot.width).put("height", node.boundsInRoot.height)) + } + } + File(directory, "$name-type-metrics.json").writeText(rows.toString(2)) + } + + @Test fun st029_discover() = capture("st-029") + @Test fun st030_picksCollection() = capture("st-030") { state -> state.openCollection(state.lanes.first { it.id == "pk-movie" }) } + @Test fun st031_hidden() = capture("st-031") { hidden(it) } + @Test fun st032_restore() { + capture("st-032") { state -> hidden(state); state.overlay = DiscoverOverlayState.Restore(state.snapshot.picks[7]) } + val title = rule.onAllNodesWithText(fixture.snapshot("justin").picks[7].title, useUnmergedTree = true) + .fetchSemanticsNodes().maxBy { it.boundsInRoot.left }.boundsInRoot + val sub = rule.onNodeWithText("Hidden from Justinโ€™s picks.", useUnmergedTree = true).fetchSemanticsNode().boundsInRoot + val gap = with(rule.density) { (WolfskinTokens.Discover.sheetGap + WolfskinTokens.Discover.sheetSubTop).toPx() } + assertTrue("Restore subtitle must retain the negative top margin", kotlin.math.abs(sub.top - title.bottom - gap) <= 1f) + } + @Test fun st033_failedBadge() = capture("st-033") { state -> + val lane = state.lanes.first { it.id == "pk-movie" } + state.requests[lane.titles[1].key] = listOf(DiscoverRequestResult(RequestPhase.Receipt, "Justin", "Failed", requester = "justin")) + state.focus(state.lanes.indexOf(lane) + 2, 1) + } + @Test fun st034_retryTail() = capture("st-034", snapshotTransform = { snapshot -> + snapshot.copy(lanes = snapshot.lanes.map { if (it.id == "trending") it.copy(tail = DiscoverTail.Retry) else it }) + }) { state -> val lane = state.lanes.first { it.id == "trending" }; state.focus(state.lanes.indexOf(lane) + 2, lane.titles.size) } + @Test fun st035_duplicateTail() = capture("st-035") { state -> + val titles = state.snapshot.lanes.first { it.id == "trending" }.fullTitles.take(36) + state.openCollection(DiscoverLane("trending", "Trending", titles, tail = DiscoverTail.ShowMore)) + state.collection!!.index = state.collection!!.tailIndex + } + @Test fun st036_needsSignIn() { + capture("st-036", snapshotTransform = { DiscoverSnapshot(status = DiscoverStatus.NeedsSignIn) }) + val button = rule.onNodeWithText("Try again").fetchSemanticsNode().boundsInRoot + val minimum = with(rule.density) { WolfskinTokens.Layout.buttonHeight.toPx() } + assertTrue("The sign-in button must not shrink to fit the scroll row", button.height >= minimum) + } + @Test fun st037_series() { + capture("st-037", person = "mindel") { it.filter = "tv" } + val title = rule.onNodeWithText("56 Days", useUnmergedTree = true).fetchSemanticsNode() + val layouts = mutableListOf() + title.config[SemanticsActions.GetTextLayoutResult].action?.invoke(layouts) + val layout = layouts.single() + val cssHeight = with(rule.density) { DiscoverType.hero.lineHeight.toPx() } * layout.lineCount + assertTrue("Natural font height must not inflate the hero CSS line box", kotlin.math.abs(title.boundsInRoot.height - cssHeight) <= 1f) + } + @Test fun st038_noSeeds() = capture("st-038", snapshotTransform = { it.copy(status = DiscoverStatus.NoSeeds) }) + @Test fun st039_trendingCollection() = capture("st-039") { state -> state.openCollection(state.lanes.first { it.id == "trending" }) } + @Test fun st040_service() = capture("st-040") { state -> state.openService(state.snapshot.services.first()) } + @Test fun st041_unreachable() = capture("st-041", snapshotTransform = { DiscoverSnapshot(status = DiscoverStatus.Unavailable) }) + @Test fun st058_hiddenReceipt() = capture("st-058") { state -> state.openTitle(state.snapshot.picks.first()); state.titleButton = 2; state.hide(state.title!!) } + @Test fun st059_hiddenTitle() = capture("st-059") { state -> state.hide(state.snapshot.picks.first()); state.overlay = null; state.openTitle(state.snapshot.picks.first()); state.titleButton = 2 } + @Test fun st071_requestSelf() = capture("st-071") { request(it) } + @Test fun st072_requestOther() = capture("st-072") { request(it, other = true) } + @Test fun st073_addHeld() = capture("st-073") { state -> request(state, fixture.find("The Girl Who Leapt Through Time"), other = true) } + @Test fun st074_receipt() = capture("st-074") { request(it, other = true, phase = RequestPhase.Receipt) } + @Test fun st075_notConfirmed() = capture("st-075") { request(it, phase = RequestPhase.NotConfirmed) } + @Test fun st076_pending() = capture("st-076") { request(it, phase = RequestPhase.Pending) } + @Test fun st077_refused() = capture("st-077", person = "mindel") { request(it, other = true, phase = RequestPhase.Refused) } + @Test fun st078_recipientsLoading() = capture("st-078") { request(it, other = true, phase = RequestPhase.LoadingRecipients) } + @Test fun st079_recipientsUnavailable() = capture("st-079") { request(it, other = true, phase = RequestPhase.RecipientsUnavailable) } + @Test fun st080_seasonsUnknown() = capture("st-080") { state -> request(state, state.snapshot.picks.first { it.type == "tv" }) } + @Test fun st087_sharedReceipt() = capture("st-087", person = "shared") { request(it, phase = RequestPhase.Receipt) } + @Test fun st105_pickPlate() = capture("st-105") { state -> val lane = state.lanes.first { it.id == "pk-movie" }; state.focus(state.lanes.indexOf(lane) + 2, 1) } + @Test fun st110_heldRatings() = capture("st-110") { state -> request(state, fixture.find("The Girl Who Leapt Through Time"), other = true) } + + private fun hidden(state: DiscoverState) { + state.hide(state.snapshot.picks[7]); state.hide(state.snapshot.picks[20]); state.overlay = null + val lane = state.lanes.first { it.hidden } + state.focus(state.lanes.indexOf(lane) + 2, lane.titles.indexOfFirst { it.key == state.snapshot.picks[7].key }) + } + + private fun request(state: DiscoverState, title: DiscoverTitle = state.snapshot.picks.first(), other: Boolean = false, phase: RequestPhase = RequestPhase.Choose) { + state.openTitle(title); state.openRequest(other, phase = phase) + if (phase == RequestPhase.Receipt) { + val sheet = (state.overlay as DiscoverOverlayState.Request).state + val receipt = DiscoverRequestResult(phase, state.shell.person.name, requester = sheet.selectedPerson.key) + sheet.result = receipt; state.requests[title.key] = listOf(receipt) + } + } +} + +internal fun discoverTestFixture(): DiscoverFixture { + val json = DiscoverCaptureTest::class.java.getResourceAsStream("/wolfskin-discover.json")!!.bufferedReader().use { it.readText() } + val assets = File("../app/src/debug/assets/wolfskin-discover").canonicalFile + return DiscoverFixture(json) { File(assets, it).absolutePath } +} + +/** In-process effects are inspectable without exposing any live client or endpoint. */ +internal class RecordingDiscoverOperations(private val snapshot: DiscoverSnapshot, private val actor: String) : DiscoverOperations { + val sent = mutableListOf() + var checked = 0 + var next = RequestPhase.Receipt + var mutationSucceeds = true + override suspend fun request(intent: DiscoverRequest): DiscoverRequestResult { sent += intent; return DiscoverRequestResult(next, actor.replaceFirstChar { it.uppercase() }) } + override suspend fun check(intent: DiscoverRequest): DiscoverRequestResult { checked++; return DiscoverRequestResult(next, actor.replaceFirstChar { it.uppercase() }) } + override suspend fun hide(profile: String, title: DiscoverTitle) = mutationSucceeds + override suspend fun restore(profile: String, title: DiscoverTitle) = mutationSucceeds + override suspend fun refresh() = snapshot +} diff --git a/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/DiscoverKeysTest.kt b/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/DiscoverKeysTest.kt new file mode 100644 index 00000000..8d95e376 --- /dev/null +++ b/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/DiscoverKeysTest.kt @@ -0,0 +1,258 @@ +// SPDX-License-Identifier: GPL-2.0-only +package org.justinvisser.wolfskin.design + +import android.app.Application +import android.view.KeyEvent as AndroidKeyEvent +import androidx.compose.ui.input.key.Key +import androidx.compose.ui.input.key.KeyEvent +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onNodeWithTag +import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.performKeyInput +import androidx.compose.ui.test.pressKey +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import org.json.JSONObject +import org.junit.Assert.* +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config + +/** Acceptance data drives real Android events through the shell's production focus adapter. */ +@RunWith(RobolectricTestRunner::class) +@Config(sdk = [34], application = Application::class, qualifiers = "w960dp-h540dp-xhdpi") +class DiscoverKeysTest { + @get:Rule val rule = createComposeRule() + private val fixture = discoverTestFixture() + private val shell = ShellState(fixturePeople(), "justin") + private val snapshot = fixture.snapshot("justin") + private val operations = RecordingDiscoverOperations(snapshot, "justin") + private val state = DiscoverState(shell, snapshot, operations, CoroutineScope(Dispatchers.Main.immediate), shell::enterDestination, + { shell.enterDestination("discover") }, fixture::service) + + private fun launch() { + rule.setContent { + WolfskinTheme { + ShellSurface(shell, overlay = { DiscoverOverlay(state) }) { modifier -> + if (shell.route == "discover" || shell.route.startsWith("discover-")) DiscoverScreen(state, modifier) else ShellPlaceholder(shell.route, modifier) + } + } + } + } + + private fun press(first: Key, second: Key? = null) = listOfNotNull(first, second).forEach { key -> rule.onNodeWithTag("wolfskin-shell").performKeyInput { pressKey(key) } } + + private fun replay(goal: String) { + val paths = JSONObject(javaClass.getResourceAsStream("/discover-keys.json")!!.bufferedReader().use { it.readText() }).getJSONArray("pressPaths") + val path = (0 until paths.length()).map { paths.getJSONObject(it) }.single { it.getString("goal") == goal } + val keys = path.getJSONArray("keys") + assertEquals(path.getInt("presses"), keys.length()) + launch() + repeat(keys.length()) { index -> press(when (keys.getString(index)) { + "OK" -> Key.DirectionCenter; "UP" -> Key.DirectionUp; "DOWN" -> Key.DirectionDown; "LEFT" -> Key.DirectionLeft; "RIGHT" -> Key.DirectionRight; else -> Key.Back + }) } + rule.waitForIdle() + } + + @Test fun openDiscoverInFourPresses() { + replay("Open Discover") + assertEquals("discover", shell.route) + assertFalse(shell.navFocused) + assertEquals("The Amazing Spider-Man", state.hero?.title) + } + + @Test fun requestForYourselfInSevenPresses() { + replay("Request a pick for yourself") + val sheet = (state.overlay as DiscoverOverlayState.Request).state + assertEquals(RequestPhase.Receipt, sheet.phase) + assertEquals("justin", operations.sent.single().requester) + assertEquals("Justin", sheet.result?.actor) + assertEquals("Waiting", state.requests.getValue(requireNotNull(state.title).key).single().stage) + } + + @Test fun requestForMindelInNinePresses() { + replay("Request a pick for Mindel") + val sheet = (state.overlay as DiscoverOverlayState.Request).state + assertEquals(RequestPhase.Receipt, sheet.phase) + assertEquals("mindel", operations.sent.single().requester) + assertEquals("Justin", sheet.result?.actor) + } + + @Test fun notInterestedInEightPressesAndUndoRestoresEveryIndex() { + val original = state.lanes.map { lane -> lane.id to lane.titles.map { it.key } } + replay("Round 3 ยท Not interested on a pick (Discover hero)") + val hidden = state.overlay as DiscoverOverlayState.Hidden + assertTrue(state.isHidden(hidden.title)) + assertTrue(state.heroes.none { it.key == hidden.title.key }) + assertTrue(state.lanes.filterNot { it.hidden }.none { lane -> lane.titles.any { it.key == hidden.title.key } }) + press(Key.DirectionCenter) + assertNull(state.overlay) + assertEquals("The Amazing Spider-Man", state.hero?.title) + assertEquals(original, state.lanes.map { lane -> lane.id to lane.titles.map { it.key } }) + } + + @Test fun heldOkOpensSheetButNeverSubmits() { + replay("Open Discover") + press(Key.DirectionCenter) + rule.runOnIdle { + shell.handleKey(KeyEvent(AndroidKeyEvent(0, 0, AndroidKeyEvent.ACTION_DOWN, AndroidKeyEvent.KEYCODE_DPAD_CENTER, 0))) + repeat(8) { index -> shell.handleKey(KeyEvent(AndroidKeyEvent(0, 0, AndroidKeyEvent.ACTION_DOWN, AndroidKeyEvent.KEYCODE_DPAD_CENTER, index + 1))) } + shell.handleKey(KeyEvent(AndroidKeyEvent(0, 0, AndroidKeyEvent.ACTION_UP, AndroidKeyEvent.KEYCODE_DPAD_CENTER, 0))) + } + assertEquals(RequestPhase.Choose, (state.overlay as DiscoverOverlayState.Request).state.phase) + assertTrue(operations.sent.isEmpty()) + } + + @Test fun uncertainOutcomeChecksWithoutResending() { + operations.next = RequestPhase.NotConfirmed + replay("Request a pick for yourself") + assertEquals(1, operations.sent.size) + assertEquals(RequestPhase.NotConfirmed, (state.overlay as DiscoverOverlayState.Request).state.phase) + operations.next = RequestPhase.Receipt + press(Key.DirectionCenter) + assertEquals(1, operations.sent.size) + assertEquals(1, operations.checked) + assertEquals(RequestPhase.Receipt, (state.overlay as DiscoverOverlayState.Request).state.phase) + } + + @Test fun closingAnUncertainReceiptNeverTurnsReopeningIntoAnotherPost() { + operations.next = RequestPhase.NotConfirmed + replay("Request a pick for yourself") + press(Key.Back, Key.DirectionCenter) + assertEquals(RequestPhase.NotConfirmed, (state.overlay as DiscoverOverlayState.Request).state.phase) + operations.next = RequestPhase.Receipt + press(Key.DirectionCenter) + assertEquals(1, operations.sent.size) + assertEquals(1, operations.checked) + assertEquals(RequestPhase.Receipt, (state.overlay as DiscoverOverlayState.Request).state.phase) + } + + @Test fun requestingForAnotherPersonKeepsYourOwnRequestedAction() { + replay("Request a pick for yourself") + press(Key.DirectionCenter) + press(Key.DirectionRight, Key.DirectionCenter) + press(Key.DirectionCenter, Key.DirectionCenter) + assertEquals(setOf("justin", "mindel"), state.requests.getValue(state.title!!.key).map { it.requester }.toSet()) + press(Key.DirectionCenter) + press(Key.DirectionLeft, Key.DirectionCenter) + assertTrue(shell.requestsVisible) + assertEquals(2, operations.sent.size) + } + + @Test fun choosingAnUncertainRecipientAgainNeverResubmits() { + operations.next = RequestPhase.NotConfirmed + replay("Open Discover") + press(Key.DirectionCenter) + press(Key.DirectionRight, Key.DirectionCenter) + press(Key.DirectionDown, Key.DirectionCenter) + press(Key.DirectionCenter) + assertEquals("shared", operations.sent.single().requester) + press(Key.Back, Key.DirectionCenter) + press(Key.DirectionDown, Key.DirectionCenter) + press(Key.DirectionCenter) + assertEquals(1, operations.sent.size) + assertEquals(RequestPhase.NotConfirmed, (state.overlay as DiscoverOverlayState.Request).state.phase) + operations.next = RequestPhase.Receipt + press(Key.DirectionCenter) + assertEquals(1, operations.sent.size) + assertEquals(1, operations.checked) + assertEquals(RequestPhase.Receipt, (state.overlay as DiscoverOverlayState.Request).state.phase) + } + + @Test fun unknownSeriesSeasonsNeverSubmitAndBackRestoresOpener() { + replay("Open Discover") + rule.runOnIdle { state.openTitle(snapshot.picks.first { it.type == "tv" }); state.openRequest(false) } + press(Key.DirectionCenter) + assertTrue(operations.sent.isEmpty()) + assertNull(state.overlay) + assertNotNull(state.title) + assertFalse(shell.navFocused) + } + + @Test fun cardOkWaitsForReleaseAndFocusMoveCancelsActivation() { + replay("Open Discover") + press(Key.DirectionDown, Key.DirectionDown) + rule.runOnIdle { shell.handleKey(KeyEvent(AndroidKeyEvent(0, 0, AndroidKeyEvent.ACTION_DOWN, AndroidKeyEvent.KEYCODE_DPAD_CENTER, 0))) } + assertNull(state.title) + press(Key.DirectionRight) + rule.runOnIdle { shell.handleKey(KeyEvent(AndroidKeyEvent(0, 0, AndroidKeyEvent.ACTION_UP, AndroidKeyEvent.KEYCODE_DPAD_CENTER, 0))) } + assertNull(state.title) + press(Key.DirectionCenter) + assertNotNull(state.title) + } + @Test fun downClampsToOccupiedCardsAndThenTheTail() { + shell.pickerVisible = false + val items = snapshot.picks.take(8) + state.openCollection(DiscoverLane("short", "Picks", items, tail = DiscoverTail.ShowMore)) + launch() + repeat(5) { press(Key.DirectionRight) } + assertEquals(5, state.collection!!.index % state.collection!!.columns) + press(Key.DirectionDown) + assertEquals(1, state.collection!!.index / state.collection!!.columns) + assertEquals(1, state.collection!!.index % state.collection!!.columns) + assertEquals(items.last().key, state.collection!!.items[state.collection!!.index].id) + press(Key.DirectionDown, Key.DirectionRight) + assertEquals(2, state.collection!!.index / state.collection!!.columns) + assertEquals(0, state.collection!!.index % state.collection!!.columns) + assertEquals(GridTail.ShowMore, state.collection!!.tail) + } + + @Test fun collectionRetryReadsNewTitlesAndOpensTheFirstAppendedTitle() { + shell.pickerVisible = false + val lane = state.lanes.first { it.id == "trending" } + state.openCollection(lane.copy(titles = lane.fullTitles.take(6), fullTitles = lane.fullTitles.take(6), tail = DiscoverTail.Retry)) + val grid = state.collection!! + grid.index = grid.tailIndex + launch() + press(Key.DirectionCenter) + assertEquals(GridTail.None, grid.tail) + assertEquals(lane.fullTitles.map { it.key }, grid.items.map { it.id }) + assertEquals(lane.fullTitles[6].key, grid.focusedTitle?.id) + press(Key.DirectionCenter) + assertEquals(lane.fullTitles[6], state.title) + } + + @Test fun collectionDismissalAndUndoKeepTheOriginalOrderAndFocus() { + shell.pickerVisible = false + state.openCollection(state.lanes.first { it.id == "pk-movie" }) + val grid = state.collection!! + val original = grid.items.map { it.id } + launch() + press(Key.DirectionCenter) + val opener = state.title!! + press(Key.DirectionRight, Key.DirectionRight) + press(Key.DirectionCenter) + assertFalse(grid.items.any { it.id == opener.key }) + press(Key.DirectionCenter) + assertEquals(original, grid.items.map { it.id }) + assertEquals(opener.key, grid.focusedTitle?.id) + } + + @Test fun collectionBackRestoresTheExactOrigin() { + shell.pickerVisible = false; shell.enterDestination("discover") + state.focus(3, 2) + val origin = shell.view + state.openCollection(state.lanes.first { it.id == "pk-movie" }) + launch() + press(Key.DirectionDown, Key.Back) + assertNull(state.collection) + assertSame(origin, shell.view) + assertEquals(3, shell.view.row) + assertEquals(2, shell.view.cards[state.rowKey]) + } + + @Test + @Config(qualifiers = "nl-rNL-w960dp-h540dp-xhdpi") + fun dutchPlateUsesLocaleAndStaysOnOneLine() { + shell.pickerVisible = false + val title = snapshot.picks.first().copy(ratings = listOf(DiscoverRating("tmdb", 7.8))) + state.openCollection(DiscoverLane("locale", "Picks", listOf(title))) + launch() + rule.mainClock.advanceTimeBy(1000) + rule.onNodeWithText("7,8").assertExists() + assertEquals("7.8", formatDiscoverRating(title.ratings.single(), java.util.Locale.ENGLISH)) + assertEquals("91%", formatDiscoverRating(DiscoverRating("rtCritics", 91.7), java.util.Locale.forLanguageTag("nl-NL"))) + } +} diff --git a/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/DiscoverLaneProjectionTest.kt b/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/DiscoverLaneProjectionTest.kt new file mode 100644 index 00000000..ed62d6f4 --- /dev/null +++ b/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/DiscoverLaneProjectionTest.kt @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-2.0-only +package org.justinvisser.wolfskin.design + +import org.junit.Assert.assertEquals +import org.junit.Test + +/** Feed projection must not lose titles when a contribution row is too short to display. */ +class DiscoverLaneProjectionTest { + @Test fun discardedSeedGroupRemainsAvailableInCatalogue() { + val titles = (1L..6L).map { DiscoverTitle(it, "movie", "Film $it") } + val snapshot = DiscoverSnapshot(picks = titles, seeds = listOf(DiscoverSeed("Seed", titles.subList(3, 5))), + lanes = listOf(DiscoverLane("trending", "Trending", titles)), status = DiscoverStatus.Ready) + val rows = projectDiscoverLanes(snapshot, emptyList(), "all", emptyMap()) + assertEquals(listOf("pk-movie", "trending"), rows.map { it.id }) + assertEquals(titles.take(3), rows.first().titles) + assertEquals(titles.drop(3), rows.last().titles) + } + + @Test fun catalogueDeduplicationKeepsMediaTypesDistinctAndHiddenPicksLast() { + val movie = DiscoverTitle(1, "movie", "Film") + val series = DiscoverTitle(1, "tv", "Series") + val hidden = DiscoverTitle(2, "movie", "Hidden") + val later = DiscoverTitle(3, "movie", "Later") + val snapshot = DiscoverSnapshot(hidden = listOf(hidden), status = DiscoverStatus.Ready, lanes = listOf( + DiscoverLane("first", "First", listOf(movie, series, hidden)), + DiscoverLane("second", "Second", listOf(movie, series, later)))) + val rows = projectDiscoverLanes(snapshot, emptyList(), "all", mapOf(hidden.key to hidden)) + assertEquals(listOf(listOf(movie, series), listOf(later), listOf(hidden)), rows.map { it.titles }) + assertEquals("hidden", rows.last().id) + val filtered = projectDiscoverLanes(snapshot, emptyList(), "tv", mapOf(hidden.key to hidden)) + assertEquals(listOf(listOf(series)), filtered.map { it.titles }) + } +} diff --git a/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/HomeArtTest.kt b/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/HomeArtTest.kt new file mode 100644 index 00000000..970ea46e --- /dev/null +++ b/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/HomeArtTest.kt @@ -0,0 +1,26 @@ +package org.justinvisser.wolfskin.design + +import android.app.Application +import androidx.compose.foundation.layout.size +import androidx.compose.ui.Modifier +import androidx.compose.ui.test.* +import androidx.compose.ui.test.junit4.createComposeRule +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config + +/** An unreadable local image exercises Coil's real error path without a network provider. */ +@RunWith(RobolectricTestRunner::class) +@Config(sdk = [34], application = Application::class, qualifiers = "w960dp-h540dp-xhdpi") +class HomeArtTest { + @get:Rule val rule = createComposeRule() + + @Test fun imageFailureShowsTheTitleFallbackInsteadOfAnEmptyCard() { + val title = HomeTitle("missing-image", "A missing film", "movie", poster = "file:///android_asset/wolfskin-home/not-present.jpg") + rule.setContent { WolfskinTheme { TitleArtwork(title.title, title.type, title.poster, WolfskinTokens.Card.posterW, WolfskinTokens.Card.posterH, Modifier.size(WolfskinTokens.Card.posterW, WolfskinTokens.Card.posterH)) } } + rule.waitUntil(5000) { rule.onAllNodesWithText(title.title).fetchSemanticsNodes().isNotEmpty() } + rule.onNodeWithText(title.title).assertIsDisplayed() + } +} diff --git a/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/HomeCaptureTest.kt b/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/HomeCaptureTest.kt new file mode 100644 index 00000000..04a5e866 --- /dev/null +++ b/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/HomeCaptureTest.kt @@ -0,0 +1,119 @@ +package org.justinvisser.wolfskin.design + +import android.app.Application +import android.view.View +import android.view.WindowManager +import androidx.activity.ComponentActivity +import androidx.compose.foundation.layout.requiredSize +import androidx.compose.ui.Modifier +import androidx.compose.ui.test.junit4.createAndroidComposeRule +import androidx.compose.ui.test.onRoot +import androidx.compose.ui.test.SemanticsMatcher +import androidx.compose.ui.semantics.SemanticsActions +import androidx.compose.ui.text.TextLayoutResult +import org.json.JSONArray +import org.json.JSONObject +import com.github.takahirom.roborazzi.captureRoboImage +import java.io.File +import java.util.Locale +import kotlinx.coroutines.runBlocking +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config +import org.robolectric.annotation.GraphicsMode + +/** Every frozen Home acceptance state renders the actual native Compose surface at density 2. */ +@RunWith(RobolectricTestRunner::class) +@Config(sdk = [34], application = Application::class, qualifiers = "w960dp-h540dp-xhdpi") +@GraphicsMode(GraphicsMode.Mode.NATIVE) +class HomeCaptureTest { + @get:Rule val rule = createAndroidComposeRule() + + @Before fun fullscreen() { + rule.activity.window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN) + @Suppress("DEPRECATION") + rule.activity.window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_FULLSCREEN or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY + } + + private fun capture(name: String, person: String = "justin", mode: String = "ready", row: String = "hero", column: Int = 0, nav: Int? = null) { + val previous = Locale.getDefault() + Locale.setDefault(Locale.US) + try { + val snapshot = HomeFixture(rule.activity).snapshot(person, mode) + val shell = ShellState(fixturePeople(), person).apply { + pickerVisible = false + view.row = snapshot.rows.indexOfFirst { it.id == row }.coerceAtLeast(0) + view.cards[row] = column + if (nav != null) { navFocused = true; navIndex = nav } + } + preload(snapshot, shell.view.row) + rule.setContent { WolfskinTheme { + ShellSurface(shell, Modifier.requiredSize(WolfskinTokens.Shell.stageWidth, WolfskinTokens.Shell.stageHeight)) { modifier -> HomeScreen(shell, snapshot, modifier) {} } + } } + rule.mainClock.advanceTimeBy(1200) + rule.waitForIdle() + val directory = File(System.getProperty("wolfskin.captureDirectory"), "home").apply { mkdirs() } + rule.onRoot().captureRoboImage(File(directory, "$name.png").absolutePath) + recordTextLayouts(File(directory, "$name-layout.json")) + } finally { Locale.setDefault(previous) } + } + + private fun recordTextLayouts(output: File) { + val nodes = JSONArray() + rule.onAllNodes(SemanticsMatcher.keyIsDefined(SemanticsActions.GetTextLayoutResult), useUnmergedTree = true).fetchSemanticsNodes().forEach { node -> + val results = mutableListOf() + node.config[SemanticsActions.GetTextLayoutResult].action?.invoke(results) + results.forEach { layout -> + val lines = JSONArray() + repeat(layout.lineCount) { line -> + lines.put(JSONObject().put("top", layout.getLineTop(line)).put("bottom", layout.getLineBottom(line)).put("baseline", layout.getLineBaseline(line))) + } + nodes.put(JSONObject().put("text", layout.layoutInput.text.text) + .put("left", node.boundsInRoot.left).put("top", node.boundsInRoot.top) + .put("width", layout.size.width).put("height", layout.size.height) + .put("lineHeight", layout.layoutInput.style.lineHeight.toString()) + .put("lineHeightStyle", layout.layoutInput.style.lineHeightStyle.toString()).put("lines", lines)) + } + } + output.writeText(nodes.toString(2)) + } + + private fun preload(snapshot: HomeSnapshot, focused: Int) = runBlocking { + val rows = if (focused == 0) snapshot.rows.take(2) else snapshot.rows.drop(focused).take(3) + for (row in rows) for (title in row.cards.take(8)) { + val hero = row.kind == HomeRowKind.Hero + val landscape = hero || row.cardKind != HomeCardKind.Poster + val width = if (hero) 1280 else (row.cardWidth.value * 2).toInt() + val height = if (hero) 720 else (row.cardHeight.value * 2).toInt() + val source = if (landscape) title.backdrop ?: title.poster else title.poster + if (source != null) WolfskinImages.loader(rule.activity).execute(WolfskinImages.request(rule.activity, source, width, height, !landscape)) + } + } + + @Test fun st005_loading() = capture("st-005", mode = "loading", nav = 0) + @Test fun st006_justinNext() = capture("st-006") + @Test fun st007_mindelResume() = capture("st-007", person = "mindel") + @Test fun st008_sharedResume() = capture("st-008", person = "shared") + @Test fun st009_deepTrending() = capture("st-009", row = "trending", column = 2) + @Test fun st010_heroNav() = capture("st-010", nav = 0) + @Test fun st011_deepBackNav() = capture("st-011", row = "lib-shows", column = 2, nav = 0) + @Test fun st012_explore() = capture("st-012", row = "explore") + @Test fun st013_unsigned() = capture("st-013", mode = "unsigned", row = "signin") + @Test fun st014_discoverNav() = capture("st-014", nav = 1) + @Test fun st015_offlineSaved() = capture("st-015", mode = "offline") + @Test fun st016_conductarrDown() = capture("st-016", mode = "cond-down", row = "cond-down") + @Test fun st017_conductarrSaved() = capture("st-017", mode = "cond-cached") + @Test fun st018_jellyfinDown() = capture("st-018", mode = "jf-down") + @Test fun st019_picksUnavailable() = capture("st-019", mode = "picks-unavailable", row = "trending") + @Test fun st020_missingArt() = capture("st-020", person = "shared", mode = "missing", row = "lib-movies") + @Test fun st096_widestTilePlate() = capture("st-096", person = "mindel", row = "new", column = 4) + @Test fun st100_episodePlate() = capture("st-100", person = "mindel", row = "nu") + @Test fun st099_posterPlate() = capture("st-099", row = "lib-movies", column = 1) + @Test fun st101_unratedEpisode() = capture("st-101", person = "mindel", row = "nu", column = 2) + @Test fun st102_filmTile() = capture("st-102", person = "mindel", row = "new", column = 4) + @Test fun st103_heroRatings() = capture("st-103") + @Test fun xHomeDiscoverStart() = capture("x-home-discover-start", row = "pk-m") +} diff --git a/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/HomeKeysTest.kt b/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/HomeKeysTest.kt new file mode 100644 index 00000000..01c953b8 --- /dev/null +++ b/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/HomeKeysTest.kt @@ -0,0 +1,224 @@ +package org.justinvisser.wolfskin.design + +import android.app.Application +import androidx.activity.ComponentActivity +import androidx.compose.runtime.* +import androidx.compose.ui.input.key.Key +import androidx.compose.ui.test.* +import androidx.compose.ui.test.junit4.createAndroidComposeRule +import org.json.JSONArray +import org.junit.Assert.* +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config + +/** Approved replay data drives the same Android event handling used by the Home surface. */ +@RunWith(RobolectricTestRunner::class) +@Config(sdk = [34], application = Application::class, qualifiers = "w960dp-h540dp-xhdpi") +class HomeKeysTest { + @get:Rule val rule = createAndroidComposeRule() + + @Test fun approvedHomePathsMatchFocusAndCounts() { + val fixture = HomeFixture(rule.activity) + var shell by mutableStateOf(ShellState(fixturePeople(), "justin")) + var action: HomeAction? = null + rule.setContent { WolfskinTheme { + val snapshot = remember(shell, shell.person) { fixture.snapshot(shell.person.key) } + ShellSurface(shell) { modifier -> HomeScreen(shell, snapshot, modifier) { action = it } } + } } + val paths = javaClass.getResourceAsStream("/wolfskin-home-presses.json")!!.bufferedReader().use { JSONArray(it.readText()) } + for (index in 0 until paths.length()) { + val path = paths.getJSONObject(index) + val keys = path.getJSONArray("keys") + rule.runOnIdle { shell = ShellState(fixturePeople(), "justin"); action = null } + for (key in 0 until keys.length()) press(keys.getString(key)) + assertEquals(path.getString("goal"), path.getInt("presses"), keys.length()) + when (index) { + 0 -> { assertEquals("mindel", shell.person.key); assertTrue(action is HomeAction.Play); assertTrue((action as HomeAction.Play).resume) } + 1 -> { assertTrue(action is HomeAction.Play); assertFalse((action as HomeAction.Play).resume); assertEquals("Yu Yu Hakusho", (action as HomeAction.Play).title.seriesTitle) } + 2 -> assertEquals("trending", fixture.snapshot("justin").rows[shell.view.row].id) + 3 -> { val row = fixture.snapshot("justin").rows[shell.view.row]; assertEquals("trending", row.id); assertEquals(row.cards.size, shell.view.cards[row.id]); assertTrue(row.hasSeeAll) } + 4 -> { val row = fixture.snapshot("justin").rows[shell.view.row]; assertEquals("lib-shows", row.id); assertEquals(2, shell.view.cards[row.id]); assertFalse(shell.navFocused) } + 5 -> assertEquals("discover", shell.route) + } + } + } + + @Test fun cardsActivateOnlyOnReleaseAndMovementCancelsArming() { + val shell = ShellState(fixturePeople(), "justin").apply { pickerVisible = false } + val snapshot = HomeFixture(rule.activity).snapshot("justin") + var action: HomeAction? = null + rule.setContent { WolfskinTheme { ShellSurface(shell) { modifier -> HomeScreen(shell, snapshot, modifier) { action = it } } } } + press("DOWN") + rule.onNodeWithTag("wolfskin-shell").performKeyInput { keyDown(Key.DirectionCenter) } + assertNull(action) + rule.onNodeWithTag("wolfskin-shell").performKeyInput { keyUp(Key.DirectionCenter) } + assertTrue(action is HomeAction.Details) + rule.runOnIdle { action = null } + rule.onNodeWithTag("wolfskin-shell").performKeyInput { keyDown(Key.DirectionCenter); pressKey(Key.DirectionRight); keyUp(Key.DirectionCenter) } + assertNull(action) + } + + @Test fun loadingHasNavFocus() { + val shell = ShellState(fixturePeople(), "justin").apply { pickerVisible = false } + val snapshot = HomeFixture(rule.activity).snapshot("justin", "loading") + rule.setContent { WolfskinTheme { ShellSurface(shell) { modifier -> HomeScreen(shell, snapshot, modifier) {} } } } + rule.waitForIdle() + assertTrue(shell.navFocused) + assertEquals(0, shell.navIndex) + } + + @Test fun returningHomeRestoresTheExactViewportAndArrowReentersVisibleContent() { + val shell = ShellState(fixturePeople(), "justin").apply { pickerVisible = false } + val snapshot = HomeFixture(rule.activity).snapshot("justin") + rule.setContent { WolfskinTheme { ShellSurface(shell) { modifier -> + if (shell.route == "home") HomeScreen(shell, snapshot, modifier) {} else ShellPlaceholder(shell.route, modifier) + } } } + rule.onNodeWithTag("wolfskin-home").performScrollToIndex(3) + val view = shell.view + val savedIndex = view.listState.firstVisibleItemIndex + val savedOffset = view.listState.firstVisibleItemScrollOffset + assertEquals(3, savedIndex) + rule.runOnIdle { shell.enterDestination("movies") } + rule.runOnIdle { shell.enterDestination("home") } + rule.waitForIdle() + assertSame(view, shell.view) + assertEquals(savedIndex, view.listState.firstVisibleItemIndex) + assertEquals(savedOffset, view.listState.firstVisibleItemScrollOffset) + press("RIGHT") + assertEquals("lib-movies", snapshot.rows[view.row].id) + assertEquals(0, view.cards["lib-movies"]) + } + + @Test fun pointerHoverMovesFocusWithoutActivatingTheCard() { + val shell = ShellState(fixturePeople(), "justin").apply { pickerVisible = false } + val snapshot = HomeFixture(rule.activity).snapshot("justin") + var action: HomeAction? = null + rule.setContent { WolfskinTheme { ShellSurface(shell) { modifier -> HomeScreen(shell, snapshot, modifier) { action = it } } } } + press("DOWN") + rule.onNodeWithTag("home-card:nu:2").performMouseInput { enter(center) } + rule.waitForIdle() + assertEquals("nu", snapshot.rows[shell.view.row].id) + assertEquals(2, shell.view.cards["nu"]) + assertNull(action) + } + + @Test fun downClampsToShortRowsAndNeverMovesPastTheFinalSeeAll() { + val shell = ShellState(fixturePeople(), "justin").apply { pickerVisible = false; navFocused = false } + val cards = HomeFixture(rule.activity).snapshot("justin").rows.first { it.id == "lib-movies" }.cards + val long = HomeRow(id = "long", kind = HomeRowKind.Shelf, cards = cards) + val short = long.copy(id = "short", cards = cards.take(2), total = 2) + val tail = short.copy(id = "tail", total = 20) + shell.view.cards[long.id] = cards.lastIndex + var action: HomeAction? = null + rule.setContent { WolfskinTheme { + ShellSurface(shell) { modifier -> HomeScreen(shell, HomeSnapshot(listOf(long, short, tail)), modifier) { action = it } } + } } + press("DOWN") + assertEquals(short.id, listOf(long, short, tail)[shell.view.row].id) + assertEquals(1, shell.view.cards[short.id]) + rule.onNodeWithTag("home-card:short:1").assertIsDisplayed() + press("RIGHT") + assertEquals(1, shell.view.cards[short.id]) + press("DOWN") + press("RIGHT") + press("DOWN") + assertEquals(2, shell.view.row) + assertEquals(2, shell.view.cards[tail.id]) + rule.onNodeWithTag("home-card:tail:2").assertIsDisplayed() + press("OK") + assertEquals(tail.id, (action as HomeAction.SeeAll).row.id) + } + + @Test fun mixedWidthRowsUseNearestCenterAndKeepTheTrackWhenMovingBackInsideItsMiddle() { + val shell = ShellState(fixturePeople(), "justin").apply { pickerVisible = false; navFocused = false } + val cards = HomeFixture(rule.activity).snapshot("justin").rows.first { it.id == "lib-movies" }.cards + val posters = HomeRow(id = "posters", kind = HomeRowKind.Shelf, cards = cards) + val tiles = posters.copy(id = "tiles", cardKind = HomeCardKind.Tile) + shell.view.cards[posters.id] = 3 + rule.setContent { WolfskinTheme { + ShellSurface(shell) { modifier -> HomeScreen(shell, HomeSnapshot(listOf(posters, tiles)), modifier) {} } + } } + press("DOWN") + assertEquals("The third tile is nearest the fourth poster's horizontal center", 2, shell.view.cards[tiles.id]) + repeat(4) { press("RIGHT") } + val left = rule.onNodeWithTag("home-card:tiles:4").fetchSemanticsNode().boundsInRoot.left + press("LEFT") + assertEquals("Moving back within the visible middle must not shift the track", left, + rule.onNodeWithTag("home-card:tiles:4").fetchSemanticsNode().boundsInRoot.left, .1f) + press("UP") + assertEquals("A visited row retains its column", 3, shell.view.cards[posters.id]) + } + + @Test fun asynchronousFreshHomePlaysNextInTwoPresses() { + val fixture = HomeFixture(rule.activity) + val shell = ShellState(fixturePeople(), "justin") + val delivery = kotlinx.coroutines.CompletableDeferred() + var action: HomeAction? = null + rule.setContent { + val snapshot by produceState(fixture.snapshot("justin", "loading")) { value = delivery.await() } + WolfskinTheme { ShellSurface(shell) { modifier -> HomeScreen(shell, snapshot, modifier) { action = it } } } + } + press("OK") + rule.waitForIdle() + assertTrue(shell.navFocused) + rule.runOnIdle { delivery.complete(fixture.snapshot("justin")) } + rule.waitForIdle() + assertFalse(shell.navFocused) + assertEquals(0, shell.view.cards["hero"]) + press("OK") + val play = action as HomeAction.Play + assertFalse(play.resume) + assertEquals("Yu Yu Hakusho", play.title.seriesTitle) + } + + @Test fun asynchronousHomeDoesNotStealFocusAfterNavInput() { + val fixture = HomeFixture(rule.activity) + val shell = ShellState(fixturePeople(), "justin") + val delivery = kotlinx.coroutines.CompletableDeferred() + rule.setContent { + val snapshot by produceState(fixture.snapshot("justin", "loading")) { value = delivery.await() } + WolfskinTheme { ShellSurface(shell) { modifier -> HomeScreen(shell, snapshot, modifier) {} } } + } + press("OK") + press("RIGHT") + rule.runOnIdle { delivery.complete(fixture.snapshot("justin")) } + rule.waitForIdle() + assertTrue(shell.navFocused) + assertEquals(1, shell.navIndex) + } + + @Test fun heldOkRepeatEventsDoNotReplayButtonsOrActivateCardsBeforeRelease() { + val shell = ShellState(fixturePeople(), "justin").apply { pickerVisible = false } + val snapshot = HomeFixture(rule.activity).snapshot("justin") + val actions = mutableListOf() + rule.setContent { WolfskinTheme { ShellSurface(shell) { modifier -> HomeScreen(shell, snapshot, modifier) { actions += it } } } } + val input = rule.onNodeWithTag("wolfskin-shell") + fun repeatOk() = rule.runOnIdle { + rule.activity.dispatchKeyEvent(android.view.KeyEvent(0L, 0L, android.view.KeyEvent.ACTION_DOWN, android.view.KeyEvent.KEYCODE_DPAD_CENTER, 3)) + } + input.performKeyInput { keyDown(Key.DirectionCenter) } + repeatOk() + assertEquals(1, actions.size) + assertTrue(actions.single() is HomeAction.Play) + input.performKeyInput { keyUp(Key.DirectionCenter) } + press("DOWN") + input.performKeyInput { keyDown(Key.DirectionCenter) } + repeatOk() + assertEquals(1, actions.size) + input.performKeyInput { keyUp(Key.DirectionCenter) } + assertEquals(2, actions.size) + assertTrue(actions.last() is HomeAction.Details) + } + + private fun press(name: String) { + val key = when (name) { + "UP" -> Key.DirectionUp; "DOWN" -> Key.DirectionDown + "LEFT" -> Key.DirectionLeft; "RIGHT" -> Key.DirectionRight + "BACK" -> Key.Back; else -> Key.DirectionCenter + } + rule.onNodeWithTag("wolfskin-shell").performKeyInput { pressKey(key) } + } +} diff --git a/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/HomeRatingCacheTest.kt b/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/HomeRatingCacheTest.kt new file mode 100644 index 00000000..0a93e74e --- /dev/null +++ b/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/HomeRatingCacheTest.kt @@ -0,0 +1,38 @@ +package org.justinvisser.wolfskin.design + +import java.util.Locale +import org.junit.Assert.* +import org.junit.Test + +/** Cache boundaries protect visible ratings during offline browsing and fast repeated focus. */ +class HomeRatingCacheTest { + private val title = HomeTitle("jellyfin-1", "A film", "movie", tmdbId = 42) + private val ratings = listOf(HomeRating("tmdb", 7.8)) + + @Test fun cacheIsSharedByCatalogueIdentityAndExpiresAtSixHours() { + var now = 0L + val cache = HomeRatingCache { now } + cache.save(title, ratings) + assertEquals(ratings, cache.read(title.copy(id = "another-server-copy"))) + now = 6L * 60 * 60 * 1000 - 1 + assertEquals(ratings, cache.read(title)) + now++ + assertNull(cache.read(title)) + } + + @Test fun cacheKeepsObservedAbsenceAndEvictsOldestBeyondCapacity() { + var now = 0L + val cache = HomeRatingCache { now++ } + cache.save(title, emptyList()) + assertEquals(emptyList(), cache.read(title)) + repeat(300) { index -> cache.save(title.copy(id = "other-$index", tmdbId = index + 100), ratings) } + assertNull(cache.read(title)) + assertEquals(ratings, cache.read(title.copy(id = "last", tmdbId = 399))) + } + + @Test fun decimalScoresFollowLocaleButPercentagesDoNot() { + assertEquals("7,8", ratings.single().format(Locale.forLanguageTag("nl-NL"))) + assertEquals("7.8", ratings.single().format(Locale.US)) + assertEquals("87%", HomeRating("fresh", 87.9, percentage = true).format(Locale.forLanguageTag("nl-NL"))) + } +} diff --git a/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/HomeRatingsUiTest.kt b/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/HomeRatingsUiTest.kt new file mode 100644 index 00000000..664ecba6 --- /dev/null +++ b/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/HomeRatingsUiTest.kt @@ -0,0 +1,67 @@ +package org.justinvisser.wolfskin.design + +import android.app.Application +import androidx.compose.foundation.layout.width +import androidx.compose.ui.Modifier +import androidx.compose.ui.input.key.Key +import androidx.compose.ui.semantics.SemanticsActions +import androidx.compose.ui.test.* +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.text.TextLayoutResult +import java.util.Locale +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue +import org.junit.Assert.assertFalse +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config + +/** Real text layout proves locale formatting and the focus dwell instead of testing copied strings. */ +@RunWith(RobolectricTestRunner::class) +@Config(sdk = [34], application = Application::class, qualifiers = "w960dp-h540dp-xhdpi") +class HomeRatingsUiTest { + @get:Rule val rule = createComposeRule() + + @Test fun dutchDecimalPlateStaysOnOneLine() { + val previous = Locale.getDefault() + Locale.setDefault(Locale.forLanguageTag("nl-NL")) + try { + rule.setContent { WolfskinTheme { HomeRatingPlate(listOf(HomeRating("tmdb", 7.8)), true, Modifier.width(WolfskinTokens.Card.posterW)) } } + val layouts = mutableListOf() + rule.onNodeWithText("7,8").performSemanticsAction(SemanticsActions.GetTextLayoutResult) { it(layouts) } + assertEquals(1, layouts.single().lineCount) + rule.onNodeWithText("7.8").assertDoesNotExist() + } finally { Locale.setDefault(previous) } + } + + @Test fun focusDwellDefersUncachedPlateButCachedFocusReturnsImmediately() { + val shell = ShellState(fixturePeople(), "justin").apply { pickerVisible = false } + val title = HomeTitle("dwell", "A film", "movie", ratings = listOf(HomeRating("tmdb", 7.8))) + val snapshot = HomeSnapshot(listOf(HomeRow("shelf", HomeRowKind.Shelf, "Shelf", listOf(title))), HomeAvailability.Ready) + rule.mainClock.autoAdvance = false + rule.setContent { WolfskinTheme { ShellSurface(shell) { modifier -> HomeScreen(shell, snapshot, modifier) {} } } } + rule.mainClock.advanceTimeBy(100) + rule.onNodeWithText("7.8").assertDoesNotExist() + rule.mainClock.advanceTimeBy(450) + rule.onNodeWithText("7.8").assertExists() + rule.onNodeWithTag("wolfskin-shell").performKeyInput { pressKey(Key.Back) } + rule.runOnIdle { assertTrue(shell.navFocused) } + rule.mainClock.advanceTimeBy(32) + rule.onNodeWithText("7.8").assertDoesNotExist() + rule.onNodeWithTag("wolfskin-shell").performKeyInput { pressKey(Key.DirectionDown) } + rule.runOnIdle { assertFalse(shell.navFocused) } + rule.mainClock.advanceTimeBy(32) + rule.onNodeWithText("7.8").assertExists() + } + + @Test fun signedOutHomeNeverDrawsHeroOrPlateScores() { + val shell = ShellState(fixturePeople(), "justin").apply { pickerVisible = false } + val title = HomeTitle("signed-out", "A film", "movie", ratings = listOf(HomeRating("tmdb", 7.8))) + val rows = buildHomeRows(HomeLibrary(nextUp = listOf(title)), listOf(homeDiscoverState(HomeAvailability.SignedOut))) + rule.setContent { WolfskinTheme { ShellSurface(shell) { modifier -> HomeScreen(shell, HomeSnapshot(rows), modifier) {} } } } + rule.mainClock.advanceTimeBy(1000) + rule.onNodeWithText("7.8").assertDoesNotExist() + } +} diff --git a/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/HomeRowsTest.kt b/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/HomeRowsTest.kt new file mode 100644 index 00000000..9fa7e9a9 --- /dev/null +++ b/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/HomeRowsTest.kt @@ -0,0 +1,50 @@ +package org.justinvisser.wolfskin.design + +import org.junit.Assert.* +import org.junit.Test + +/** Hero precedence and empty/error transitions preserve useful, focusable Home content. */ +class HomeRowsTest { + private val resume = HomeTitle("resume", "Resume", "movie") + private val next = HomeTitle("next", "Next", "episode") + private val newest = HomeTitle("new", "New", "movie") + private val pick = HomeTitle("pick", "Pick", "movie") + private val continuation = listOf(HomeRow("pk-m", HomeRowKind.Shelf, cards = listOf(pick))) + + @Test fun heroChainUsesResumeThenNextThenNewThenPickAndNeverRepeatsHeroOnShelves() { + val cases = listOf( + HomeLibrary(listOf(resume), listOf(next), listOf(newest)) to resume, + HomeLibrary(nextUp = listOf(next), newest = listOf(newest)) to next, + HomeLibrary(newest = listOf(newest)) to newest, + HomeLibrary() to pick, + ) + for ((library, expected) in cases) { + val rows = buildHomeRows(library, continuation) + assertEquals(expected.id, rows.first().cards.single().id) + assertFalse(rows.filter { it.id in setOf("cw", "nu", "new") }.flatMap { it.cards }.any { it.id == expected.id }) + } + } + + @Test fun heldShelvesAreUnwatchedFirstAndSeeAllUsesFullDestinationCount() { + val watched = newest.copy(id = "watched", played = true, addedAt = "2026-11-05") + val older = newest.copy(id = "older", addedAt = "2026-01-01") + val recent = newest.copy(id = "recent", addedAt = "2026-10-01") + val rows = buildHomeRows(HomeLibrary(destinations = mapOf("movies" to listOf(watched, older, recent)), destinationTotals = mapOf("movies" to 84)), continuation) + val shelf = rows.single { it.id == "lib-movies" } + assertEquals(listOf("recent", "older", "watched"), shelf.cards.map { it.id }) + assertEquals(84, shelf.total) + assertTrue(shelf.hasSeeAll) + } + + @Test fun unavailableLibraryKeepsDiscoverAndFocusableRecoveryInsteadOfHeldShelves() { + val rows = buildHomeRows(HomeLibrary(listOf(resume), listOf(next), listOf(newest), mapOf("movies" to listOf(newest))), continuation, libraryAvailable = false) + assertEquals(listOf("hero", "jf-down", "disc-h", "pk-m"), rows.map { it.id }) + assertTrue(rows.single { it.id == "jf-down" }.focusable) + } + + @Test fun firstReadSkeletonHasNoFocusableContent() { + val rows = buildHomeRows(HomeLibrary(), continuation, loading = true) + assertEquals(listOf(HomeRowKind.Hero, HomeRowKind.Shelf, HomeRowKind.Shelf, HomeRowKind.Shelf, HomeRowKind.Shelf), rows.map { it.kind }) + assertTrue(rows.all { !it.focusable }) + } +} diff --git a/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/LibraryCaptureTest.kt b/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/LibraryCaptureTest.kt new file mode 100644 index 00000000..af8387f9 --- /dev/null +++ b/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/LibraryCaptureTest.kt @@ -0,0 +1,89 @@ +package org.justinvisser.wolfskin.design + +import android.app.Application +import android.graphics.BitmapFactory +import android.view.View +import android.view.WindowManager +import androidx.activity.ComponentActivity +import androidx.compose.foundation.layout.requiredSize +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.ImageBitmap +import androidx.compose.ui.graphics.asImageBitmap +import androidx.compose.ui.test.junit4.createAndroidComposeRule +import androidx.compose.ui.test.onRoot +import com.github.takahirom.roborazzi.captureRoboImage +import java.io.File +import java.util.Locale +import org.junit.Before +import org.junit.After +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config +import org.robolectric.annotation.GraphicsMode + +/** Each native screen state uses offline prototype data and real shell focus drawing. */ +@RunWith(RobolectricTestRunner::class) +@Config(sdk = [34], application = Application::class, qualifiers = "w960dp-h540dp-xhdpi") +@GraphicsMode(GraphicsMode.Mode.NATIVE) +class LibraryCaptureTest { + @get:Rule val rule = createAndroidComposeRule() + private val previousLocale = Locale.getDefault() + private val fixture by lazy { libraryFixture() } + + @Before fun fullscreen() { + Locale.setDefault(Locale.US) + rule.activity.window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN) + @Suppress("DEPRECATION") + rule.activity.window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_FULLSCREEN or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY + } + @After fun restoreLocale() { Locale.setDefault(previousLocale) } + + private fun capture(name: String, person: String = "shared", destination: String = "movies", catalogue: String? = null, ratings: Boolean = true, reachable: Boolean = true, cached: Boolean = false, configure: (LibraryGridState) -> Unit = {}) { + val shell = ShellState(fixturePeople(), person).apply { pickerVisible = false; enterDestination(destination) } + val source = when (catalogue) { + "picks" -> fixture.picks(person, "movie") + "trending" -> fixture.trending() + "duplicate" -> fixture.duplicatePage() + else -> fixture.library(person, destination) + } + val grid = LibraryGridState(if (catalogue == "picks") "Movies for you" else if (catalogue != null) "Trending" else destination.replaceFirstChar { it.uppercase() }, source, catalogue != null) + configure(grid) + shell.view.library = grid + rule.setContent { + WolfskinTheme { + ShellSurface(shell, Modifier.requiredSize(WolfskinTokens.Shell.stageWidth, WolfskinTokens.Shell.stageHeight)) { modifier -> + LibraryScreen(shell, grid, modifier, ratingsSignedIn = ratings, ratingsReachable = reachable, + cachedRatings = if (cached) setOf(grid.items[grid.index].id) else emptySet(), offlineArt = ::fixtureArt) + } + } + } + rule.mainClock.advanceTimeBy(1000) + rule.waitForIdle() + val directory = File(System.getProperty("wolfskin.captureDirectory"), "library").apply { mkdirs() } + rule.onRoot().captureRoboImage(File(directory, "$name.png").absolutePath) + } + + @Test fun st021_sharedMovies() = capture("st-021") + @Test fun st022_ratingSort() = capture("st-022") { it.sort = 2 } + @Test fun st023_rowEndClamps() = capture("st-023") { it.index = 5; it.key(ShellKey.Right) } + @Test fun st024_anime() = capture("st-024", "justin", "anime") + @Test fun st025_unwatched() = capture("st-025") { it.unwatched = true } + @Test fun st026_empty() = capture("st-026", "mindel") { it.source = emptyList() } + @Test fun st027_unavailable() = capture("st-027", "mindel", "shows") { it.status = LibraryStatus.Unavailable } + @Test fun st028_loading() = capture("st-028") { it.status = LibraryStatus.Loading } + @Test fun st030_fullPicks() = capture("st-030", "justin", "discover", "picks") + @Test fun st035_duplicateOnlyTail() = capture("st-035", "justin", "discover", "duplicate") { it.tail = GridTail.ShowMore; it.index = it.tailIndex } + @Test fun st039_trending() = capture("st-039", "justin", "discover", "trending") + @Test fun st095_widestPosterPlate() = capture("st-095") { grid -> grid.index = grid.items.indexOfFirst { it.title == "Grave of the Fireflies" } } + @Test fun st097_criticsPlate() = capture("st-097") + @Test fun st098_tmdbPlate() = capture("st-098", "justin", "anime") { grid -> grid.index = grid.items.indexOfFirst { it.title == "Chainsaw Man" } } + @Test fun st112_cachedWhileDown() = capture("st-112", reachable = false, cached = true) + @Test fun st113_uncachedWhileDown() = capture("st-113", reachable = false) + @Test fun unsignedRatingsHidden() = capture("library-unsigned", ratings = false) +} + +fun libraryFixture(): LibraryFixture = LibraryFixture(LibraryCaptureTest::class.java.getResourceAsStream("/wolfskin-library.json")!!.bufferedReader().use { it.readText() }, "/library/") + +fun fixtureArt(path: String): ImageBitmap? = LibraryCaptureTest::class.java.getResourceAsStream(path)?.use { BitmapFactory.decodeStream(it)?.asImageBitmap() } diff --git a/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/LibraryKeysTest.kt b/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/LibraryKeysTest.kt new file mode 100644 index 00000000..b8d27262 --- /dev/null +++ b/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/LibraryKeysTest.kt @@ -0,0 +1,187 @@ +package org.justinvisser.wolfskin.design + +import android.app.Application +import android.view.KeyEvent as AndroidKeyEvent +import androidx.compose.runtime.remember +import androidx.compose.ui.input.key.Key +import androidx.compose.ui.input.key.KeyEvent +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onNodeWithTag +import androidx.compose.ui.test.performKeyInput +import androidx.compose.ui.test.pressKey +import org.json.JSONObject +import org.junit.Assert.* +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config +import java.util.Locale + +/** Acceptance data drives Android keys through the real shell and grid controller. */ +@RunWith(RobolectricTestRunner::class) +@Config(sdk = [34], application = Application::class, qualifiers = "w960dp-h540dp-xhdpi") +class LibraryKeysTest { + @get:Rule val rule = createComposeRule() + private val shell = ShellState(fixturePeople(), "justin") + private val fixture by lazy { libraryFixture() } + private var opened: LibraryTitle? = null + + private fun render() { + rule.setContent { + WolfskinTheme { + ShellSurface(shell) { modifier -> + if (shell.route in listOf("movies", "shows", "anime")) { + val view = shell.view + val grid = remember(shell.person.key, shell.route, view) { + view.library ?: LibraryGridState(shell.route, fixture.library(shell.person.key, shell.route), onTitle = { opened = it }).also { view.library = it } + } + LibraryScreen(shell, grid, modifier, offlineArt = ::fixtureArt) + } else ShellPlaceholder(shell.route, modifier) + } + } + } + } + private fun press(key: Key) { rule.onNodeWithTag("wolfskin-shell").performKeyInput { pressKey(key) }; rule.waitForIdle() } + private fun press(keys: List) { keys.forEach(::press) } + + @Test fun spiritedAwayInApprovedTwentyPresses() { + val document = LibraryKeysTest::class.java.getResourceAsStream("/library-screen.json")!!.bufferedReader().use { JSONObject(it.readText()) } + val paths = document.getJSONArray("pressPaths") + render() + for (index in 0 until paths.length()) { + val path = paths.getJSONObject(index) + val keys = path.getJSONArray("keys") + assertEquals(path.getInt("presses"), keys.length()) + for (keyIndex in 0 until keys.length()) press(when (keys.getString(keyIndex)) { + "UP" -> Key.DirectionUp + "DOWN" -> Key.DirectionDown + "LEFT" -> Key.DirectionLeft + "RIGHT" -> Key.DirectionRight + "OK" -> Key.DirectionCenter + else -> error("Unknown acceptance key") + }) + assertEquals("shared", shell.person.key) + assertEquals("movies", shell.route) + assertFalse(shell.navFocused) + assertEquals("Spirited Away", shell.view.library!!.focusedTitle!!.title) + } + } + + @Test fun rowEdgesToolbarSortAndBackKeepExactCard() { + render() + press(listOf(Key.DirectionRight, Key.DirectionRight, Key.DirectionCenter, Key.DirectionUp, Key.DirectionRight, Key.DirectionRight, Key.DirectionCenter)) + val grid = shell.view.library!! + press(Key.DirectionLeft) + assertEquals(0, grid.index) + repeat(6) { press(Key.DirectionRight) } + assertEquals(5, grid.index) + assertFalse(grid.inRail) + press(listOf(Key.DirectionDown, Key.Back)) + assertTrue(shell.navFocused) + assertEquals(11, grid.index) + press(Key.DirectionDown) + assertEquals(11, grid.index) + press(listOf(Key.DirectionUp, Key.DirectionUp)) + assertTrue(grid.toolbar) + press(Key.DirectionCenter) + assertEquals(1, grid.sort) + assertTrue(grid.toolbar) + press(Key.DirectionCenter) + assertEquals(2, grid.sort) + assertEquals("Grave of the Fireflies", grid.items.first().title) + } + + @Test fun cardActsOnReleaseAndHeldRepeatCannotOpenTwice() { + render() + press(listOf(Key.DirectionCenter, Key.DirectionUp, Key.DirectionRight, Key.DirectionRight, Key.DirectionCenter)) + rule.runOnIdle { + shell.handleKey(KeyEvent(AndroidKeyEvent(0, 0, AndroidKeyEvent.ACTION_DOWN, AndroidKeyEvent.KEYCODE_DPAD_CENTER, 0))) + assertNull(opened) + shell.handleKey(KeyEvent(AndroidKeyEvent(0, 0, AndroidKeyEvent.ACTION_DOWN, AndroidKeyEvent.KEYCODE_DPAD_CENTER, 1))) + assertNull(opened) + shell.handleKey(KeyEvent(AndroidKeyEvent(0, 0, AndroidKeyEvent.ACTION_UP, AndroidKeyEvent.KEYCODE_DPAD_CENTER, 0))) + assertEquals(shell.view.library!!.focusedTitle, opened) + opened = null + shell.handleKey(KeyEvent(AndroidKeyEvent(0, 0, AndroidKeyEvent.ACTION_UP, AndroidKeyEvent.KEYCODE_DPAD_CENTER, 0))) + assertNull(opened) + } + } + + @Test fun railGateJumpAndBackRespectOriginalCard() { + val titles = (0 until 200).map { index -> LibraryTitle("$index", "${('A'.code + index / 10).toChar()}Title $index", "movie") } + val grid = LibraryGridState("Movies", titles) + assertTrue(grid.railVisible) + grid.index = 5 + grid.key(ShellKey.Right) + assertTrue(grid.inRail) + grid.key(ShellKey.Down) + assertEquals('B', grid.railLetter) + grid.key(ShellKey.Back) + assertEquals(5, grid.index) + assertFalse(grid.inRail) + grid.key(ShellKey.Right); grid.key(ShellKey.Down); grid.key(ShellKey.Ok) + assertEquals('B', grid.focusedTitle!!.letter) + grid.source = titles.take(199) + assertFalse(grid.railVisible) + grid.source = titles; grid.sort = 1 + assertFalse(grid.railVisible) + } + + @Test fun mixedSeeAllPreservesFullListAndClampsShortRow() { + val grid = LibraryGridState("Full list", (0 until 8).map { LibraryTitle("$it", "Title $it", if (it % 2 == 0) "movie" else "tv") }, catalogue = true) + grid.index = 5 + grid.key(ShellKey.Down) + assertEquals(7, grid.index) + grid.key(ShellKey.Up); grid.key(ShellKey.Up) + assertTrue(grid.toolbar) + grid.key(ShellKey.Right); grid.key(ShellKey.Ok) + assertEquals(listOf("0", "2", "4", "6"), grid.items.map { it.id }) + grid.key(ShellKey.Left); grid.key(ShellKey.Ok) + assertEquals(8, grid.items.size) + } + + @Test fun downClampsShortLastRowBeforeEnteringRecoveryTail() { + var recoveries = 0 + val grid = LibraryGridState("Trending", + (0 until 20).map { LibraryTitle("$it", "Title $it", "movie") }, + catalogue = true, onRecover = { recoveries++ }, + ).apply { tail = GridTail.Retry; index = 14 } + shell.pickerVisible = false + shell.enterDestination("discover") + rule.setContent { + WolfskinTheme { + ShellSurface(shell) { modifier -> + LibraryScreen(shell, grid, modifier) + } + } + } + press(Key.DirectionDown) + assertEquals(19, grid.index) + assertEquals("Title 19", grid.focusedTitle!!.title) + assertEquals(0, recoveries) + press(Key.DirectionDown) + assertEquals(24, grid.index) + assertEquals("grid-tail", grid.cardKey) + press(Key.DirectionDown) + assertEquals(24, grid.index) + press(Key.DirectionCenter) + assertEquals(1, recoveries) + press(Key.DirectionUp) + assertEquals(18, grid.index) + assertEquals("Title 18", grid.focusedTitle!!.title) + } + + @Test fun scoresFollowLocaleAndUnratedSortsLast() { + assertEquals("7,8", LibraryRating("tmdb", 7.8).formatted(Locale.forLanguageTag("nl-NL"))) + assertEquals("7.8", LibraryRating("tmdb", 7.8).formatted(Locale.US)) + assertEquals("87%", LibraryRating("rtCritics", 87.9).formatted(Locale.forLanguageTag("nl-NL"))) + val grid = LibraryGridState("Movies", listOf( + LibraryTitle("none", "The Apple", "movie"), + LibraryTitle("imdb", "A Bee", "movie", ratings = listOf(LibraryRating("imdb", 8.0))), + LibraryTitle("rt", "An Ant", "movie", ratings = listOf(LibraryRating("rtCritics", 80.0))), + )) + grid.sort = 2 + assertEquals(listOf("rt", "imdb", "none"), grid.items.map { it.id }) + } +} diff --git a/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/LibraryPaginationTest.kt b/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/LibraryPaginationTest.kt new file mode 100644 index 00000000..6b0e41ba --- /dev/null +++ b/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/LibraryPaginationTest.kt @@ -0,0 +1,55 @@ +package org.justinvisser.wolfskin.design + +import kotlinx.coroutines.runBlocking +import org.junit.Assert.* +import org.junit.Test + +/** Paging never loops through repeated pages or loses the readable list after a failure. */ +class LibraryPaginationTest { + private fun title(id: Int) = LibraryTitle("$id", "Title $id", "movie") + + @Test fun duplicateOnlyReadWaitsForExplicitRetryThenAppendsUniqueTitles() = runBlocking { + val grid = LibraryGridState("Trending", (0 until 20).map(::title), catalogue = true) + var calls = 0 + val pager = LibraryPagination(grid) { page -> + calls++ + when (page) { + 2 -> LibraryPage((0 until 20).map(::title), true) + 3 -> LibraryPage((18 until 25).map(::title), false) + else -> error("Unexpected extra read") + } + } + grid.index = 9 + pager.readAhead() + assertEquals(0, calls) + grid.index = 10 + pager.readAhead() + assertEquals(GridTail.ShowMore, grid.tail) + pager.readAhead() + assertEquals(1, calls) + pager.readAhead(force = true) + assertEquals((0 until 25).map { "$it" }, grid.source.map { it.id }) + assertEquals(GridTail.None, grid.tail) + pager.readAhead(force = true) + assertEquals(2, calls) + } + + @Test fun failedReadRetainsTitlesAndRetriesSamePage() = runBlocking { + val grid = LibraryGridState("Trending", (0 until 12).map(::title), catalogue = true) + var reachable = false + val pages = mutableListOf() + val pager = LibraryPagination(grid) { page -> + pages += page + if (!reachable) throw java.io.IOException("offline") + LibraryPage(listOf(title(12)), false) + } + grid.index = 11 + pager.readAhead() + assertEquals(GridTail.Retry, grid.tail) + assertEquals((0 until 12).map { "$it" }, grid.source.map { it.id }) + reachable = true + pager.readAhead(force = true) + assertEquals(listOf(2, 2), pages) + assertEquals("12", grid.source.last().id) + } +} diff --git a/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/NavSpringTest.kt b/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/NavSpringTest.kt new file mode 100644 index 00000000..07dec9a8 --- /dev/null +++ b/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/NavSpringTest.kt @@ -0,0 +1,38 @@ +package org.justinvisser.wolfskin.design + +import androidx.compose.animation.core.TargetBasedAnimation +import androidx.compose.animation.core.VectorConverter +import androidx.compose.animation.core.spring +import java.io.File +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue +import org.junit.Test + +/** Sample the shipped Compose spring, not a separately approximated motion function. */ +class NavSpringTest { + @Test + fun criticallyDampedBlobMatchesLockedCurveWithoutOvershoot() { + val animation = TargetBasedAnimation( + animationSpec = spring(WolfskinTokens.Motion.navBlobDampingRatio, WolfskinTokens.Motion.navBlobStiffness), + typeConverter = Float.VectorConverter, + initialValue = 478f, + targetValue = 688f, + ) + val times = listOf(50, 99, 150, 200) + val expected = listOf(554.5f, 628.7f, 665.9f, 680.2f) + val values = times.map { animation.getValueFromNanos(it * 1_000_000L) } + values.zip(expected).forEach { (actual, target) -> assertEquals(target, actual, .2f) } + assertTrue((values[1] - 478) / 210 in .55f.. .8f) + assertEquals(688f, animation.getValueFromNanos(300_000_000), 1f) + var previous = 478f + for (millisecond in 0..1000) { + val value = animation.getValueFromNanos(millisecond * 1_000_000L) + assertTrue("Spring reversed at $millisecond ms", value >= previous) + assertTrue("Spring overshot at $millisecond ms", value <= 688f) + previous = value + } + val directory = File(System.getProperty("wolfskin.captureDirectory")) + directory.mkdirs() + File(directory, "nav-spring.json").writeText(times.zip(values).joinToString(prefix = "[", postfix = "]") { (time, value) -> "{\"ms\":$time,\"x\":$value}" }) + } +} diff --git a/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/RecoveryCaptureTest.kt b/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/RecoveryCaptureTest.kt new file mode 100644 index 00000000..f61d97e1 --- /dev/null +++ b/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/RecoveryCaptureTest.kt @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: GPL-2.0-only +package org.justinvisser.wolfskin.design + +import android.app.Application +import android.view.View +import android.view.WindowManager +import androidx.activity.ComponentActivity +import androidx.compose.foundation.layout.requiredSize +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.input.key.Key +import androidx.compose.ui.semantics.SemanticsActions +import androidx.compose.ui.test.* +import androidx.compose.ui.test.junit4.createAndroidComposeRule +import androidx.compose.ui.text.TextLayoutResult +import com.github.takahirom.roborazzi.captureRoboImage +import java.io.File +import java.util.Locale +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import org.json.JSONArray +import org.json.JSONObject +import org.junit.Assert.* +import org.junit.Before +import org.junit.After +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config +import org.robolectric.annotation.GraphicsMode + +/** Native state proof uses only packaged fixtures and records the actual text/font/layout surface. */ +@RunWith(RobolectricTestRunner::class) +@Config(sdk = [34], application = Application::class, qualifiers = "w960dp-h540dp-xhdpi") +@GraphicsMode(GraphicsMode.Mode.NATIVE) +class RecoveryCaptureTest { + @get:Rule val rule = createAndroidComposeRule() + private val previousLocale = Locale.getDefault() + + @Before fun fullscreen() { + Locale.setDefault(Locale.US) + rule.activity.window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN) + @Suppress("DEPRECATION") + rule.activity.window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_FULLSCREEN or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY + } + @After fun restoreLocale() { Locale.setDefault(previousLocale) } + + private fun shell(route: String = "home") = ShellState(fixturePeople(), "mindel").apply { pickerVisible = false; enterDestination(route) } + + private fun mount(shell: ShellState, overlay: @Composable () -> Unit = {}, content: @Composable (Modifier) -> Unit) { + rule.setContent { WolfskinTheme { + ShellSurface(shell, Modifier.requiredSize(WolfskinTokens.Shell.stageWidth, WolfskinTokens.Shell.stageHeight), overlay = overlay, content = content) + } } + rule.mainClock.advanceTimeBy(1000) + rule.waitForIdle() + } + + private fun capture(name: String) { + val directory = File(System.getProperty("wolfskin.captureDirectory"), "recovery").apply { mkdirs() } + rule.onRoot().captureRoboImage(File(directory, "$name.png").absolutePath) + val text = JSONArray() + val forbidden = Regex("Recs Movies|Recs Shows|DGiC|(?:Justin|Mindel|Shared) (?:Movies|Shows)|(?:Next|Previous) page|Page [0-9]") + rule.onAllNodes(SemanticsMatcher.keyIsDefined(SemanticsActions.GetTextLayoutResult), useUnmergedTree = true).fetchSemanticsNodes().forEach { node -> + val layouts = mutableListOf() + node.config[SemanticsActions.GetTextLayoutResult].action?.invoke(layouts) + layouts.forEach { layout -> + val words = layout.layoutInput.text.text + val style = layout.layoutInput.style + assertTrue("Text smaller than 12sp: $words", style.fontSize.value >= 12f) + assertFalse("Internal wording: $words", forbidden.containsMatchIn(words)) + text.put(JSONObject().put("text", words).put("fontSizeSp", style.fontSize.value).put("weight", style.fontWeight?.weight) + .put("lineCount", layout.lineCount).put("lineHeightSp", style.lineHeight.value.takeIf { it.isFinite() } ?: JSONObject.NULL) + .put("left", node.boundsInRoot.left).put("top", node.boundsInRoot.top).put("width", node.boundsInRoot.width).put("height", node.boundsInRoot.height)) + } + } + File(directory, "$name-layout.json").writeText(text.toString(2)) + } + + @Test fun st090_offlinePlayToastRetainsHomeAndFocusedResume() { + val shell = shell() + val snapshot = HomeFixture(rule.activity).snapshot("mindel", "offline") + shell.toast = RecoveryMessage.PlaybackUnavailable + mount(shell) { HomeScreen(shell, snapshot, it) {} } + rule.onNodeWithText(RecoveryMessage.PlaybackUnavailable).assertIsDisplayed() + rule.onNodeWithText("Resume S4 E9").assertIsDisplayed() + assertFalse(shell.navFocused) + val toast = rule.onNodeWithTag("recovery-toast").fetchSemanticsNode().boundsInRoot + val message = rule.onNodeWithText(RecoveryMessage.PlaybackUnavailable).fetchSemanticsNode().boundsInRoot + assertEquals(1064f, toast.left, 1f) + assertEquals(150f, toast.top, 1f) + assertEquals(760f, toast.width, 1f) + assertEquals(1136f, message.left, 1f) + capture("st-090") + } + + @Test fun savedLibraryHasNavAndHeaderChipAndAReachableRetryTail() { + var retried = false + val shell = shell("movies") + val grid = LibraryGridState("Movies", listOf(LibraryTitle("saved", "A saved film", "movie")), onRecover = { retried = true }).apply { + savedAt = "20:42"; tail = GridTail.Retry + } + mount(shell) { LibraryScreen(shell, grid, it) } + assertEquals(2, rule.onAllNodesWithText("Saved 20:42").fetchSemanticsNodes().size) + rule.onNodeWithTag("wolfskin-shell").performKeyInput { pressKey(Key.DirectionDown); pressKey(Key.DirectionCenter) } + assertTrue(retried) + capture("library-saved") + } + + @Test fun libraryWithoutSavedDataOffersRecovery() { + var retried = false + val shell = shell("shows") + val grid = LibraryGridState("Shows", emptyList(), onRecover = { retried = true }).apply { status = LibraryStatus.Unavailable } + mount(shell) { LibraryScreen(shell, grid, it) } + rule.onNodeWithText("Try again").assertIsDisplayed() + rule.onNodeWithTag("wolfskin-shell").performKeyInput { pressKey(Key.DirectionCenter) } + assertTrue(retried) + capture("library-unavailable") + } + + @Test fun savedDiscoverKeepsHeroAndRecoveryWithoutAllowingRequests() { + val shell = shell("discover") + val snapshot = discoverTestFixture().snapshot("mindel").copy(savedAt = "20:42") + val state = DiscoverState(shell, snapshot, RecordingDiscoverOperations(DiscoverSnapshot(status = DiscoverStatus.Unavailable), "Mindel"), CoroutineScope(Dispatchers.Main.immediate)) + mount(shell, overlay = { DiscoverOverlay(state) }) { DiscoverScreen(state, it) } + rule.onNodeWithText("Saved 20:42").assertIsDisplayed() + assertTrue(state.hasHero) + assertFalse(state.canRequest) + rule.runOnIdle { state.focus(state.rowCount - 1) } + rule.mainClock.advanceTimeBy(1000) + rule.onNodeWithText("More titles couldnโ€™t load").assertIsDisplayed() + capture("discover-saved") + } + + @Test fun unavailableDiscoverRetryShowsExactFailureToast() { + val shell = shell("discover") + val snapshot = DiscoverSnapshot(status = DiscoverStatus.Unavailable) + val state = DiscoverState(shell, snapshot, RecordingDiscoverOperations(snapshot, "Mindel"), CoroutineScope(Dispatchers.Main.immediate)) + mount(shell, overlay = { DiscoverOverlay(state) }) { DiscoverScreen(state, it) } + rule.onNodeWithTag("wolfskin-shell").performKeyInput { pressKey(Key.DirectionCenter) } + rule.onNodeWithText(RecoveryMessage.StillUnreachable).assertIsDisplayed() + capture("discover-unavailable-retry") + } + + @Test fun savedRequestsKeepTheirRowsAndRecoveryAfterFailure() { + val shell = shell("settings") + val item = ComingInRequest("saved", "movie", 1, "A saved request", "mindel", "Mindel", "shared", "Shared", ComingInStage.Waiting) + shell.requests.update(ComingInSnapshot(listOf(item), ComingInStatus.Ready, signedIn = true, savedAt = "20:42")) + shell.requests.update(ComingInSnapshot(status = ComingInStatus.Unavailable, signedIn = true)) + shell.openRequests() + mount(shell) { SettingsList(shell, it) } + rule.onNodeWithText("A saved request").assertIsDisplayed() + rule.onNodeWithText("Try again").assertIsDisplayed() + rule.onNodeWithTag("wolfskin-shell").performKeyInput { pressKey(Key.DirectionDown) } + assertTrue(shell.requests.recoveryFocused) + capture("requests-saved") + } + + @Test fun failedPosterReadUsesTheSameMissingArtFallbackAsHome() { + val title = LibraryTitle("missing", "A missing film", "movie", poster = "file:///missing-offline-poster.jpg") + mount(shell("movies")) { LibraryScreen(shell("movies"), LibraryGridState("Movies", listOf(title)), it) } + rule.waitUntil(5000) { rule.onAllNodesWithText(title.title).fetchSemanticsNodes().size >= 2 } + capture("library-missing-art") + } + + @Test fun dutchLibraryScoreRendersCommaWithoutBreakingThePlate() { + Locale.setDefault(Locale.forLanguageTag("nl-NL")) + val title = LibraryTitle("dutch", "A film", "movie", ratings = listOf(LibraryRating("tmdb", 7.8))) + val shell = shell("movies") + mount(shell) { LibraryScreen(shell, LibraryGridState("Movies", listOf(title)), it, ratingsSignedIn = true) } + rule.onNodeWithText("7,8").assertIsDisplayed() + capture("library-dutch-score") + } + + @Config(qualifiers = "nl-rNL-w960dp-h540dp-xhdpi") + @Test fun dutchDiscoverHeroScoreRendersComma() { + Locale.setDefault(Locale.forLanguageTag("nl-NL")) + val title = DiscoverTitle(1, "movie", "A film", ratings = listOf(DiscoverRating("tmdb", 7.8))) + val snapshot = DiscoverSnapshot(picks = listOf(title), status = DiscoverStatus.Ready) + val shell = shell("discover") + val state = DiscoverState(shell, snapshot, RecordingDiscoverOperations(snapshot, "Mindel"), CoroutineScope(Dispatchers.Main.immediate)) + mount(shell) { DiscoverScreen(state, it) } + rule.onNodeWithText("7,8").assertIsDisplayed() + capture("discover-dutch-score") + } + + @Test fun failedDiscoverBackdropUsesTheSharedAmbientFallback() { + val shell = shell("discover") + val title = DiscoverTitle(1, "movie", "A film", backdrop = "file:///missing-offline-backdrop.jpg") + val snapshot = DiscoverSnapshot(picks = listOf(title), status = DiscoverStatus.Ready) + val state = DiscoverState(shell, snapshot, RecordingDiscoverOperations(snapshot, "Mindel"), CoroutineScope(Dispatchers.Main.immediate)) + mount(shell) { DiscoverScreen(state, it) } + rule.waitUntil(5000) { rule.onAllNodesWithTag("discover-missing-art").fetchSemanticsNodes().isNotEmpty() } + rule.onNodeWithTag("discover-missing-art").assertIsDisplayed() + capture("discover-missing-art") + } +} diff --git a/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/RecoveryStateTest.kt b/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/RecoveryStateTest.kt new file mode 100644 index 00000000..d0a98595 --- /dev/null +++ b/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/RecoveryStateTest.kt @@ -0,0 +1,117 @@ +// SPDX-License-Identifier: GPL-2.0-only +package org.justinvisser.wolfskin.design + +import android.app.Application +import kotlinx.coroutines.test.runTest +import org.junit.Assert.* +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config + +/** Failed refresh, loading focus and identity changes must never discard or leak a saved view. */ +@RunWith(RobolectricTestRunner::class) +@Config(sdk = [34], application = Application::class) +class RecoveryStateTest { + @Test fun failedDiscoverRefreshKeepsTitlesAndFocusButDisablesWritesUntilRecovery() = runTest { + val title = DiscoverTitle(1, "movie", "Saved film") + val initial = DiscoverSnapshot(picks = listOf(title), status = DiscoverStatus.Ready) + var response = DiscoverSnapshot(status = DiscoverStatus.Unavailable) + var writes = 0 + val operations = object : DiscoverOperations { + override suspend fun refresh() = response + override suspend fun request(intent: DiscoverRequest): DiscoverRequestResult { writes++; return DiscoverRequestResult(RequestPhase.Receipt) } + override suspend fun check(intent: DiscoverRequest) = DiscoverRequestResult(RequestPhase.NotConfirmed) + override suspend fun hide(profile: String, title: DiscoverTitle): Boolean { writes++; return true } + override suspend fun restore(profile: String, title: DiscoverTitle): Boolean { writes++; return true } + } + val shell = ShellState(fixturePeople(), "justin").apply { pickerVisible = false; enterDestination("discover") } + val state = DiscoverState(shell, initial, operations, backgroundScope, nowMillis = { 1000L }) + state.focus(0) + state.refresh() + testScheduler.runCurrent() + assertEquals(listOf(title), state.heroes) + assertEquals(0, state.focusedRow) + assertNotNull(state.snapshot.savedAt) + assertFalse(state.canRequest) + assertEquals(RecoveryMessage.StillUnreachable, state.toast) + state.hide(title) + testScheduler.runCurrent() + assertEquals(0, writes) + val recovery = state.lanes.last() + state.focus(state.lanes.indexOf(recovery) + state.firstShelf) + assertEquals(DiscoverTail.Retry, state.focusedLane?.tail) + response = initial + state.key(ShellKey.Ok) + testScheduler.runCurrent() + assertTrue(state.canRequest) + assertNull(state.snapshot.savedAt) + assertNull(state.toast) + } + + @Test fun revokedDiscoverIdentityDropsSavedTitlesInsteadOfPaintingThemWhileSignedOut() = runTest { + val initial = discoverTestFixture().snapshot("justin") + val operations = RecordingDiscoverOperations(DiscoverSnapshot(status = DiscoverStatus.NeedsSignIn), "Justin") + val state = DiscoverState(ShellState(fixturePeople(), "justin"), initial, operations, backgroundScope) + state.refresh() + testScheduler.runCurrent() + assertFalse(state.isSignedIn) + assertTrue(state.heroes.isEmpty()) + assertTrue(state.lanes.isEmpty()) + } + + @Test fun DownCannotLeaveNavForSkeletonOnlyHomeLibraryOrDiscover() = runTest { + val shell = ShellState(fixturePeople(), "justin").apply { pickerVisible = false } + val loading = LibraryGridState("Movies", emptyList()).apply { status = LibraryStatus.Loading } + val home = HomeFocus(shell, buildHomeRows(HomeLibrary(), emptyList(), loading = true)) {} + val discover = DiscoverState(shell, DiscoverSnapshot(status = DiscoverStatus.Loading), RecordingDiscoverOperations(DiscoverSnapshot(), "Justin"), backgroundScope) + for (content in listOf(loading, home, discover)) { + shell.contentFocus = content + shell.focusNav(shell.currentTab) + shell.key(ShellKey.Down) + assertTrue("Skeleton-only content must retain nav focus", shell.navFocused) + } + loading.status = LibraryStatus.Unavailable + shell.contentFocus = loading + shell.key(ShellKey.Down) + assertFalse("A recovery button is reachable once loading fails", shell.navFocused) + } + + @Test fun requestsKeepSavedRowsOnFailureAndRecoveryNeverOpensTheLastTitle() { + var retried = false + var opened = false + val shell = ShellState(fixturePeople(), "justin") { + if (it == ShellAction.RetryRequests) retried = true + if (it is ShellAction.RequestTitle) opened = true + }.apply { pickerVisible = false; enterDestination("settings") } + val request = ComingInRequest("a", "movie", 1, "Saved film", "justin", "Justin", "justin", "Justin", ComingInStage.Waiting) + shell.requests.update(ComingInSnapshot(listOf(request), ComingInStatus.Ready, signedIn = true, savedAt = "20:42")) + shell.requests.update(ComingInSnapshot(status = ComingInStatus.Unavailable, signedIn = true)) + shell.openRequests() + assertEquals(listOf(request), shell.requests.snapshot.items) + assertEquals("20:42", shell.navSavedAt) + shell.key(ShellKey.Down) + assertTrue(shell.requests.recoveryFocused) + shell.key(ShellKey.Ok) + assertTrue(retried) + assertFalse(opened) + shell.key(ShellKey.Up) + assertFalse(shell.requests.recoveryFocused) + shell.key(ShellKey.Back) + assertFalse(shell.requestsVisible) + } + + @Test fun switchingPeopleNeverShowsAnotherPersonsCachedRequestsOrSavedChip() { + val shell = ShellState(fixturePeople(), "justin") + val item = ComingInRequest("private", "movie", 1, "Person A film", "justin", "Justin", "justin", "Justin", ComingInStage.Waiting) + shell.requests.update(ComingInSnapshot(listOf(item), ComingInStatus.Ready, signedIn = true, savedAt = "20:42")) + val original = shell.requests + shell.pickerIndex = 1 + shell.key(ShellKey.Ok) + shell.openRequests() + assertEquals("mindel", shell.person.key) + assertTrue(shell.requests.snapshot.items.isEmpty()) + assertNull(shell.navSavedAt) + assertNotSame(original, shell.requests) + } +} diff --git a/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/RequestsCaptureTest.kt b/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/RequestsCaptureTest.kt new file mode 100644 index 00000000..7f114a64 --- /dev/null +++ b/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/RequestsCaptureTest.kt @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: GPL-2.0-only +package org.justinvisser.wolfskin.design + +import android.app.Application +import android.view.View +import android.view.WindowManager +import androidx.activity.ComponentActivity +import androidx.compose.foundation.layout.requiredSize +import androidx.compose.ui.Modifier +import androidx.compose.ui.test.junit4.createAndroidComposeRule +import androidx.compose.ui.test.onRoot +import com.github.takahirom.roborazzi.captureRoboImage +import java.io.File +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config +import org.robolectric.annotation.GraphicsMode + +/** Every approved Requests state uses the actual shell overlay at native television density. */ +@RunWith(RobolectricTestRunner::class) +@Config(sdk = [34], application = Application::class, qualifiers = "w960dp-h540dp-xhdpi") +@GraphicsMode(GraphicsMode.Mode.NATIVE) +class RequestsCaptureTest { + @get:Rule val rule = createAndroidComposeRule() + + @Before fun fullscreen() { + rule.activity.window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN) + @Suppress("DEPRECATION") + rule.activity.window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_FULLSCREEN or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY + } + + private fun capture(name: String, snapshot: ComingInSnapshot, person: String = "justin", expanded: Boolean = false) { + val state = ShellState(fixturePeople(), person) + state.pickerVisible = false + state.enterDestination("settings") + state.requests.update(snapshot) + state.openRequests() + if (expanded) { state.requests.key(ShellKey.Down); state.requests.key(ShellKey.Right) } + rule.setContent { + WolfskinTheme { ShellSurface(state, Modifier.requiredSize(WolfskinTokens.Shell.stageWidth, WolfskinTokens.Shell.stageHeight)) } + } + rule.mainClock.advanceTimeBy(1000) + rule.waitForIdle() + val directory = File(System.getProperty("wolfskin.captureDirectory")) + directory.mkdirs() + rule.onRoot().captureRoboImage(File(directory, "$name.png").absolutePath) + } + + @Test fun st081_empty() = capture("st-081", ComingInSnapshot(status = ComingInStatus.Ready, signedIn = true)) + @Test fun st082_stages() = capture("st-082", requestsFixture()) + @Test fun st083_unavailable() = capture("st-083", ComingInSnapshot()) + @Test fun st084_loading() = capture("st-084", ComingInSnapshot(status = ComingInStatus.Loading)) + @Test fun st085_partial() = capture("st-085", requestsFixture().copy(items = requestsFixture().items.take(3), partial = true)) + @Test fun st086_readiness() = capture("st-086", requestsFixture(), expanded = true) + @Test fun st088_sharedActor() = capture("st-088", requestsFixture(shared = true), person = "shared") + @Test fun st111_focusedRatings() = capture("st-111", requestsFixture(ratings = true)) +} + +/** Shared actor and stage fixtures are projections, never network calls or synthetic UI redraws. */ +fun requestsFixture(shared: Boolean = false, ratings: Boolean = false): ComingInSnapshot { + val source = RequestsCaptureTest::class.java.getResourceAsStream("/wolfskin-requests.json")!!.bufferedReader().use { it.readText() } + val items = readComingInFixture(source) { name -> + RequestsCaptureTest::class.java.getResourceAsStream("/wolfskin-requests/$name")!!.use { it.readBytes() } + } + val selected = when { shared -> items.filter { it.id == "x7" }; ratings -> items.filter { it.id == "x8" }; else -> items.take(6) } + return ComingInSnapshot(selected, ComingInStatus.Ready, signedIn = true) +} diff --git a/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/RequestsKeysTest.kt b/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/RequestsKeysTest.kt new file mode 100644 index 00000000..780a6575 --- /dev/null +++ b/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/RequestsKeysTest.kt @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: GPL-2.0-only +package org.justinvisser.wolfskin.design + +import android.app.Application +import androidx.compose.ui.input.key.Key +import androidx.compose.ui.test.* +import androidx.compose.ui.test.junit4.createComposeRule +import java.util.Locale +import org.json.JSONArray +import org.junit.Assert.* +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config + +/** Key replays exercise real shell handling, including trapped overlays and title-return memory. */ +@RunWith(RobolectricTestRunner::class) +@Config(sdk = [34], application = Application::class, qualifiers = "w960dp-h540dp-xhdpi") +class RequestsKeysTest { + @get:Rule val rule = createComposeRule() + + private fun mount(state: ShellState) { + rule.setContent { WolfskinTheme { ShellSurface(state) } } + rule.mainClock.advanceTimeByFrame() + } + + private fun send(first: Key, second: Key? = null, third: Key? = null, fourth: Key? = null) { + listOfNotNull(first, second, third, fourth).forEach { key -> + rule.onNodeWithTag("wolfskin-shell").performKeyInput { pressKey(key) } + rule.mainClock.advanceTimeByFrame() + } + } + + private fun sheet(snapshot: ComingInSnapshot = requestsFixture(), actions: (ShellAction) -> Unit = {}): ShellState = + ShellState(fixturePeople(), "justin", actions).apply { + pickerVisible = false + enterDestination("settings") + requests.update(snapshot) + openRequests() + } + + @Test fun approvedNinePressPathUsesRealShellFocus() { + val paths = RequestsKeysTest::class.java.getResourceAsStream("/requests-press-paths.json")!!.bufferedReader().use { JSONArray(it.readText()) } + val keys = mapOf("OK" to Key.DirectionCenter, "UP" to Key.DirectionUp, "LEFT" to Key.DirectionLeft, + "RIGHT" to Key.DirectionRight, "DOWN" to Key.DirectionDown) + val state = ShellState(fixturePeople(), "justin") + state.requests.update(requestsFixture()) + mount(state) + val path = paths.getJSONObject(0) + val presses = path.getJSONArray("keys") + assertEquals(9, path.getInt("presses")) + assertEquals(path.getInt("presses"), presses.length()) + for (index in 0 until presses.length()) send(keys.getValue(presses.getString(index))) + rule.onNodeWithTag("coming-in").assertExists() + rule.onNodeWithText("Requests ยท 5 open").assertExists() + assertEquals("settings", state.route) + assertEquals("x5", state.requests.focusedId) + assertFalse(state.navFocused) + } + + @Test fun readinessWindowAndTitleRoundTripPreserveRequest() { + lateinit var state: ShellState + state = sheet { action -> if (action is ShellAction.RequestTitle) state.enterDestination("title/${action.request.mediaType}:${action.request.tmdbId}") } + mount(state) + send(Key.DirectionDown, Key.DirectionRight) + rule.onNodeWithText("Download ยท Downloading").assertExists() + assertEquals(4, state.requests.windowSize) + assertEquals("x1", state.requests.focusedId) + send(Key.DirectionLeft) + rule.onNodeWithText("Download ยท Downloading").assertDoesNotExist() + send(Key.DirectionDown, Key.DirectionDown, Key.DirectionDown, Key.DirectionDown) + assertEquals("x6", state.requests.focusedId) + assertEquals(1, state.requests.windowStart) + send(Key.DirectionDown) + assertEquals("x6", state.requests.focusedId) + send(Key.DirectionCenter) + assertFalse(state.requestsVisible) + assertTrue(state.route.startsWith("title/")) + send(Key.Back) + rule.onNodeWithTag("coming-row-x6").assertExists() + assertEquals("x6", state.requests.focusedId) + assertTrue(state.requestsVisible) + send(Key.Back) + assertFalse(state.requestsVisible) + assertEquals("settings", state.route) + assertEquals(0, state.settingsRow) + } + + @Test fun emptyAndLoadingTrapDirectionsWhileUnavailableRetries() { + var retries = 0 + val state = sheet(ComingInSnapshot(status = ComingInStatus.Loading)) { if (it == ShellAction.RetryRequests) retries++ } + mount(state) + send(Key.DirectionUp, Key.DirectionLeft) + assertFalse(state.navFocused) + assertTrue(state.requestsVisible) + send(Key.DirectionCenter) + assertFalse(state.requestsVisible) + rule.runOnIdle { state.requests.update(ComingInSnapshot()); state.openRequests() } + send(Key.DirectionCenter) + assertEquals(1, retries) + assertTrue(state.requestsVisible) + rule.runOnIdle { state.requests.update(ComingInSnapshot(status = ComingInStatus.Ready)) } + send(Key.DirectionDown, Key.DirectionCenter) + rule.onNodeWithText("Nothing coming in.").assertExists() + assertTrue(state.requestsVisible) + } + + @Test fun cachedRatingsRenderInTheTelevisionLocale() { + val original = Locale.getDefault() + try { + Locale.setDefault(Locale.forLanguageTag("nl-NL")) + val state = sheet(requestsFixture(ratings = true)) + kotlinx.coroutines.test.runTest { state.requests.awaitFocusedRatings() } + mount(state) + rule.onNodeWithText("7,6").assertExists() + rule.onNodeWithText("87%").assertExists() + rule.runOnIdle { state.requests.update(state.requests.snapshot.copy(signedIn = false)) } + rule.onNodeWithText("7,6").assertDoesNotExist() + rule.onNodeWithText("87%").assertDoesNotExist() + } finally { Locale.setDefault(original) } + } + + @Test fun selectingARootAfterARequestTitleDiscardsTheSheetReturnLink() { + lateinit var state: ShellState + state = sheet { action -> if (action is ShellAction.RequestTitle) state.enterDestination("title/${action.request.mediaType}:${action.request.tmdbId}") } + mount(state) + send(Key.DirectionCenter, Key.DirectionUp, Key.DirectionCenter) + assertEquals("home", state.route) + send(Key.Back) + assertFalse("Root Back must focus navigation, not reopen the abandoned sheet", state.requestsVisible) + assertTrue(state.navFocused) + } + + @Test fun refreshKeepsStableFocusAndSharedActorNeverBecomesYou() { + val snapshot = requestsFixture() + val state = sheet(snapshot) + mount(state) + send(Key.DirectionDown) + rule.runOnIdle { state.requests.update(snapshot.copy(items = snapshot.items.reversed(), partial = true)) } + assertEquals("x1", state.requests.focusedId) + rule.onNodeWithText("Some requests may be missing: Conductarr answered only in part.").assertExists() + val shared = requestsFixture(shared = true).items.single() + val viewer = fixturePeople().single { it.key == "shared" } + assertEquals("Shared", shared.actor(viewer)) + assertEquals("Justin", shared.recipient(viewer)) + assertEquals(5, snapshot.openCount) + assertEquals(listOf(0, 1, 1, 2, 3, 4), snapshot.ordered.map { it.stage.rank }) + } +} diff --git a/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/ShellCaptureTest.kt b/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/ShellCaptureTest.kt new file mode 100644 index 00000000..62d40759 --- /dev/null +++ b/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/ShellCaptureTest.kt @@ -0,0 +1,81 @@ +package org.justinvisser.wolfskin.design + +import android.app.Application +import android.view.View +import android.view.WindowManager +import androidx.activity.ComponentActivity +import androidx.compose.foundation.layout.requiredSize +import androidx.compose.ui.Modifier +import androidx.compose.ui.test.junit4.createAndroidComposeRule +import androidx.compose.ui.test.onRoot +import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.performSemanticsAction +import androidx.compose.ui.semantics.SemanticsActions +import androidx.compose.ui.text.TextLayoutResult +import com.github.takahirom.roborazzi.captureRoboImage +import java.io.File +import org.json.JSONObject +import org.junit.Before +import org.junit.Assert.assertEquals +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config +import org.robolectric.annotation.GraphicsMode + +/** Native 2.0-density captures are compared against the frozen browser states outside the build tree. */ +@RunWith(RobolectricTestRunner::class) +@Config(sdk = [34], application = Application::class, qualifiers = "w960dp-h540dp-xhdpi") +@GraphicsMode(GraphicsMode.Mode.NATIVE) +class ShellCaptureTest { + @get:Rule val rule = createAndroidComposeRule() + + @Before + fun fullscreen() { + rule.activity.window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN) + @Suppress("DEPRECATION") + rule.activity.window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_FULLSCREEN or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY + } + + private fun capture(name: String, openRequests: Int? = null, configure: (ShellState) -> Unit = {}) { + val state = ShellState(fixturePeople(), "justin") + configure(state) + rule.setContent { + WolfskinTheme { + ShellSurface(state, Modifier.requiredSize(WolfskinTokens.Shell.stageWidth, WolfskinTokens.Shell.stageHeight), settingsOpenRequests = openRequests) + } + } + rule.mainClock.advanceTimeBy(1000) + rule.waitForIdle() + val directory = File(System.getProperty("wolfskin.captureDirectory")) + directory.mkdirs() + rule.onRoot().captureRoboImage(File(directory, "$name.png").absolutePath) + } + + @Test fun st001_launch() = capture("st-001") + @Test fun st002_gear() { + capture("st-002") { it.pickerIndex = 2; it.gearFocused = true } + val layouts = mutableListOf() + rule.onNodeWithText("Settings").performSemanticsAction(SemanticsActions.GetTextLayoutResult) { get -> get(layouts) } + assertEquals("The caption must not wrap under the small gear", 1, layouts.single().lineCount) + } + @Test fun st003_loading() = capture("st-003") { it.peopleStatus = PeopleStatus.Loading } + @Test fun st004_unavailable() = capture("st-004") { it.peopleStatus = PeopleStatus.Unavailable } + @Test fun st010_homeNav() = capture("st-010") { it.pickerVisible = false; it.navFocused = true } + @Test fun st011_rememberedNav() = capture("st-011") { it.pickerVisible = false; it.navFocused = true; it.view.row = 4; it.view.cards["row-4"] = 2 } + @Test fun st014_discoverNav() = capture("st-014") { it.pickerVisible = false; it.navFocused = true; it.navIndex = 1 } + @Test fun st091_settings() = capture("st-091") { it.pickerVisible = false; it.enterDestination("settings") } + @Test fun st092_requestsCountFixture() = capture("st-092", openRequests = 5) { it.pickerVisible = false; it.enterDestination("settings") } + @Test fun st093_profileFocus() = capture("st-093") { it.pickerVisible = false; it.enterDestination("settings"); it.settingsRow = 4 } +} + +/** Tests and debug builds share the same shell-only projection of the locked fixture. */ +fun fixturePeople(): List { + val json = ShellCaptureTest::class.java.getResourceAsStream("/wolfskin-shell.json")!!.bufferedReader().use { JSONObject(it.readText()) } + val people = json.getJSONArray("profiles") + return List(people.length()) { index -> + val person = people.getJSONObject(index) + ShellPerson(person.getString("key"), person.getString("name"), person.getString("initial"), person.getJSONObject("destinations").has("Anime")) + } +} diff --git a/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/ShellKeysTest.kt b/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/ShellKeysTest.kt new file mode 100644 index 00000000..77052d6f --- /dev/null +++ b/wolfskin-design/src/test/java/org/justinvisser/wolfskin/design/ShellKeysTest.kt @@ -0,0 +1,114 @@ +package org.justinvisser.wolfskin.design + +import android.app.Application +import android.view.KeyEvent as AndroidKeyEvent +import androidx.compose.ui.input.key.Key +import androidx.compose.ui.input.key.KeyEvent +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onNodeWithTag +import androidx.compose.ui.test.performKeyInput +import androidx.compose.ui.test.pressKey +import org.junit.Assert.* +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config + +/** Press counts exercise the actual Android-to-shell event path, not a second focus implementation. */ +@RunWith(RobolectricTestRunner::class) +@Config(sdk = [34], application = Application::class, qualifiers = "w960dp-h540dp-xhdpi") +class ShellKeysTest { + @get:Rule val rule = createComposeRule() + private val state = ShellState(fixturePeople(), "justin") + private val settings = listOf(Key.DirectionCenter, Key.DirectionUp, Key.DirectionLeft, Key.DirectionCenter, Key.DirectionRight, Key.DirectionRight, Key.DirectionDown, Key.DirectionCenter) + + private fun replay(keys: List, presses: Int) { + assertEquals("Acceptance press count", presses, keys.size) + rule.setContent { WolfskinTheme { ShellSurface(state) } } + keys.forEach { key -> rule.onNodeWithTag("wolfskin-shell").performKeyInput { pressKey(key) } } + } + + @Test fun switchPersonInSixPresses() { + replay(listOf(Key.DirectionCenter, Key.DirectionUp, Key.DirectionLeft, Key.DirectionCenter, Key.DirectionRight, Key.DirectionCenter), 6) + assertEquals("mindel", state.person.key) + assertEquals("home", state.route) + assertFalse(state.pickerVisible) + assertFalse(state.navFocused) + assertFalse(state.tabs.contains("anime")) + } + + @Test fun openSettingsInEightPresses() { + replay(settings, 8) + assertEquals("settings", state.route) + assertEquals(0, state.settingsRow) + assertFalse(state.pickerVisible) + assertFalse("Requests content, not the nav, must own focus", state.navFocused) + } + + @Test fun settingsBackBackInTenPresses() { + replay(settings + listOf(Key.Back, Key.Back), 10) + assertEquals("home", state.route) + assertFalse(state.pickerVisible) + assertTrue(state.navFocused) + assertEquals(state.tabs.size, state.navIndex) + } + + @Test fun playbackHandOffInElevenPresses() { + replay(settings + listOf(Key.DirectionDown, Key.DirectionDown, Key.DirectionCenter), 11) + assertEquals("playback", state.handOff) + assertEquals(2, state.settingsRow) + } + + @Test fun onlyLastPersonReachesGearAndUpReturnsThere() { + replay(listOf(Key.DirectionDown, Key.DirectionRight, Key.DirectionDown), 3) + assertFalse(state.gearFocused) + rule.onNodeWithTag("wolfskin-shell").performKeyInput { pressKey(Key.DirectionRight); pressKey(Key.DirectionDown) } + assertTrue(state.gearFocused) + rule.onNodeWithTag("wolfskin-shell").performKeyInput { pressKey(Key.DirectionUp) } + assertFalse(state.gearFocused) + assertEquals(2, state.pickerIndex) + } + + @Test fun rootBackAndNavDownPreserveViewAndWrap() { + replay(listOf(Key.DirectionCenter), 1) + val view = state.view + rule.runOnIdle { view.row = 4; view.cards["row-4"] = 2 } + rule.onNodeWithTag("wolfskin-shell").performKeyInput { pressKey(Key.Back); pressKey(Key.DirectionDown) } + assertSame(view, state.view) + assertEquals(4, state.view.row) + assertEquals(2, state.view.cards["row-4"]) + rule.onNodeWithTag("wolfskin-shell").performKeyInput { pressKey(Key.DirectionUp); pressKey(Key.DirectionLeft) } + assertEquals(state.tabs.size, state.navIndex) + rule.onNodeWithTag("wolfskin-shell").performKeyInput { pressKey(Key.DirectionRight) } + assertEquals(0, state.navIndex) + } + + @Test fun destinationViewsAreIsolatedAndReselectResets() { + replay(listOf(Key.DirectionCenter), 1) + rule.runOnIdle { + state.enterDestination("movies") + val movies = state.view + movies.row = 3; movies.cards["movies"] = 2 + state.enterDestination("shows") + state.view.row = 1 + state.enterDestination("movies") + assertSame(movies, state.view) + state.focusNav(2); state.key(ShellKey.Ok) + assertNotSame(movies, state.view) + assertEquals(0, state.view.row) + assertTrue(state.view.cards.isEmpty()) + } + } + + @Test fun heldOkCannotActivateNewOverlay() { + replay(listOf(Key.DirectionCenter, Key.DirectionUp, Key.DirectionLeft), 3) + rule.runOnIdle { + state.handleKey(KeyEvent(AndroidKeyEvent(0, 0, AndroidKeyEvent.ACTION_DOWN, AndroidKeyEvent.KEYCODE_DPAD_CENTER, 0))) + repeat(5) { repeat -> state.handleKey(KeyEvent(AndroidKeyEvent(0, 0, AndroidKeyEvent.ACTION_DOWN, AndroidKeyEvent.KEYCODE_DPAD_CENTER, repeat + 1))) } + state.handleKey(KeyEvent(AndroidKeyEvent(0, 0, AndroidKeyEvent.ACTION_UP, AndroidKeyEvent.KEYCODE_DPAD_CENTER, 0))) + } + assertTrue(state.pickerVisible) + assertEquals("justin", state.person.key) + } +} diff --git a/wolfskin-design/src/test/resources/discover-keys.json b/wolfskin-design/src/test/resources/discover-keys.json new file mode 100644 index 00000000..d1328e10 --- /dev/null +++ b/wolfskin-design/src/test/resources/discover-keys.json @@ -0,0 +1,92 @@ +{ + "pressPaths": [ + { + "goal": "Open Discover", + "keys": [ + "OK", + "UP", + "RIGHT", + "OK" + ], + "presses": 4, + "note": "", + "start": "app launch: Who's watching with Justin focused (index.html:357)", + "replayed": "PASS", + "source": "index.html:2152-2174 PRESSES, replayed 2026-11-05" + }, + { + "goal": "Request a pick for yourself", + "keys": [ + "OK", + "UP", + "RIGHT", + "OK", + "OK", + "OK", + "OK" + ], + "presses": 7, + "note": "", + "start": "app launch: Who's watching with Justin focused (index.html:357)", + "replayed": "PASS", + "source": "index.html:2152-2174 PRESSES, replayed 2026-11-05" + }, + { + "goal": "Request a pick for Mindel", + "keys": [ + "OK", + "UP", + "RIGHT", + "OK", + "OK", + "RIGHT", + "OK", + "OK", + "OK" + ], + "presses": 9, + "note": "", + "start": "app launch: Who's watching with Justin focused (index.html:357)", + "replayed": "PASS", + "source": "index.html:2152-2174 PRESSES, replayed 2026-11-05" + }, + { + "goal": "Round 3 ยท Not interested on a pick (Discover hero)", + "keys": [ + "OK", + "UP", + "RIGHT", + "OK", + "OK", + "RIGHT", + "RIGHT", + "OK" + ], + "presses": 8, + "note": "", + "start": "app launch: Who's watching with Justin focused (index.html:357)", + "replayed": "PASS", + "source": "index.html:2152-2174 PRESSES, replayed 2026-11-05" + }, + { + "goal": "Round 4 ยท Discover pick nobody holds โ†’ its Trailer (sample hand-off)", + "keys": [ + "OK", + "UP", + "RIGHT", + "OK", + "OK", + "RIGHT", + "RIGHT", + "RIGHT", + "OK" + ], + "presses": 9, + "note": "4 on the title page (3 Rights to Trailer, OK); The Amazing Spider-Man", + "start": "app launch: Who's watching with Justin focused (index.html:357)", + "replayed": "PASS", + "source": "index.html:2152-2174 PRESSES, replayed 2026-11-05", + "requires": "Conductarr trailer field (spec 3.2, fifth addition); the press path runs once it lands" + } + ] +} diff --git a/wolfskin-design/src/test/resources/library-screen.json b/wolfskin-design/src/test/resources/library-screen.json new file mode 100644 index 00000000..0d1c8c2a --- /dev/null +++ b/wolfskin-design/src/test/resources/library-screen.json @@ -0,0 +1,494 @@ +{ + "id": "library", + "title": "Libraries: Movies, Shows, Anime (one continuous 6-column grid)", + "specSection": "6.4", + "source": "index.html:1403-1426, 1563-1611", + "layout": [ + { + "id": "lhead", + "type": "lhead", + "token": null, + "title": "Movies", + "yPx": 0, + "heightPx": 236, + "cards": null, + "focusable": false, + "endsInSeeAll": false, + "sampleFill": false + }, + { + "id": "ltools", + "type": "chips", + "token": null, + "title": "", + "yPx": 236, + "heightPx": 104, + "cards": null, + "focusable": true, + "endsInSeeAll": false, + "sampleFill": false + }, + { + "id": "g0", + "type": "grid", + "token": "poster", + "title": "", + "yPx": 340, + "heightPx": 488, + "cards": 6, + "focusable": true, + "endsInSeeAll": false, + "sampleFill": false + }, + { + "id": "g1", + "type": "grid", + "token": "poster", + "title": "", + "yPx": 828, + "heightPx": 488, + "cards": 6, + "focusable": true, + "endsInSeeAll": false, + "sampleFill": false + }, + { + "id": "g2", + "type": "grid", + "token": "poster", + "title": "", + "yPx": 1316, + "heightPx": 488, + "cards": 6, + "focusable": true, + "endsInSeeAll": false, + "sampleFill": false + }, + { + "id": "g3", + "type": "grid", + "token": "poster", + "title": "", + "yPx": 1804, + "heightPx": 488, + "cards": 6, + "focusable": true, + "endsInSeeAll": false, + "sampleFill": false + }, + { + "id": "g4", + "type": "grid", + "token": "poster", + "title": "", + "yPx": 2292, + "heightPx": 488, + "cards": 6, + "focusable": true, + "endsInSeeAll": false, + "sampleFill": false + }, + { + "id": "g5", + "type": "grid", + "token": "poster", + "title": "", + "yPx": 2780, + "heightPx": 488, + "cards": 6, + "focusable": true, + "endsInSeeAll": false, + "sampleFill": false + }, + { + "id": "g6", + "type": "grid", + "token": "poster", + "title": "", + "yPx": 3268, + "heightPx": 488, + "cards": 6, + "focusable": true, + "endsInSeeAll": false, + "sampleFill": false + }, + { + "id": "g7", + "type": "grid", + "token": "poster", + "title": "", + "yPx": 3756, + "heightPx": 488, + "cards": 6, + "focusable": true, + "endsInSeeAll": false, + "sampleFill": false + }, + { + "id": "g8", + "type": "grid", + "token": "poster", + "title": "", + "yPx": 4244, + "heightPx": 488, + "cards": 6, + "focusable": true, + "endsInSeeAll": false, + "sampleFill": false + }, + { + "id": "g9", + "type": "grid", + "token": "poster", + "title": "", + "yPx": 4732, + "heightPx": 488, + "cards": 6, + "focusable": true, + "endsInSeeAll": false, + "sampleFill": false + }, + { + "id": "g10", + "type": "grid", + "token": "poster", + "title": "", + "yPx": 5220, + "heightPx": 488, + "cards": 6, + "focusable": true, + "endsInSeeAll": false, + "sampleFill": false + }, + { + "id": "g11", + "type": "grid", + "token": "poster", + "title": "", + "yPx": 5708, + "heightPx": 488, + "cards": 6, + "focusable": true, + "endsInSeeAll": false, + "sampleFill": false + }, + { + "id": "g12", + "type": "grid", + "token": "poster", + "title": "", + "yPx": 6196, + "heightPx": 488, + "cards": 6, + "focusable": true, + "endsInSeeAll": false, + "sampleFill": false + }, + { + "id": "g13", + "type": "grid", + "token": "poster", + "title": "", + "yPx": 6684, + "heightPx": 488, + "cards": 6, + "focusable": true, + "endsInSeeAll": false, + "sampleFill": false + } + ], + "states": [ + { + "id": "st-021", + "name": "Shared Movies: 84, continuous grid", + "statesGroup": "Libraries", + "capture": "st-021-shared-movies-84-continuous-grid.jpg", + "captureUrl": "https://pages.justinvisser.org/wolfskin/tv-spec/img/st-021-shared-movies-84-continuous-grid.jpg", + "screenKind": "library", + "overlay": null, + "focusZone": "content", + "person": "shared", + "focusReadout": "State: Shared Movies: 84, continuous grid ยท Person: Shared ยท Screen: Movies ยท Focus: g0 โ€บ American Gangster" + }, + { + "id": "st-022", + "name": "Shared Movies sorted by Rating (G10)", + "statesGroup": "Libraries", + "capture": "st-022-shared-movies-sorted-by-rating-g10.jpg", + "captureUrl": "https://pages.justinvisser.org/wolfskin/tv-spec/img/st-022-shared-movies-sorted-by-rating-g10.jpg", + "screenKind": "library", + "overlay": null, + "focusZone": "content", + "person": "shared", + "focusReadout": "State: Shared Movies sorted by Rating (G10) ยท Person: Shared ยท Screen: Movies ยท Focus: g0 โ€บ Grave of the Fireflies" + }, + { + "id": "st-023", + "name": "Right at a row end clamps (no letter rail below 200)", + "statesGroup": "Libraries", + "capture": "st-023-right-at-a-row-end-clamps-no-letter-rail-below-200.jpg", + "captureUrl": "https://pages.justinvisser.org/wolfskin/tv-spec/img/st-023-right-at-a-row-end-clamps-no-letter-rail-below-200.jpg", + "screenKind": "library", + "overlay": null, + "focusZone": "content", + "person": "shared", + "focusReadout": "State: Right at a row end clamps (no letter rail below 200) ยท Person: Shared ยท Screen: Movies ยท Focus: g0 โ€บ Bohemian Rhapsody" + }, + { + "id": "st-024", + "name": "Justin Anime: 18 series", + "statesGroup": "Libraries", + "capture": "st-024-justin-anime-18-series.jpg", + "captureUrl": "https://pages.justinvisser.org/wolfskin/tv-spec/img/st-024-justin-anime-18-series.jpg", + "screenKind": "library", + "overlay": null, + "focusZone": "content", + "person": "justin", + "focusReadout": "State: Justin Anime: 18 series ยท Person: Justin ยท Screen: Anime ยท Focus: g0 โ€บ Bleach" + }, + { + "id": "st-025", + "name": "Unwatched filter", + "statesGroup": "Libraries", + "capture": "st-025-unwatched-filter.jpg", + "captureUrl": "https://pages.justinvisser.org/wolfskin/tv-spec/img/st-025-unwatched-filter.jpg", + "screenKind": "library", + "overlay": null, + "focusZone": "content", + "person": "shared", + "focusReadout": "State: Unwatched filter ยท Person: Shared ยท Screen: Movies ยท Focus: g0 โ€บ Annie Hall" + }, + { + "id": "st-026", + "name": "Empty destination", + "statesGroup": "Libraries", + "capture": "st-026-empty-destination.jpg", + "captureUrl": "https://pages.justinvisser.org/wolfskin/tv-spec/img/st-026-empty-destination.jpg", + "screenKind": "library", + "overlay": null, + "focusZone": "content", + "person": "mindel", + "focusReadout": "State: Empty destination ยท Person: Mindel ยท Screen: Movies ยท Focus: Nothing in Movies yet โ€บ Open Discover" + }, + { + "id": "st-027", + "name": "Jellyfin unreachable (error)", + "statesGroup": "Libraries", + "capture": "st-027-jellyfin-unreachable-error.jpg", + "captureUrl": "https://pages.justinvisser.org/wolfskin/tv-spec/img/st-027-jellyfin-unreachable-error.jpg", + "screenKind": "library", + "overlay": null, + "focusZone": "content", + "person": "mindel", + "focusReadout": "State: Jellyfin unreachable (error) ยท Person: Mindel ยท Screen: Shows ยท Focus: Couldnโ€™t reach your library โ€บ Try again" + }, + { + "id": "st-028", + "name": "Loading (skeleton, no saved copy)", + "statesGroup": "Libraries", + "capture": "st-028-loading-skeleton-no-saved-copy.jpg", + "captureUrl": "https://pages.justinvisser.org/wolfskin/tv-spec/img/st-028-loading-skeleton-no-saved-copy.jpg", + "screenKind": "library", + "overlay": null, + "focusZone": "nav", + "person": "shared", + "focusReadout": "State: Loading (skeleton, no saved copy) ยท Person: Shared ยท Screen: Movies ยท Focus: nav โ€บ Movies" + }, + { + "id": "st-095", + "name": "Plate: widest real set on a 256 px poster", + "statesGroup": "Ratings: one-line plate (round 3)", + "capture": "st-095-plate-widest-real-set-on-a-256-px-poster.jpg", + "captureUrl": "https://pages.justinvisser.org/wolfskin/tv-spec/img/st-095-plate-widest-real-set-on-a-256-px-poster.jpg", + "screenKind": "library", + "overlay": null, + "focusZone": "content", + "person": "shared", + "focusReadout": "State: Plate: widest real set on a 256 px poster ยท Person: Shared ยท Screen: Movies ยท Focus: g4 โ€บ Grave of the Fireflies" + }, + { + "id": "st-097", + "name": "Poster: RT critics on a library grid (Shared Movies)", + "statesGroup": "Ratings (round 2)", + "capture": "st-097-poster-rt-critics-on-a-library-grid-shared-movies.jpg", + "captureUrl": "https://pages.justinvisser.org/wolfskin/tv-spec/img/st-097-poster-rt-critics-on-a-library-grid-shared-movies.jpg", + "screenKind": "library", + "overlay": null, + "focusZone": "content", + "person": "shared", + "focusReadout": "State: Poster: RT critics on a library grid (Shared Movies) ยท Person: Shared ยท Screen: Movies ยท Focus: g0 โ€บ American Gangster" + }, + { + "id": "st-098", + "name": "Poster: TMDB only (Justin Anime)", + "statesGroup": "Ratings (round 2)", + "capture": "st-098-poster-tmdb-only-justin-anime.jpg", + "captureUrl": "https://pages.justinvisser.org/wolfskin/tv-spec/img/st-098-poster-tmdb-only-justin-anime.jpg", + "screenKind": "library", + "overlay": null, + "focusZone": "content", + "person": "justin", + "focusReadout": "State: Poster: TMDB only (Justin Anime) ยท Person: Justin ยท Screen: Anime ยท Focus: g0 โ€บ Chainsaw Man" + }, + { + "id": "st-112", + "name": "Conductarr down: a cached rating still shows", + "statesGroup": "Ratings (round 2)", + "capture": "st-112-conductarr-down-a-cached-rating-still-shows.jpg", + "captureUrl": "https://pages.justinvisser.org/wolfskin/tv-spec/img/st-112-conductarr-down-a-cached-rating-still-shows.jpg", + "screenKind": "library", + "overlay": null, + "focusZone": "content", + "person": "shared", + "focusReadout": "State: Conductarr down: a cached rating still shows ยท Person: Shared ยท Screen: Movies ยท Focus: g0 โ€บ American Gangster" + }, + { + "id": "st-113", + "name": "Conductarr down: an uncached title shows nothing", + "statesGroup": "Ratings (round 2)", + "capture": "st-113-conductarr-down-an-uncached-title-shows-nothing.jpg", + "captureUrl": "https://pages.justinvisser.org/wolfskin/tv-spec/img/st-113-conductarr-down-an-uncached-title-shows-nothing.jpg", + "screenKind": "library", + "overlay": null, + "focusZone": "content", + "person": "shared", + "focusReadout": "State: Conductarr down: an uncached title shows nothing ยท Person: Shared ยท Screen: Movies ยท Focus: g0 โ€บ American Gangster" + } + ], + "focusMap": { + "entry": "first grid card (not the toolbar); returning: remembered card per person", + "zones": { + "toolbar": { + "up": "nav", + "down": "grid", + "left": "previous chip", + "right": "next chip", + "ok": "Sort cycles Aโ€“Z -> Recently added -> Rating; Filter toggles All / Unwatched; focus returns to the toolbar", + "back": "nav", + "source": "index.html:445" + }, + "grid": { + "up": "row above, same column (top row -> toolbar)", + "down": "row below, same column (shorter last row: its last card)", + "left": "previous column (column 0: stays)", + "right": "next column; at the row end: stays (no rail below 200 titles)", + "ok": "title page (key-up)", + "back": "nav, place kept", + "ratings": "one-line plate after 350 ms", + "source": "index.html:446" + }, + "letterRail": "only at >= 200 titles and Aโ€“Z sort: Right at a row end enters; Up/Down move letters and scroll live; OK or Left drops focus on that letter's first title; Back returns to where you were (index.html:1586-1605)" + }, + "exit": [ + "Up from toolbar -> nav", + "Back -> nav" + ] + }, + "pressPaths": [ + { + "goal": "Reach โ€œSpirited Awayโ€ (68th of 84) in Shared Movies by scrolling", + "keys": [ + "RIGHT", + "RIGHT", + "OK", + "UP", + "RIGHT", + "RIGHT", + "OK", + "DOWN", + "DOWN", + "DOWN", + "DOWN", + "DOWN", + "DOWN", + "DOWN", + "DOWN", + "DOWN", + "DOWN", + "DOWN", + "RIGHT", + "RIGHT" + ], + "presses": 20, + "note": "", + "start": "app launch: Who's watching with Justin focused (index.html:357)", + "replayed": "PASS", + "source": "index.html:2152-2174 PRESSES, replayed 2026-11-05" + } + ], + "data": [ + { + "component": "Library grid", + "source": "Jellyfin /Users/{id}/Items?ParentId=โ€ฆ&SortBy=SortName over the destination's libraries, read in full in 200-item chunks ahead of focus", + "fields": [ + "SortName", + "ProductionYear", + "ImageTags.Primary", + "UserData.Played", + "UserData.PlaybackPositionTicks", + "ProviderIds.Tmdb" + ], + "cache": "LKG snapshot per destination; refresh on open if older than 10 min", + "states": [ + "empty", + "Jellyfin unreachable (LKG + Saved chip, or state row)", + "missing art" + ], + "pageRow": "index.html:469" + }, + { + "component": "Destinations", + "source": "Conductarr GET /curation/library-audiences (owner, media_type, is_anime, libraries[], users[]); until sign-in, the name rule (parked board mapping-source = name-rule)", + "pageRow": "index.html:468" + } + ], + "strings": { + "count": "{n} films | {n} series", + "empty": [ + "Nothing in {Destination} yet", + "Titles you or others request for you land here.", + "Open Discover" + ], + "emptyUnwatched": [ + "Nothing unwatched in {Destination}", + "Everything here has been watched.", + "Show all" + ], + "down": [ + "Couldnโ€™t reach your library", + "Jellyfin isnโ€™t answering. Nothing here is lost; try again in a moment.", + "Try again" + ], + "sort": [ + "Aโ€“Z", + "Recently added", + "Rating" + ], + "filter": [ + "All", + "Unwatched" + ] + }, + "ratingScoreFormat": { + "rule": "TMDB, IMDb and \"Ep\" scores (0-10) are formatted with the TV locale and exactly one decimal, e.g. String.format(Locale.getDefault(), \"%.1f\", x): 7,8 on a Dutch-locale box, 7.8 on an English one. RT percentages unchanged (87%). The page prints 7.8 always: a stand-in for the English locale, not authoritative.", + "acceptance": "on a Dutch-locale emulator a TMDB 7.8 renders 7,8 and the one-line plate rule (spec 4.8) still holds because the width is unchanged [INFERENCE: comma and point advance widths not measured]; on an English-locale emulator it renders 7.8 as in the captures", + "source": "Justin 2026-11-05, corr=c248698d8546e1ab; spec 4.7 rule 5, 10.1 check 8" + }, + "$schema": "wolfskin-tv-spec/screen@1", + "tokens": "data/tv-spec/tokens.json", + "captures": [ + "st-021-shared-movies-84-continuous-grid.jpg", + "st-022-shared-movies-sorted-by-rating-g10.jpg", + "st-023-right-at-a-row-end-clamps-no-letter-rail-below-200.jpg", + "st-024-justin-anime-18-series.jpg", + "st-025-unwatched-filter.jpg", + "st-026-empty-destination.jpg", + "st-027-jellyfin-unreachable-error.jpg", + "st-028-loading-skeleton-no-saved-copy.jpg", + "st-095-plate-widest-real-set-on-a-256-px-poster.jpg", + "st-097-poster-rt-critics-on-a-library-grid-shared-movies.jpg", + "st-098-poster-tmdb-only-justin-anime.jpg", + "st-112-conductarr-down-a-cached-rating-still-shows.jpg", + "st-113-conductarr-down-an-uncached-title-shows-nothing.jpg" + ] +} \ No newline at end of file diff --git a/wolfskin-design/src/test/resources/library/assets/movie-101-dalmatians-ii-patch-s-london-adventure-2003-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-101-dalmatians-ii-patch-s-london-adventure-2003-poster.jpg new file mode 100644 index 00000000..b9b72894 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-101-dalmatians-ii-patch-s-london-adventure-2003-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-12-years-a-slave-2013-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-12-years-a-slave-2013-poster.jpg new file mode 100644 index 00000000..ff1f55e6 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-12-years-a-slave-2013-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-a-bronx-tale-1993-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-a-bronx-tale-1993-poster.jpg new file mode 100644 index 00000000..f7444271 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-a-bronx-tale-1993-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-a-silent-voice-the-movie-2016-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-a-silent-voice-the-movie-2016-poster.jpg new file mode 100644 index 00000000..580b22f4 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-a-silent-voice-the-movie-2016-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-absolution-2024-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-absolution-2024-poster.jpg new file mode 100644 index 00000000..3ce49112 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-absolution-2024-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-across-the-hall-2009-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-across-the-hall-2009-poster.jpg new file mode 100644 index 00000000..52362b4e Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-across-the-hall-2009-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-addicted-2014-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-addicted-2014-poster.jpg new file mode 100644 index 00000000..e9a03c14 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-addicted-2014-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-adulterers-2016-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-adulterers-2016-poster.jpg new file mode 100644 index 00000000..8b65745b Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-adulterers-2016-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-all-the-money-in-the-world-2017-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-all-the-money-in-the-world-2017-poster.jpg new file mode 100644 index 00000000..8beb2f7f Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-all-the-money-in-the-world-2017-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-alone-with-her-2006-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-alone-with-her-2006-poster.jpg new file mode 100644 index 00000000..7ce6fa96 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-alone-with-her-2006-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-american-gangster-2007-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-american-gangster-2007-poster.jpg new file mode 100644 index 00000000..0f41d299 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-american-gangster-2007-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-annie-hall-1977-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-annie-hall-1977-poster.jpg new file mode 100644 index 00000000..9023a691 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-annie-hall-1977-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-ant-man-and-the-wasp-quantumania-2023-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-ant-man-and-the-wasp-quantumania-2023-poster.jpg new file mode 100644 index 00000000..030addf0 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-ant-man-and-the-wasp-quantumania-2023-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-apocalypse-now-1979-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-apocalypse-now-1979-poster.jpg new file mode 100644 index 00000000..09cd6aa8 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-apocalypse-now-1979-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-appleseed-alpha-2014-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-appleseed-alpha-2014-poster.jpg new file mode 100644 index 00000000..62bd0afa Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-appleseed-alpha-2014-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-aquaman-and-the-lost-kingdom-2023-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-aquaman-and-the-lost-kingdom-2023-poster.jpg new file mode 100644 index 00000000..4550bdaa Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-aquaman-and-the-lost-kingdom-2023-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-arctic-dogs-2019-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-arctic-dogs-2019-poster.jpg new file mode 100644 index 00000000..07552443 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-arctic-dogs-2019-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-arrival-2016-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-arrival-2016-poster.jpg new file mode 100644 index 00000000..fe224a15 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-arrival-2016-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-avatar-aang-the-last-airbender-2026-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-avatar-aang-the-last-airbender-2026-poster.jpg new file mode 100644 index 00000000..f57f1052 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-avatar-aang-the-last-airbender-2026-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-avengers-age-of-ultron-2015-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-avengers-age-of-ultron-2015-poster.jpg new file mode 100644 index 00000000..300840ff Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-avengers-age-of-ultron-2015-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-avengers-confidential-black-widow-punisher-2014-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-avengers-confidential-black-widow-punisher-2014-poster.jpg new file mode 100644 index 00000000..b096fff2 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-avengers-confidential-black-widow-punisher-2014-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-avengers-infinity-war-2018-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-avengers-infinity-war-2018-poster.jpg new file mode 100644 index 00000000..57df9298 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-avengers-infinity-war-2018-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-awake-2007-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-awake-2007-poster.jpg new file mode 100644 index 00000000..32595897 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-awake-2007-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-batman-ninja-2018-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-batman-ninja-2018-poster.jpg new file mode 100644 index 00000000..7f59127b Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-batman-ninja-2018-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-batman-the-dark-knight-returns-part-1-2012-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-batman-the-dark-knight-returns-part-1-2012-poster.jpg new file mode 100644 index 00000000..ce5623fe Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-batman-the-dark-knight-returns-part-1-2012-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-batman-v-superman-dawn-of-justice-2016-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-batman-v-superman-dawn-of-justice-2016-poster.jpg new file mode 100644 index 00000000..f8115170 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-batman-v-superman-dawn-of-justice-2016-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-black-adam-2022-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-black-adam-2022-poster.jpg new file mode 100644 index 00000000..dde008b5 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-black-adam-2022-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-black-bear-2020-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-black-bear-2020-poster.jpg new file mode 100644 index 00000000..61c8860f Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-black-bear-2020-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-black-panther-2018-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-black-panther-2018-poster.jpg new file mode 100644 index 00000000..6fdaa3d2 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-black-panther-2018-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-black-panther-wakanda-forever-2022-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-black-panther-wakanda-forever-2022-poster.jpg new file mode 100644 index 00000000..d0219a75 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-black-panther-wakanda-forever-2022-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-blame-2017-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-blame-2017-poster.jpg new file mode 100644 index 00000000..8d50255f Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-blame-2017-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-bleach-the-movie-fade-to-black-2008-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-bleach-the-movie-fade-to-black-2008-poster.jpg new file mode 100644 index 00000000..d3619fbd Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-bleach-the-movie-fade-to-black-2008-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-bohemian-rhapsody-2018-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-bohemian-rhapsody-2018-poster.jpg new file mode 100644 index 00000000..20d2f9ee Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-bohemian-rhapsody-2018-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-braveheart-1995-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-braveheart-1995-poster.jpg new file mode 100644 index 00000000..32fd8d4d Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-braveheart-1995-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-butterfly-on-a-wheel-2007-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-butterfly-on-a-wheel-2007-poster.jpg new file mode 100644 index 00000000..b54cc5c7 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-butterfly-on-a-wheel-2007-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-by-any-means-2026-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-by-any-means-2026-poster.jpg new file mode 100644 index 00000000..92fd601f Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-by-any-means-2026-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-captain-america-civil-war-2016-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-captain-america-civil-war-2016-poster.jpg new file mode 100644 index 00000000..426142ef Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-captain-america-civil-war-2016-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-captain-america-the-first-avenger-2011-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-captain-america-the-first-avenger-2011-poster.jpg new file mode 100644 index 00000000..bba96574 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-captain-america-the-first-avenger-2011-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-captain-america-the-winter-soldier-2014-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-captain-america-the-winter-soldier-2014-poster.jpg new file mode 100644 index 00000000..c2dc5612 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-captain-america-the-winter-soldier-2014-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-careful-what-you-wish-for-2015-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-careful-what-you-wish-for-2015-poster.jpg new file mode 100644 index 00000000..b58ce600 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-careful-what-you-wish-for-2015-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-castle-in-the-sky-1986-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-castle-in-the-sky-1986-poster.jpg new file mode 100644 index 00000000..a6a99fee Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-castle-in-the-sky-1986-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-chicago-2002-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-chicago-2002-poster.jpg new file mode 100644 index 00000000..1def9414 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-chicago-2002-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-citizen-kane-1941-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-citizen-kane-1941-poster.jpg new file mode 100644 index 00000000..f26414a7 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-citizen-kane-1941-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-coherence-2014-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-coherence-2014-poster.jpg new file mode 100644 index 00000000..f3601b9b Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-coherence-2014-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-conclave-2024-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-conclave-2024-poster.jpg new file mode 100644 index 00000000..c6aecefa Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-conclave-2024-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-crime-of-passion-1956-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-crime-of-passion-1956-poster.jpg new file mode 100644 index 00000000..4acfa871 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-crime-of-passion-1956-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-deep-water-2022-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-deep-water-2022-poster.jpg new file mode 100644 index 00000000..018d4f4b Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-deep-water-2022-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-derailed-2005-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-derailed-2005-poster.jpg new file mode 100644 index 00000000..d93f3124 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-derailed-2005-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-die-my-love-2025-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-die-my-love-2025-poster.jpg new file mode 100644 index 00000000..f6eca818 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-die-my-love-2025-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-dream-house-2011-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-dream-house-2011-poster.jpg new file mode 100644 index 00000000..d3444637 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-dream-house-2011-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-dream-lover-1994-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-dream-lover-1994-poster.jpg new file mode 100644 index 00000000..3b563cf9 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-dream-lover-1994-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-drop-2025-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-drop-2025-poster.jpg new file mode 100644 index 00000000..4cf7d66b Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-drop-2025-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-eastern-promises-2007-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-eastern-promises-2007-poster.jpg new file mode 100644 index 00000000..01a26f3b Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-eastern-promises-2007-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-easy-a-2010-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-easy-a-2010-poster.jpg new file mode 100644 index 00000000..45e13a32 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-easy-a-2010-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-el-camino-a-breaking-bad-movie-2019-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-el-camino-a-breaking-bad-movie-2019-poster.jpg new file mode 100644 index 00000000..7a62df45 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-el-camino-a-breaking-bad-movie-2019-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-emancipation-2022-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-emancipation-2022-poster.jpg new file mode 100644 index 00000000..c1bee971 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-emancipation-2022-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-faces-1968-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-faces-1968-poster.jpg new file mode 100644 index 00000000..43f996bd Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-faces-1968-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-fatale-2020-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-fatale-2020-poster.jpg new file mode 100644 index 00000000..dda9d622 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-fatale-2020-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-fighting-with-my-family-2019-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-fighting-with-my-family-2019-poster.jpg new file mode 100644 index 00000000..169c466d Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-fighting-with-my-family-2019-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-force-of-nature-the-dry-2-2024-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-force-of-nature-the-dry-2-2024-poster.jpg new file mode 100644 index 00000000..93ba0d71 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-force-of-nature-the-dry-2-2024-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-free-state-of-jones-2016-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-free-state-of-jones-2016-poster.jpg new file mode 100644 index 00000000..e69af7c0 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-free-state-of-jones-2016-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-from-up-on-poppy-hill-2011-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-from-up-on-poppy-hill-2011-poster.jpg new file mode 100644 index 00000000..264076e2 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-from-up-on-poppy-hill-2011-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-ghost-in-the-shell-1995-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-ghost-in-the-shell-1995-poster.jpg new file mode 100644 index 00000000..58d221ba Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-ghost-in-the-shell-1995-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-ghost-in-the-shell-2-innocence-2004-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-ghost-in-the-shell-2-innocence-2004-poster.jpg new file mode 100644 index 00000000..ae262147 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-ghost-in-the-shell-2-innocence-2004-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-gosford-park-2001-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-gosford-park-2001-poster.jpg new file mode 100644 index 00000000..6a6aa651 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-gosford-park-2001-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-grave-of-the-fireflies-1988-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-grave-of-the-fireflies-1988-poster.jpg new file mode 100644 index 00000000..1b71996a Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-grave-of-the-fireflies-1988-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-howl-s-moving-castle-2004-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-howl-s-moving-castle-2004-poster.jpg new file mode 100644 index 00000000..042a6c80 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-howl-s-moving-castle-2004-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-in-the-heights-2021-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-in-the-heights-2021-poster.jpg new file mode 100644 index 00000000..e05bfdb0 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-in-the-heights-2021-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-jennifer-s-body-2009-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-jennifer-s-body-2009-poster.jpg new file mode 100644 index 00000000..41cc1eb5 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-jennifer-s-body-2009-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-kiki-s-delivery-service-1989-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-kiki-s-delivery-service-1989-poster.jpg new file mode 100644 index 00000000..80a59b1e Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-kiki-s-delivery-service-1989-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-lemony-snicket-s-a-series-of-unfortunate-events-2004-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-lemony-snicket-s-a-series-of-unfortunate-events-2004-poster.jpg new file mode 100644 index 00000000..4c78fee9 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-lemony-snicket-s-a-series-of-unfortunate-events-2004-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-locke-2014-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-locke-2014-poster.jpg new file mode 100644 index 00000000..94ebe97d Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-locke-2014-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-look-who-s-back-2015-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-look-who-s-back-2015-poster.jpg new file mode 100644 index 00000000..423043cf Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-look-who-s-back-2015-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-memories-1995-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-memories-1995-poster.jpg new file mode 100644 index 00000000..f3725b42 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-memories-1995-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-mercy-2026-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-mercy-2026-poster.jpg new file mode 100644 index 00000000..cfc0d812 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-mercy-2026-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-night-is-short-walk-on-girl-2017-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-night-is-short-walk-on-girl-2017-poster.jpg new file mode 100644 index 00000000..c6fa6a26 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-night-is-short-walk-on-girl-2017-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-normal-2026-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-normal-2026-poster.jpg new file mode 100644 index 00000000..f4c89db7 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-normal-2026-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-outlaw-king-2018-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-outlaw-king-2018-poster.jpg new file mode 100644 index 00000000..d6760468 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-outlaw-king-2018-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-panic-room-2002-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-panic-room-2002-poster.jpg new file mode 100644 index 00000000..0b2a0d30 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-panic-room-2002-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-peaky-blinders-the-immortal-man-2026-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-peaky-blinders-the-immortal-man-2026-poster.jpg new file mode 100644 index 00000000..a4814472 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-peaky-blinders-the-immortal-man-2026-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-ponyo-2008-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-ponyo-2008-poster.jpg new file mode 100644 index 00000000..f548e831 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-ponyo-2008-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-porco-rosso-1992-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-porco-rosso-1992-poster.jpg new file mode 100644 index 00000000..4a6a2bd1 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-porco-rosso-1992-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-princess-mononoke-1997-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-princess-mononoke-1997-poster.jpg new file mode 100644 index 00000000..21dd9359 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-princess-mononoke-1997-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-prisoners-2013-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-prisoners-2013-poster.jpg new file mode 100644 index 00000000..411b149b Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-prisoners-2013-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-racing-stripes-2005-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-racing-stripes-2005-poster.jpg new file mode 100644 index 00000000..cc2ef2ce Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-racing-stripes-2005-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-reincarnated-2012-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-reincarnated-2012-poster.jpg new file mode 100644 index 00000000..e9ab449c Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-reincarnated-2012-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-requiem-for-a-dream-2000-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-requiem-for-a-dream-2000-poster.jpg new file mode 100644 index 00000000..6f89abc3 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-requiem-for-a-dream-2000-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-rogue-one-a-star-wars-story-2016-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-rogue-one-a-star-wars-story-2016-poster.jpg new file mode 100644 index 00000000..c79e70a1 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-rogue-one-a-star-wars-story-2016-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-secondhand-lions-2003-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-secondhand-lions-2003-poster.jpg new file mode 100644 index 00000000..33408fa0 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-secondhand-lions-2003-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-self-reliance-2024-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-self-reliance-2024-poster.jpg new file mode 100644 index 00000000..0f6017ed Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-self-reliance-2024-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-serpico-1973-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-serpico-1973-poster.jpg new file mode 100644 index 00000000..8ddd6e52 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-serpico-1973-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-shaft-2000-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-shaft-2000-poster.jpg new file mode 100644 index 00000000..6b2b79ce Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-shaft-2000-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-shipwrecked-nightmare-at-sea-2026-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-shipwrecked-nightmare-at-sea-2026-poster.jpg new file mode 100644 index 00000000..f200a28d Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-shipwrecked-nightmare-at-sea-2026-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-sinbad-legend-of-the-seven-seas-2003-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-sinbad-legend-of-the-seven-seas-2003-poster.jpg new file mode 100644 index 00000000..428bb38b Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-sinbad-legend-of-the-seven-seas-2003-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-sleeping-with-other-people-2015-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-sleeping-with-other-people-2015-poster.jpg new file mode 100644 index 00000000..a5ffff1f Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-sleeping-with-other-people-2015-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-snowpiercer-2013-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-snowpiercer-2013-poster.jpg new file mode 100644 index 00000000..be1873fd Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-snowpiercer-2013-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-spider-man-brand-new-day-2026-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-spider-man-brand-new-day-2026-poster.jpg new file mode 100644 index 00000000..51fa155f Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-spider-man-brand-new-day-2026-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-spider-man-far-from-home-2019-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-spider-man-far-from-home-2019-poster.jpg new file mode 100644 index 00000000..28521997 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-spider-man-far-from-home-2019-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-spider-man-homecoming-2017-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-spider-man-homecoming-2017-poster.jpg new file mode 100644 index 00000000..97fc9c05 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-spider-man-homecoming-2017-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-spider-man-no-way-home-2021-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-spider-man-no-way-home-2021-poster.jpg new file mode 100644 index 00000000..bc92a4cd Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-spider-man-no-way-home-2021-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-spirited-away-2001-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-spirited-away-2001-poster.jpg new file mode 100644 index 00000000..5a79da62 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-spirited-away-2001-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-steins-gate-the-movie-load-region-of-deja-vu-2013-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-steins-gate-the-movie-load-region-of-deja-vu-2013-poster.jpg new file mode 100644 index 00000000..e85ddb90 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-steins-gate-the-movie-load-region-of-deja-vu-2013-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-taxi-driver-1976-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-taxi-driver-1976-poster.jpg new file mode 100644 index 00000000..c410b981 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-taxi-driver-1976-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-the-alto-knights-2025-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-the-alto-knights-2025-poster.jpg new file mode 100644 index 00000000..bb009cbf Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-the-alto-knights-2025-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-the-amazing-spider-man-2-2014-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-the-amazing-spider-man-2-2014-poster.jpg new file mode 100644 index 00000000..4de2711f Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-the-amazing-spider-man-2-2014-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-the-amazing-spider-man-2012-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-the-amazing-spider-man-2012-poster.jpg new file mode 100644 index 00000000..c1aec876 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-the-amazing-spider-man-2012-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-the-animatrix-2003-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-the-animatrix-2003-poster.jpg new file mode 100644 index 00000000..65553d47 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-the-animatrix-2003-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-the-avengers-2012-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-the-avengers-2012-poster.jpg new file mode 100644 index 00000000..be87067c Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-the-avengers-2012-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-the-boy-and-the-heron-2023-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-the-boy-and-the-heron-2023-poster.jpg new file mode 100644 index 00000000..094df64e Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-the-boy-and-the-heron-2023-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-the-breakfast-club-1985-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-the-breakfast-club-1985-poster.jpg new file mode 100644 index 00000000..d1823120 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-the-breakfast-club-1985-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-the-dry-2021-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-the-dry-2021-poster.jpg new file mode 100644 index 00000000..a0379f2f Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-the-dry-2021-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-the-girl-who-leapt-through-time-2006-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-the-girl-who-leapt-through-time-2006-poster.jpg new file mode 100644 index 00000000..ded6cd2a Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-the-girl-who-leapt-through-time-2006-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-the-godfather-1972-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-the-godfather-1972-poster.jpg new file mode 100644 index 00000000..94111d9b Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-the-godfather-1972-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-the-godfather-part-ii-1974-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-the-godfather-part-ii-1974-poster.jpg new file mode 100644 index 00000000..1328c99e Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-the-godfather-part-ii-1974-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-the-godfather-part-iii-1990-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-the-godfather-part-iii-1990-poster.jpg new file mode 100644 index 00000000..abbe5e99 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-the-godfather-part-iii-1990-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-the-great-gatsby-2013-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-the-great-gatsby-2013-poster.jpg new file mode 100644 index 00000000..e949fb3e Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-the-great-gatsby-2013-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-the-hours-2002-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-the-hours-2002-poster.jpg new file mode 100644 index 00000000..f87e919f Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-the-hours-2002-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-the-killing-of-a-sacred-deer-2017-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-the-killing-of-a-sacred-deer-2017-poster.jpg new file mode 100644 index 00000000..83464d4c Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-the-killing-of-a-sacred-deer-2017-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-the-last-of-the-mohicans-1992-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-the-last-of-the-mohicans-1992-poster.jpg new file mode 100644 index 00000000..950e9ba1 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-the-last-of-the-mohicans-1992-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-the-last-samurai-2003-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-the-last-samurai-2003-poster.jpg new file mode 100644 index 00000000..0d58440c Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-the-last-samurai-2003-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-the-lighthouse-2019-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-the-lighthouse-2019-poster.jpg new file mode 100644 index 00000000..15f26533 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-the-lighthouse-2019-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-the-matrix-1999-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-the-matrix-1999-poster.jpg new file mode 100644 index 00000000..c292dce5 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-the-matrix-1999-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-the-matrix-reloaded-2003-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-the-matrix-reloaded-2003-poster.jpg new file mode 100644 index 00000000..ab11f50f Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-the-matrix-reloaded-2003-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-the-matrix-resurrections-2021-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-the-matrix-resurrections-2021-poster.jpg new file mode 100644 index 00000000..4477ef1e Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-the-matrix-resurrections-2021-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-the-matrix-revolutions-2003-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-the-matrix-revolutions-2003-poster.jpg new file mode 100644 index 00000000..7236cc4e Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-the-matrix-revolutions-2003-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-the-patriot-2000-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-the-patriot-2000-poster.jpg new file mode 100644 index 00000000..c8582133 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-the-patriot-2000-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-the-secret-life-of-pets-2-2019-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-the-secret-life-of-pets-2-2019-poster.jpg new file mode 100644 index 00000000..fe50c2f8 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-the-secret-life-of-pets-2-2019-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-the-substance-2024-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-the-substance-2024-poster.jpg new file mode 100644 index 00000000..72accfed Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-the-substance-2024-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-the-tale-of-the-princess-kaguya-2013-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-the-tale-of-the-princess-kaguya-2013-poster.jpg new file mode 100644 index 00000000..882621cb Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-the-tale-of-the-princess-kaguya-2013-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-the-uprising-2026-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-the-uprising-2026-poster.jpg new file mode 100644 index 00000000..21976395 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-the-uprising-2026-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-the-wild-robot-2024-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-the-wild-robot-2024-poster.jpg new file mode 100644 index 00000000..0894754d Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-the-wild-robot-2024-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-the-wind-rises-2013-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-the-wind-rises-2013-poster.jpg new file mode 100644 index 00000000..b7688c77 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-the-wind-rises-2013-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-the-witcher-nightmare-of-the-wolf-2021-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-the-witcher-nightmare-of-the-wolf-2021-poster.jpg new file mode 100644 index 00000000..6db33db1 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-the-witcher-nightmare-of-the-wolf-2021-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-the-witcher-sirens-of-the-deep-2025-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-the-witcher-sirens-of-the-deep-2025-poster.jpg new file mode 100644 index 00000000..8a54bc7f Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-the-witcher-sirens-of-the-deep-2025-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-thelma-louise-1991-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-thelma-louise-1991-poster.jpg new file mode 100644 index 00000000..5a4ff0ab Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-thelma-louise-1991-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-triangle-of-sadness-2022-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-triangle-of-sadness-2022-poster.jpg new file mode 100644 index 00000000..aee092c6 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-triangle-of-sadness-2022-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-tsotsi-2005-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-tsotsi-2005-poster.jpg new file mode 100644 index 00000000..362ddd82 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-tsotsi-2005-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-unknown-number-the-high-school-catfish-2025-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-unknown-number-the-high-school-catfish-2025-poster.jpg new file mode 100644 index 00000000..e32685f3 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-unknown-number-the-high-school-catfish-2025-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-vice-2018-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-vice-2018-poster.jpg new file mode 100644 index 00000000..76855126 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-vice-2018-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-vicky-cristina-barcelona-2008-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-vicky-cristina-barcelona-2008-poster.jpg new file mode 100644 index 00000000..1351cad1 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-vicky-cristina-barcelona-2008-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-warriors-of-the-wind-1984-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-warriors-of-the-wind-1984-poster.jpg new file mode 100644 index 00000000..918e424f Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-warriors-of-the-wind-1984-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-we-bury-the-dead-2026-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-we-bury-the-dead-2026-poster.jpg new file mode 100644 index 00000000..a0d65904 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-we-bury-the-dead-2026-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/movie-white-hot-the-rise-fall-of-abercrombie-fitch-2022-poster.jpg b/wolfskin-design/src/test/resources/library/assets/movie-white-hot-the-rise-fall-of-abercrombie-fitch-2022-poster.jpg new file mode 100644 index 00000000..3a123e80 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/movie-white-hot-the-rise-fall-of-abercrombie-fitch-2022-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-12-monkeys-2015-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-12-monkeys-2015-poster.jpg new file mode 100644 index 00000000..96e3596e Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-12-monkeys-2015-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-56-days-2026-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-56-days-2026-poster.jpg new file mode 100644 index 00000000..64ca587b Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-56-days-2026-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-90-day-fiance-before-the-90-days-2017-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-90-day-fiance-before-the-90-days-2017-poster.jpg new file mode 100644 index 00000000..3362da59 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-90-day-fiance-before-the-90-days-2017-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-90-day-fiance-the-other-way-2019-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-90-day-fiance-the-other-way-2019-poster.jpg new file mode 100644 index 00000000..b4d256eb Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-90-day-fiance-the-other-way-2019-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-a-knight-of-the-seven-kingdoms-2026-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-a-knight-of-the-seven-kingdoms-2026-poster.jpg new file mode 100644 index 00000000..79f1351c Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-a-knight-of-the-seven-kingdoms-2026-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-absolutely-fabulous-1992-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-absolutely-fabulous-1992-poster.jpg new file mode 100644 index 00000000..afd371a9 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-absolutely-fabulous-1992-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-accel-world-2012-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-accel-world-2012-poster.jpg new file mode 100644 index 00000000..207b1dd1 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-accel-world-2012-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-accused-2023-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-accused-2023-poster.jpg new file mode 100644 index 00000000..74af010a Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-accused-2023-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-adults-2025-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-adults-2025-poster.jpg new file mode 100644 index 00000000..53a7ba33 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-adults-2025-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-after-life-2019-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-after-life-2019-poster.jpg new file mode 100644 index 00000000..4fae4e33 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-after-life-2019-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-agatha-christie-s-marple-2004-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-agatha-christie-s-marple-2004-poster.jpg new file mode 100644 index 00000000..ea7dda99 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-agatha-christie-s-marple-2004-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-ahsoka-2023-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-ahsoka-2023-poster.jpg new file mode 100644 index 00000000..a29d6cb4 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-ahsoka-2023-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-all-american-homecoming-2022-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-all-american-homecoming-2022-poster.jpg new file mode 100644 index 00000000..09ccfc33 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-all-american-homecoming-2022-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-all-creatures-great-and-small-1978-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-all-creatures-great-and-small-1978-poster.jpg new file mode 100644 index 00000000..5b1666e6 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-all-creatures-great-and-small-1978-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-all-creatures-great-small-2020-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-all-creatures-great-small-2020-poster.jpg new file mode 100644 index 00000000..b506f990 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-all-creatures-great-small-2020-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-american-crime-story-2016-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-american-crime-story-2016-poster.jpg new file mode 100644 index 00000000..4086bf17 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-american-crime-story-2016-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-american-dad-2005-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-american-dad-2005-poster.jpg new file mode 100644 index 00000000..1f9e239a Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-american-dad-2005-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-american-gods-2017-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-american-gods-2017-poster.jpg new file mode 100644 index 00000000..c02c46da Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-american-gods-2017-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-american-housewife-2016-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-american-housewife-2016-poster.jpg new file mode 100644 index 00000000..5f92bf05 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-american-housewife-2016-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-american-primeval-2025-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-american-primeval-2025-poster.jpg new file mode 100644 index 00000000..7f10e6aa Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-american-primeval-2025-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-and-just-like-that-2021-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-and-just-like-that-2021-poster.jpg new file mode 100644 index 00000000..9904c74b Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-and-just-like-that-2021-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-andor-2022-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-andor-2022-poster.jpg new file mode 100644 index 00000000..df5dc498 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-andor-2022-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-andromeda-2000-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-andromeda-2000-poster.jpg new file mode 100644 index 00000000..67b766b0 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-andromeda-2000-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-anne-with-an-e-2017-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-anne-with-an-e-2017-poster.jpg new file mode 100644 index 00000000..55d443b4 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-anne-with-an-e-2017-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-aqua-teen-hunger-force-2000-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-aqua-teen-hunger-force-2000-poster.jpg new file mode 100644 index 00000000..e0c97321 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-aqua-teen-hunger-force-2000-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-arifureta-from-commonplace-to-world-s-strongest-2019-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-arifureta-from-commonplace-to-world-s-strongest-2019-poster.jpg new file mode 100644 index 00000000..6a8f9a24 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-arifureta-from-commonplace-to-world-s-strongest-2019-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-arrested-development-2003-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-arrested-development-2003-poster.jpg new file mode 100644 index 00000000..02b0dd43 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-arrested-development-2003-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-arrow-2012-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-arrow-2012-poster.jpg new file mode 100644 index 00000000..adee3bb7 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-arrow-2012-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-atlantis-2013-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-atlantis-2013-poster.jpg new file mode 100644 index 00000000..5cd5f098 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-atlantis-2013-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-avatar-seven-havens-2026-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-avatar-seven-havens-2026-poster.jpg new file mode 100644 index 00000000..61f459c6 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-avatar-seven-havens-2026-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-avatar-the-last-airbender-2005-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-avatar-the-last-airbender-2005-poster.jpg new file mode 100644 index 00000000..6f99263a Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-avatar-the-last-airbender-2005-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-avatar-the-last-airbender-2024-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-avatar-the-last-airbender-2024-poster.jpg new file mode 100644 index 00000000..9d46c2ff Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-avatar-the-last-airbender-2024-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-awkward-2011-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-awkward-2011-poster.jpg new file mode 100644 index 00000000..8da6e8e2 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-awkward-2011-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-b-b-vol-liefde-2021-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-b-b-vol-liefde-2021-poster.jpg new file mode 100644 index 00000000..a12ac33e Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-b-b-vol-liefde-2021-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-back-to-life-2019-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-back-to-life-2019-poster.jpg new file mode 100644 index 00000000..b00730a8 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-back-to-life-2019-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-ballers-2015-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-ballers-2015-poster.jpg new file mode 100644 index 00000000..f1c18f69 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-ballers-2015-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-baretta-1975-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-baretta-1975-poster.jpg new file mode 100644 index 00000000..ceef0c9d Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-baretta-1975-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-based-on-a-true-story-2023-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-based-on-a-true-story-2023-poster.jpg new file mode 100644 index 00000000..386d3d90 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-based-on-a-true-story-2023-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-batman-the-brave-and-the-bold-2008-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-batman-the-brave-and-the-bold-2008-poster.jpg new file mode 100644 index 00000000..a864f50c Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-batman-the-brave-and-the-bold-2008-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-batwoman-2019-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-batwoman-2019-poster.jpg new file mode 100644 index 00000000..7ca86592 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-batwoman-2019-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-beat-bobby-flay-2013-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-beat-bobby-flay-2013-poster.jpg new file mode 100644 index 00000000..fe11122d Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-beat-bobby-flay-2013-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-benson-1979-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-benson-1979-poster.jpg new file mode 100644 index 00000000..fe264c76 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-benson-1979-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-big-boys-2022-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-big-boys-2022-poster.jpg new file mode 100644 index 00000000..93e1e86a Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-big-boys-2022-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-big-city-greens-2018-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-big-city-greens-2018-poster.jpg new file mode 100644 index 00000000..ef024946 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-big-city-greens-2018-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-big-mouth-2017-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-big-mouth-2017-poster.jpg new file mode 100644 index 00000000..4f535fec Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-big-mouth-2017-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-black-ish-2014-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-black-ish-2014-poster.jpg new file mode 100644 index 00000000..97c885ad Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-black-ish-2014-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-black-lightning-2018-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-black-lightning-2018-poster.jpg new file mode 100644 index 00000000..733f5cbc Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-black-lightning-2018-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-black-rabbit-2025-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-black-rabbit-2025-poster.jpg new file mode 100644 index 00000000..3ff9aeed Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-black-rabbit-2025-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-bleach-2004-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-bleach-2004-poster.jpg new file mode 100644 index 00000000..b233e033 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-bleach-2004-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-blue-planet-ii-2017-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-blue-planet-ii-2017-poster.jpg new file mode 100644 index 00000000..5e193ab2 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-blue-planet-ii-2017-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-brassic-2019-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-brassic-2019-poster.jpg new file mode 100644 index 00000000..73b77df2 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-brassic-2019-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-breaking-bad-2008-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-breaking-bad-2008-poster.jpg new file mode 100644 index 00000000..c4f7217c Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-breaking-bad-2008-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-breeders-2020-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-breeders-2020-poster.jpg new file mode 100644 index 00000000..49c61208 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-breeders-2020-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-californication-2007-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-californication-2007-poster.jpg new file mode 100644 index 00000000..38428e76 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-californication-2007-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-call-the-midwife-2012-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-call-the-midwife-2012-poster.jpg new file mode 100644 index 00000000..466a1a7b Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-call-the-midwife-2012-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-chainsaw-man-2022-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-chainsaw-man-2022-poster.jpg new file mode 100644 index 00000000..a3779772 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-chainsaw-man-2022-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-chernobyl-2019-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-chernobyl-2019-poster.jpg new file mode 100644 index 00000000..7664f4b0 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-chernobyl-2019-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-community-2009-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-community-2009-poster.jpg new file mode 100644 index 00000000..e75072ae Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-community-2009-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-cyberpunk-edgerunners-2022-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-cyberpunk-edgerunners-2022-poster.jpg new file mode 100644 index 00000000..8d338532 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-cyberpunk-edgerunners-2022-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-dan-da-dan-2024-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-dan-da-dan-2024-poster.jpg new file mode 100644 index 00000000..f42cec16 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-dan-da-dan-2024-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-dead-end-job-2026-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-dead-end-job-2026-poster.jpg new file mode 100644 index 00000000..f5546d88 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-dead-end-job-2026-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-derry-girls-2018-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-derry-girls-2018-poster.jpg new file mode 100644 index 00000000..56a8cd79 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-derry-girls-2018-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-desperate-housewives-2004-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-desperate-housewives-2004-poster.jpg new file mode 100644 index 00000000..0c4c38bc Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-desperate-housewives-2004-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-dopesick-2021-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-dopesick-2021-poster.jpg new file mode 100644 index 00000000..ac0b5900 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-dopesick-2021-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-dr-stone-2019-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-dr-stone-2019-poster.jpg new file mode 100644 index 00000000..0783ed8c Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-dr-stone-2019-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-dune-prophecy-2024-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-dune-prophecy-2024-poster.jpg new file mode 100644 index 00000000..eef2a4f3 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-dune-prophecy-2024-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-east-of-eden-2026-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-east-of-eden-2026-poster.jpg new file mode 100644 index 00000000..6f06f2c9 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-east-of-eden-2026-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-etoile-2025-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-etoile-2025-poster.jpg new file mode 100644 index 00000000..f078bc89 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-etoile-2025-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-fallout-2024-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-fallout-2024-poster.jpg new file mode 100644 index 00000000..5e87a07d Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-fallout-2024-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-fawlty-towers-1975-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-fawlty-towers-1975-poster.jpg new file mode 100644 index 00000000..53b406da Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-fawlty-towers-1975-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-firefly-2002-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-firefly-2002-poster.jpg new file mode 100644 index 00000000..9ad599b3 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-firefly-2002-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-fleabag-2016-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-fleabag-2016-poster.jpg new file mode 100644 index 00000000..bd3ccea5 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-fleabag-2016-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-frieren-beyond-journey-s-end-2023-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-frieren-beyond-journey-s-end-2023-poster.jpg new file mode 100644 index 00000000..cb94104e Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-frieren-beyond-journey-s-end-2023-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-fullmetal-alchemist-brotherhood-2009-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-fullmetal-alchemist-brotherhood-2009-poster.jpg new file mode 100644 index 00000000..935e4944 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-fullmetal-alchemist-brotherhood-2009-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-gilmore-girls-2000-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-gilmore-girls-2000-poster.jpg new file mode 100644 index 00000000..23b668cb Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-gilmore-girls-2000-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-ginny-georgia-2021-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-ginny-georgia-2021-poster.jpg new file mode 100644 index 00000000..1fca7bf6 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-ginny-georgia-2021-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-gravity-falls-2012-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-gravity-falls-2012-poster.jpg new file mode 100644 index 00000000..41c051e0 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-gravity-falls-2012-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-hellcats-2010-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-hellcats-2010-poster.jpg new file mode 100644 index 00000000..2427108b Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-hellcats-2010-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-high-potential-2024-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-high-potential-2024-poster.jpg new file mode 100644 index 00000000..00a07ca7 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-high-potential-2024-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-how-to-change-your-mind-2022-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-how-to-change-your-mind-2022-poster.jpg new file mode 100644 index 00000000..e80c7999 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-how-to-change-your-mind-2022-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-how-to-get-to-heaven-from-belfast-2026-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-how-to-get-to-heaven-from-belfast-2026-poster.jpg new file mode 100644 index 00000000..eb5fc487 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-how-to-get-to-heaven-from-belfast-2026-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-interrogation-2020-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-interrogation-2020-poster.jpg new file mode 100644 index 00000000..f3a21b66 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-interrogation-2020-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-invincible-2021-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-invincible-2021-poster.jpg new file mode 100644 index 00000000..c278e37e Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-invincible-2021-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-it-s-always-sunny-in-philadelphia-2005-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-it-s-always-sunny-in-philadelphia-2005-poster.jpg new file mode 100644 index 00000000..652923ee Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-it-s-always-sunny-in-philadelphia-2005-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-jujutsu-kaisen-2020-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-jujutsu-kaisen-2020-poster.jpg new file mode 100644 index 00000000..45f5ff22 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-jujutsu-kaisen-2020-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-kaiju-no-8-2024-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-kaiju-no-8-2024-poster.jpg new file mode 100644 index 00000000..062496fa Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-kaiju-no-8-2024-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-landman-2024-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-landman-2024-poster.jpg new file mode 100644 index 00000000..3d348798 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-landman-2024-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-last-samurai-standing-2025-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-last-samurai-standing-2025-poster.jpg new file mode 100644 index 00000000..a9789909 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-last-samurai-standing-2025-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-lord-of-the-flies-2026-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-lord-of-the-flies-2026-poster.jpg new file mode 100644 index 00000000..b1229ed8 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-lord-of-the-flies-2026-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-love-death-robots-2019-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-love-death-robots-2019-poster.jpg new file mode 100644 index 00000000..08449aa9 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-love-death-robots-2019-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-love-is-blind-2020-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-love-is-blind-2020-poster.jpg new file mode 100644 index 00000000..62ccf357 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-love-is-blind-2020-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-maniac-2018-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-maniac-2018-poster.jpg new file mode 100644 index 00000000..a1985217 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-maniac-2018-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-maximum-pleasure-guaranteed-2026-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-maximum-pleasure-guaranteed-2026-poster.jpg new file mode 100644 index 00000000..abe1b2e2 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-maximum-pleasure-guaranteed-2026-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-minx-2022-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-minx-2022-poster.jpg new file mode 100644 index 00000000..a8797fe5 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-minx-2022-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-mussolini-son-of-the-century-2024-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-mussolini-son-of-the-century-2024-poster.jpg new file mode 100644 index 00000000..925d5c49 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-mussolini-son-of-the-century-2024-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-my-hero-academia-2016-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-my-hero-academia-2016-poster.jpg new file mode 100644 index 00000000..cf571b93 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-my-hero-academia-2016-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-neon-genesis-evangelion-1995-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-neon-genesis-evangelion-1995-poster.jpg new file mode 100644 index 00000000..f86cd698 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-neon-genesis-evangelion-1995-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-norsemen-2016-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-norsemen-2016-poster.jpg new file mode 100644 index 00000000..e7206b88 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-norsemen-2016-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-offspring-2010-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-offspring-2010-poster.jpg new file mode 100644 index 00000000..ae305043 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-offspring-2010-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-one-piece-2023-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-one-piece-2023-poster.jpg new file mode 100644 index 00000000..286e6260 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-one-piece-2023-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-only-murders-in-the-building-2021-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-only-murders-in-the-building-2021-poster.jpg new file mode 100644 index 00000000..a6b147a4 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-only-murders-in-the-building-2021-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-outlander-blood-of-my-blood-2025-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-outlander-blood-of-my-blood-2025-poster.jpg new file mode 100644 index 00000000..930943b0 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-outlander-blood-of-my-blood-2025-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-over-the-garden-wall-2014-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-over-the-garden-wall-2014-poster.jpg new file mode 100644 index 00000000..34b1ed84 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-over-the-garden-wall-2014-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-peaky-blinders-2013-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-peaky-blinders-2013-poster.jpg new file mode 100644 index 00000000..25ceea88 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-peaky-blinders-2013-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-pluribus-2025-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-pluribus-2025-poster.jpg new file mode 100644 index 00000000..1ea4711b Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-pluribus-2025-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-record-of-ragnarok-2021-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-record-of-ragnarok-2021-poster.jpg new file mode 100644 index 00000000..97d481d6 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-record-of-ragnarok-2021-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-rick-and-morty-2013-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-rick-and-morty-2013-poster.jpg new file mode 100644 index 00000000..b95c4890 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-rick-and-morty-2013-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-ripley-2024-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-ripley-2024-poster.jpg new file mode 100644 index 00000000..de0b32dd Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-ripley-2024-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-rivals-2024-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-rivals-2024-poster.jpg new file mode 100644 index 00000000..296ac67a Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-rivals-2024-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-rooster-2026-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-rooster-2026-poster.jpg new file mode 100644 index 00000000..b698f8a6 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-rooster-2026-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-sakamoto-days-2025-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-sakamoto-days-2025-poster.jpg new file mode 100644 index 00000000..ed9358b3 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-sakamoto-days-2025-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-say-nothing-2024-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-say-nothing-2024-poster.jpg new file mode 100644 index 00000000..cf50fc09 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-say-nothing-2024-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-secret-level-2024-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-secret-level-2024-poster.jpg new file mode 100644 index 00000000..1b6e67f6 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-secret-level-2024-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-sentenced-to-be-a-hero-2025-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-sentenced-to-be-a-hero-2025-poster.jpg new file mode 100644 index 00000000..2fb1c815 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-sentenced-to-be-a-hero-2025-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-severance-2022-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-severance-2022-poster.jpg new file mode 100644 index 00000000..5a29d6f9 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-severance-2022-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-sex-and-the-city-1998-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-sex-and-the-city-1998-poster.jpg new file mode 100644 index 00000000..e546cc6d Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-sex-and-the-city-1998-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-silo-2023-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-silo-2023-poster.jpg new file mode 100644 index 00000000..b493bc7b Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-silo-2023-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-six-feet-under-2001-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-six-feet-under-2001-poster.jpg new file mode 100644 index 00000000..559d6bd1 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-six-feet-under-2001-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-skymed-2022-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-skymed-2022-poster.jpg new file mode 100644 index 00000000..2540dad7 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-skymed-2022-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-so-you-think-you-can-dance-2008-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-so-you-think-you-can-dance-2008-poster.jpg new file mode 100644 index 00000000..a2e91496 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-so-you-think-you-can-dance-2008-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-south-park-1997-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-south-park-1997-poster.jpg new file mode 100644 index 00000000..d8568d54 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-south-park-1997-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-spy-x-family-2022-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-spy-x-family-2022-poster.jpg new file mode 100644 index 00000000..fc326930 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-spy-x-family-2022-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-the-100-2014-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-the-100-2014-poster.jpg new file mode 100644 index 00000000..4d254cb0 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-the-100-2014-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-the-abbott-and-costello-show-1952-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-the-abbott-and-costello-show-1952-poster.jpg new file mode 100644 index 00000000..7d6768ea Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-the-abbott-and-costello-show-1952-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-the-afterparty-2022-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-the-afterparty-2022-poster.jpg new file mode 100644 index 00000000..9beacde2 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-the-afterparty-2022-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-the-baby-sitters-club-2020-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-the-baby-sitters-club-2020-poster.jpg new file mode 100644 index 00000000..7e4e7be2 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-the-baby-sitters-club-2020-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-the-bear-2022-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-the-bear-2022-poster.jpg new file mode 100644 index 00000000..bbf0ab28 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-the-bear-2022-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-the-beast-in-me-2025-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-the-beast-in-me-2025-poster.jpg new file mode 100644 index 00000000..c78c5cf0 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-the-beast-in-me-2025-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-the-bold-type-2017-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-the-bold-type-2017-poster.jpg new file mode 100644 index 00000000..f663eb8b Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-the-bold-type-2017-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-the-boys-2019-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-the-boys-2019-poster.jpg new file mode 100644 index 00000000..f67ff16f Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-the-boys-2019-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-the-capture-2019-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-the-capture-2019-poster.jpg new file mode 100644 index 00000000..a4039011 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-the-capture-2019-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-the-diplomat-2023-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-the-diplomat-2023-poster.jpg new file mode 100644 index 00000000..2eb48b62 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-the-diplomat-2023-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-the-durrells-2016-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-the-durrells-2016-poster.jpg new file mode 100644 index 00000000..d29448bb Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-the-durrells-2016-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-the-final-problem-2026-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-the-final-problem-2026-poster.jpg new file mode 100644 index 00000000..f0332826 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-the-final-problem-2026-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-the-four-seasons-2025-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-the-four-seasons-2025-poster.jpg new file mode 100644 index 00000000..fd252088 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-the-four-seasons-2025-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-the-get-down-2016-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-the-get-down-2016-poster.jpg new file mode 100644 index 00000000..7bb38abd Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-the-get-down-2016-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-the-hunting-wives-2025-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-the-hunting-wives-2025-poster.jpg new file mode 100644 index 00000000..034273eb Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-the-hunting-wives-2025-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-the-last-of-us-2023-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-the-last-of-us-2023-poster.jpg new file mode 100644 index 00000000..7da462da Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-the-last-of-us-2023-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-the-legend-of-korra-2012-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-the-legend-of-korra-2012-poster.jpg new file mode 100644 index 00000000..a7086d5e Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-the-legend-of-korra-2012-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-the-lord-of-the-rings-the-rings-of-power-2022-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-the-lord-of-the-rings-the-rings-of-power-2022-poster.jpg new file mode 100644 index 00000000..dc387fcd Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-the-lord-of-the-rings-the-rings-of-power-2022-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-the-lost-flowers-of-alice-hart-2023-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-the-lost-flowers-of-alice-hart-2023-poster.jpg new file mode 100644 index 00000000..71407f36 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-the-lost-flowers-of-alice-hart-2023-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-the-night-manager-2016-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-the-night-manager-2016-poster.jpg new file mode 100644 index 00000000..7ab2dbf5 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-the-night-manager-2016-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-the-pitt-2025-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-the-pitt-2025-poster.jpg new file mode 100644 index 00000000..ad1ec8ff Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-the-pitt-2025-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-the-tatami-galaxy-2010-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-the-tatami-galaxy-2010-poster.jpg new file mode 100644 index 00000000..5324dc75 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-the-tatami-galaxy-2010-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-the-walk-in-2022-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-the-walk-in-2022-poster.jpg new file mode 100644 index 00000000..715d0c80 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-the-walk-in-2022-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-the-white-lotus-2021-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-the-white-lotus-2021-poster.jpg new file mode 100644 index 00000000..2f23d1fa Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-the-white-lotus-2021-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-the-witcher-2019-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-the-witcher-2019-poster.jpg new file mode 100644 index 00000000..f5eb8f59 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-the-witcher-2019-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-undercover-2019-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-undercover-2019-poster.jpg new file mode 100644 index 00000000..8611eab4 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-undercover-2019-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-upload-2020-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-upload-2020-poster.jpg new file mode 100644 index 00000000..547d3b7a Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-upload-2020-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-vinland-saga-2019-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-vinland-saga-2019-poster.jpg new file mode 100644 index 00000000..7d0ba17a Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-vinland-saga-2019-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-widow-s-bay-2026-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-widow-s-bay-2026-poster.jpg new file mode 100644 index 00000000..8c02a0d7 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-widow-s-bay-2026-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-yellowjackets-2021-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-yellowjackets-2021-poster.jpg new file mode 100644 index 00000000..c7e16a57 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-yellowjackets-2021-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/library/assets/tv-yu-yu-hakusho-1992-poster.jpg b/wolfskin-design/src/test/resources/library/assets/tv-yu-yu-hakusho-1992-poster.jpg new file mode 100644 index 00000000..f5843766 Binary files /dev/null and b/wolfskin-design/src/test/resources/library/assets/tv-yu-yu-hakusho-1992-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/requests-press-paths.json b/wolfskin-design/src/test/resources/requests-press-paths.json new file mode 100644 index 00000000..5d76c663 --- /dev/null +++ b/wolfskin-design/src/test/resources/requests-press-paths.json @@ -0,0 +1,21 @@ +[ + { + "goal": "Round 4 \u00b7 Home hero \u2192 Requests (Coming in) in Settings", + "keys": [ + "OK", + "UP", + "LEFT", + "OK", + "RIGHT", + "RIGHT", + "DOWN", + "OK", + "OK" + ], + "presses": 9, + "note": "8 from the hero", + "start": "app launch: Who's watching with Justin focused (index.html:357)", + "replayed": "PASS", + "source": "index.html:2152-2174 PRESSES, replayed 2026-11-05" + } +] diff --git a/wolfskin-design/src/test/resources/wolfskin-discover.json b/wolfskin-design/src/test/resources/wolfskin-discover.json new file mode 100644 index 00000000..450f0ece --- /dev/null +++ b/wolfskin-design/src/test/resources/wolfskin-discover.json @@ -0,0 +1 @@ +{"schemaVersion": 1, "generatedAt": "2026-11-04T20:42:12.030108+00:00", "profiles": [{"key": "justin", "name": "Justin", "initial": "J", "color": "#62c4ff", "destinations": {"Home": {"kind": "home"}, "Movies": {"kind": "library", "collection": "movies"}, "Shows": {"kind": "library", "collection": "shows"}, "Anime": {"kind": "library", "collection": "anime"}, "Discover": {"kind": "discover", "collection": "discover"}}, "movies": [{"id": "movie-the-girl-who-leapt-through-time-2006", "title": "The Girl Who Leapt Through Time", "year": 2006, "type": "movie", "runtimeSeconds": 5886, "seasonCount": null, "communityRating": 7.772, "criticRating": 87, "genres": ["Fantasy", "Animation", "Drama"], "overview": "When 17-year-old Makoto Konno gains the ability to 'leap' backwards through time, she immediately sets about improving her grades and preventing personal mishaps. However, she soon realises that changing the past\u2026", "poster": "assets/movie-the-girl-who-leapt-through-time-2006-poster.jpg", "backdrop": "assets/movie-the-girl-who-leapt-through-time-2006-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T17:39:11.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 14069, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 87, "rtCriticsLabel": "Fresh", "rtAudience": 90, "rtAudienceLabel": "Upright", "imdb": 7.6, "imdbVotes": 76917, "tmdb": 7.775, "tmdbVotes": 2345}}, {"id": "movie-locke-2014", "title": "Locke", "year": 2014, "type": "movie", "runtimeSeconds": 5090, "seasonCount": null, "communityRating": 6.891, "criticRating": 91, "genres": ["Drama", "Thriller"], "overview": "Ivan Locke has worked hard to craft a good life for himself. Tonight, that life will collapse around him. On the eve of the biggest challenge of his career, Ivan receives a phone call that sets in motion a series of\u2026", "poster": "assets/movie-locke-2014-poster.jpg", "backdrop": "assets/movie-locke-2014-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T17:38:48.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 210479, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 90, "rtCriticsLabel": "Certified Fresh", "rtAudience": 72, "rtAudienceLabel": "Upright", "imdb": 7.1, "imdbVotes": 171265, "tmdb": 6.889, "tmdbVotes": 3088}}, {"id": "movie-look-who-s-back-2015", "title": "Look Who's Back", "year": 2015, "type": "movie", "runtimeSeconds": 6936, "seasonCount": null, "communityRating": 6.793, "criticRating": null, "genres": ["Comedy"], "overview": "When Adolf Hitler reawakens at the site of his former bunker in present-day Berlin, he is mistaken for a comedian and quickly becomes a media phenomenon.", "poster": "assets/movie-look-who-s-back-2015-poster.jpg", "backdrop": "assets/movie-look-who-s-back-2015-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:27:48.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 318917, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": 81, "rtAudienceLabel": "Upright", "imdb": 7, "imdbVotes": 54672, "tmdb": 6.796, "tmdbVotes": 1990}}, {"id": "movie-memories-1995", "title": "Memories", "year": 1995, "type": "movie", "runtimeSeconds": 6805, "seasonCount": null, "communityRating": 7.465, "criticRating": null, "genres": ["Fantasy", "Animation", "Science Fiction"], "overview": "Three back-to-back anime films by three different directors make up this sci-fi trilogy three years in the making.", "poster": "assets/movie-memories-1995-poster.jpg", "backdrop": "assets/movie-memories-1995-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-30T21:36:03.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 42994, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": 82, "rtAudienceLabel": "Upright", "imdb": 7.5, "imdbVotes": 26638, "tmdb": 7.459, "tmdbVotes": 622}}, {"id": "movie-reincarnated-2012", "title": "Reincarnated", "year": 2012, "type": "movie", "runtimeSeconds": 5759, "seasonCount": null, "communityRating": 6.145, "criticRating": 28, "genres": ["Music", "Documentary"], "overview": "Evolution as an artist is often times what separates legends from the more mundane. After being heavily influenced by his experience in Jamaica \u2013 and his subsequent name change from Snoop Dogg to Snoop Lion \u2013 the LBC\u2026", "poster": "assets/movie-reincarnated-2012-poster.jpg", "backdrop": "assets/movie-reincarnated-2012-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:27:26.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 123431, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 28, "rtCriticsLabel": "Rotten", "rtAudience": 41, "rtAudienceLabel": "Spilled", "imdb": 6.2, "imdbVotes": 2563, "tmdb": 6.1, "tmdbVotes": 69}}, {"id": "movie-shipwrecked-nightmare-at-sea-2026", "title": "Shipwrecked: Nightmare at Sea", "year": 2026, "type": "movie", "runtimeSeconds": 5385, "seasonCount": null, "communityRating": 7.181, "criticRating": null, "genres": ["Documentary"], "overview": "Never-before-seen footage and survivor accounts trace the 2012 shipwreck of a luxury cruise and the disaster that ensued, in this immersive documentary.", "poster": "assets/movie-shipwrecked-nightmare-at-sea-2026-poster.jpg", "backdrop": "assets/movie-shipwrecked-nightmare-at-sea-2026-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-20T20:11:43.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 1715492, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": 6.5, "imdbVotes": 5080, "tmdb": 7.172, "tmdbVotes": 87}}, {"id": "movie-steins-gate-the-movie-load-region-of-deja-vu-2013", "title": "Steins;Gate: The Movie - Load Region of D\u00e9j\u00e0 Vu", "year": 2013, "type": "movie", "runtimeSeconds": 5403, "seasonCount": null, "communityRating": 7.8, "criticRating": null, "genres": ["Animation", "Mystery", "Sci-Fi"], "overview": "After the events of the anime, Rintarou begins to feel the repercussions of extensive time travel, and eventually completely fades from reality. Kurisu, being the only companion to remember him, now must find a way\u2026", "poster": "assets/movie-steins-gate-the-movie-load-region-of-deja-vu-2013-poster.jpg", "backdrop": "assets/movie-steins-gate-the-movie-load-region-of-deja-vu-2013-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-22T14:55:54.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}], "shows": [{"id": "tv-andor-2022", "title": "Andor", "year": 2022, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 8.293, "criticRating": null, "genres": ["Sci-Fi & Fantasy", "Action & Adventure", "Drama"], "overview": "In an era filled with danger, deception and intrigue, Cassian Andor will discover the difference he can make in the struggle against the tyrannical Galactic Empire. He embarks on a path that is destined to turn him\u2026", "poster": "assets/tv-andor-2022-poster.jpg", "backdrop": "assets/tv-andor-2022-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0432996Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 83867, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 96, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.321, "tmdbVotes": 2312}}, {"id": "tv-the-boys-2019", "title": "The Boys", "year": 2019, "type": "tv", "runtimeSeconds": null, "seasonCount": 5, "communityRating": 8.443, "criticRating": null, "genres": ["Sci-Fi & Fantasy", "Action & Adventure"], "overview": "A group of vigilantes known informally as \u201cThe Boys\u201d set out to take down corrupt superheroes with no more than blue-collar grit and a willingness to fight dirty.", "poster": "assets/tv-the-boys-2019-poster.jpg", "backdrop": "assets/tv-the-boys-2019-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0410131Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 76479, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 92, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.4, "tmdbVotes": 13628}}, {"id": "tv-californication-2007", "title": "Californication", "year": 2007, "type": "tv", "runtimeSeconds": 1680, "seasonCount": 7, "communityRating": 7.632, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "A self-loathing, alcoholic writer attempts to repair his damaged relationships with his daughter and her mother while combating sex addiction, a budding drug problem, and the seeming inability to avoid making bad\u2026", "poster": "assets/tv-californication-2007-poster.jpg", "backdrop": "assets/tv-californication-2007-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0428037Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 1215, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 57, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.62, "tmdbVotes": 1406}}, {"id": "tv-firefly-2002", "title": "Firefly", "year": 2002, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 8.347, "criticRating": null, "genres": ["Drama", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "In the year 2517, the universe is a vast frontier where lawlessness reigns and adventure awaits! Join Captain Malcolm Reynolds and his ragtag crew aboard the spaceship Serenity as they navigate the fringes of\u2026", "poster": "assets/tv-firefly-2002-poster.jpg", "backdrop": "assets/tv-firefly-2002-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-20T11:40:08.4202369Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 1437, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 77, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.351, "tmdbVotes": 2550}}, {"id": "tv-fleabag-2016", "title": "Fleabag", "year": 2016, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 8.278, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "A portrait into the mind of a dry-witted, sexual, angry, porn-watching, grief-riddled woman, trying to make sense of the world. As she hurls herself headlong at modern living, Fleabag is thrown roughly up against the\u2026", "poster": "assets/tv-fleabag-2016-poster.jpg", "backdrop": "assets/tv-fleabag-2016-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T17:42:25.4848214Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 67070, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.3, "tmdbVotes": 1993}}, {"id": "tv-gravity-falls-2012", "title": "Gravity Falls", "year": 2012, "type": "tv", "runtimeSeconds": 1320, "seasonCount": 2, "communityRating": 8.619, "criticRating": null, "genres": ["Action & Adventure", "Animation", "Comedy"], "overview": "Twin brother and sister Dipper and Mabel Pines are in for an unexpected adventure when they spend the summer helping their great uncle Stan run a tourist trap in the mysterious town of Gravity Falls, Oregon.", "poster": "assets/tv-gravity-falls-2012-poster.jpg", "backdrop": "assets/tv-gravity-falls-2012-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0435827Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 40075, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.624, "tmdbVotes": 3647}}, {"id": "tv-invincible-2021", "title": "INVINCIBLE", "year": 2021, "type": "tv", "runtimeSeconds": null, "seasonCount": 4, "communityRating": 8.638, "criticRating": null, "genres": ["Animation", "Drama", "Sci-Fi & Fantasy"], "overview": "Mark Grayson is a normal teenager except for the fact that his father is the most powerful superhero on the planet. Shortly after his seventeenth birthday, Mark begins to develop powers of his own and enters into his\u2026", "poster": "assets/tv-invincible-2021-poster.jpg", "backdrop": "assets/tv-invincible-2021-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.040159Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 95557, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 99, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.6, "tmdbVotes": 6155}}, {"id": "tv-the-legend-of-korra-2012", "title": "The Legend of Korra", "year": 2012, "type": "tv", "runtimeSeconds": 1380, "seasonCount": 4, "communityRating": 8.2, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "Avatar Korra, a headstrong, rebellious, feisty young woman who continually challenges and breaks with tradition, is on her quest to become a fully realized Avatar. In this story, the Avatar struggles to find balance\u2026", "poster": "assets/tv-the-legend-of-korra-2012-poster.jpg", "backdrop": "assets/tv-the-legend-of-korra-2012-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-20T00:19:23.2494945Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 33880, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 88, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.221, "tmdbVotes": 2482}}, {"id": "tv-love-death-robots-2019", "title": "Love, Death & Robots", "year": 2019, "type": "tv", "runtimeSeconds": null, "seasonCount": 4, "communityRating": 8.205, "criticRating": null, "genres": ["Animation", "Sci-Fi & Fantasy"], "overview": "Terrifying creatures, wicked surprises and dark comedy converge in this NSFW anthology of animated stories presented by Tim Miller and David Fincher.", "poster": "assets/tv-love-death-robots-2019-poster.jpg", "backdrop": "assets/tv-love-death-robots-2019-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-20T11:31:20.8818757Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 86831, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 89, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.203, "tmdbVotes": 4238}}, {"id": "tv-norsemen-2016", "title": "Norsemen", "year": 2016, "type": "tv", "runtimeSeconds": 1800, "seasonCount": 3, "communityRating": 7.177, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "Norsemen is an epic and humorous drama series set in the Viking Age. The residents of an 8th-century Viking village experience political rivalry, social change and innovations that upend their culture and way of life.", "poster": "assets/tv-norsemen-2016-poster.jpg", "backdrop": "assets/tv-norsemen-2016-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.034182Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 68126, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.2, "tmdbVotes": 233}}, {"id": "tv-rick-and-morty-2013", "title": "Rick and Morty", "year": 2013, "type": "tv", "runtimeSeconds": null, "seasonCount": 9, "communityRating": 8.679, "criticRating": null, "genres": ["Animation", "Comedy", "Sci-Fi & Fantasy"], "overview": "Follows a sociopathic genius scientist who drags his inherently timid grandson on adventures across the universe.", "poster": "assets/tv-rick-and-morty-2013-poster.jpg", "backdrop": "assets/tv-rick-and-morty-2013-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0419581Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 60625, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 91, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.7, "tmdbVotes": 11548}}, {"id": "tv-secret-level-2024", "title": "Secret Level", "year": 2024, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.411, "criticRating": null, "genres": ["Animation", "Sci-Fi & Fantasy", "Action & Adventure"], "overview": "Adult animated series of original short stories which are set within the worlds of beloved video games. Each episode serves as a gateway to a new adventure, unlocking exciting worlds from beloved gaming classics and\u2026", "poster": "assets/tv-secret-level-2024-poster.jpg", "backdrop": "assets/tv-secret-level-2024-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0336417Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 261579, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 65, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.392, "tmdbVotes": 612}}, {"id": "tv-silo-2023", "title": "Silo", "year": 2023, "type": "tv", "runtimeSeconds": null, "seasonCount": 3, "communityRating": 8.178, "criticRating": null, "genres": ["Sci-Fi & Fantasy", "Drama"], "overview": "In a ruined and toxic future, thousands live in a giant silo deep underground. After its sheriff breaks a cardinal rule and residents die mysteriously, engineer Juliette starts to uncover shocking secrets and the\u2026", "poster": "assets/tv-silo-2023-poster.jpg", "backdrop": "assets/tv-silo-2023-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0346526Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 125988, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 92, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.232, "tmdbVotes": 2881}}, {"id": "tv-south-park-1997", "title": "South Park", "year": 1997, "type": "tv", "runtimeSeconds": null, "seasonCount": 29, "communityRating": 8.336, "criticRating": null, "genres": ["Animation", "Comedy"], "overview": "Follow the misadventures of four irreverent grade-schoolers in the quiet, dysfunctional town of South Park, Colorado.", "poster": "assets/tv-south-park-1997-poster.jpg", "backdrop": "assets/tv-south-park-1997-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0456124Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 2190, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 80, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.332, "tmdbVotes": 5250}}], "anime": [{"id": "tv-bleach-2004", "title": "Bleach", "year": 2004, "type": "tv", "runtimeSeconds": 1440, "seasonCount": 17, "communityRating": 8.363, "criticRating": null, "genres": ["Action & Adventure", "Animation", "Sci-Fi & Fantasy"], "overview": "For as long as he can remember, Ichigo Kurosaki has been able to see ghosts. But when he meets Rukia, a Soul Reaper who battles evil spirits known as Hollows, he finds his life is changed forever. Now, with a\u2026", "poster": "assets/tv-bleach-2004-poster.jpg", "backdrop": "assets/tv-bleach-2004-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0359827Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 30984, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.4, "tmdbVotes": 2331}}, {"id": "tv-chainsaw-man-2022", "title": "Chainsaw Man", "year": 2022, "type": "tv", "runtimeSeconds": 1440, "seasonCount": 1, "communityRating": 8.515, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "Denji has a simple dream\u2014to live a happy and peaceful life, spending time with a girl he likes. This is a far cry from reality, however, as Denji is forced by the yakuza into killing devils in order to pay off his\u2026", "poster": "assets/tv-chainsaw-man-2022-poster.jpg", "backdrop": "assets/tv-chainsaw-man-2022-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-20T22:28:13.2095501Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 114410, "artwork": {"posterKind": "center_crop", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 97, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.508, "tmdbVotes": 2364}}, {"id": "tv-cyberpunk-edgerunners-2022", "title": "Cyberpunk: Edgerunners", "year": 2022, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 8.466, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "In a dystopia riddled with corruption and cybernetic implants, a talented but reckless street kid strives to become a mercenary outlaw \u2014 an edgerunner.", "poster": "assets/tv-cyberpunk-edgerunners-2022-poster.jpg", "backdrop": "assets/tv-cyberpunk-edgerunners-2022-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-20T22:28:13.2093107Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 105248, "artwork": {"posterKind": "center_crop", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 89, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.507, "tmdbVotes": 2132}}, {"id": "tv-dan-da-dan-2024", "title": "Dan Da Dan", "year": 2024, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 8.538, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Comedy"], "overview": "In a bet to prove whether ghosts or aliens exist, two high schoolers face terrifying paranormal threats, gain superpowers and maybe even fall in love?!", "poster": "assets/tv-dan-da-dan-2024-poster.jpg", "backdrop": "assets/tv-dan-da-dan-2024-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-22T10:31:16.2652252Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 240411, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.517, "tmdbVotes": 986}}, {"id": "tv-dr-stone-2019", "title": "Dr. STONE", "year": 2019, "type": "tv", "runtimeSeconds": 1440, "seasonCount": 4, "communityRating": 8.541, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Comedy"], "overview": "One fateful day, all of humanity was petrified by a blinding flash of light. After several millennia, high schooler Taiju awakens and finds himself lost in a world of statues. However, he\u2019s not alone! His\u2026", "poster": "assets/tv-dr-stone-2019-poster.jpg", "backdrop": "assets/tv-dr-stone-2019-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-20T22:28:13.2091579Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 86031, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.53, "tmdbVotes": 1814}}, {"id": "tv-frieren-beyond-journey-s-end-2023", "title": "Frieren: Beyond Journey's End", "year": 2023, "type": "tv", "runtimeSeconds": 1500, "seasonCount": 2, "communityRating": 8.803, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Drama"], "overview": "After the party of heroes defeated the Demon King, they restored peace to the land and returned to lives of solitude. Generations pass, and the elven mage Frieren comes face to face with humanity\u2019s mortality. She\u2026", "poster": "assets/tv-frieren-beyond-journey-s-end-2023-poster.jpg", "backdrop": "assets/tv-frieren-beyond-journey-s-end-2023-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-20T22:28:13.2094435Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 209867, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.826, "tmdbVotes": 1016}}, {"id": "tv-fullmetal-alchemist-brotherhood-2009", "title": "Fullmetal Alchemist: Brotherhood", "year": 2009, "type": "tv", "runtimeSeconds": 1500, "seasonCount": 1, "communityRating": 8.7, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "Disregard for alchemy\u2019s laws ripped half of Edward Elric\u2019s limbs from his body and left his brother Alphonse\u2019s soul clinging to a suit of armor. To restore what was lost, the brothers seek the Philosopher\u2019s Stone.\u2026", "poster": "assets/tv-fullmetal-alchemist-brotherhood-2009-poster.jpg", "backdrop": "assets/tv-fullmetal-alchemist-brotherhood-2009-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-20T10:27:12.3573939Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 31911, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.7, "tmdbVotes": 2633}}, {"id": "tv-jujutsu-kaisen-2020", "title": "JUJUTSU KAISEN", "year": 2020, "type": "tv", "runtimeSeconds": 1440, "seasonCount": 3, "communityRating": 8.583, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "Yuji Itadori is a boy with tremendous physical strength, though he lives a completely ordinary high school life. One day, to save a classmate who has been attacked by curses, he eats the finger of Ryomen Sukuna,\u2026", "poster": "assets/tv-jujutsu-kaisen-2020-poster.jpg", "backdrop": "assets/tv-jujutsu-kaisen-2020-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-20T22:28:13.207573Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 95479, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.574, "tmdbVotes": 4735}}, {"id": "tv-kaiju-no-8-2024", "title": "Kaiju No. 8", "year": 2024, "type": "tv", "runtimeSeconds": 1440, "seasonCount": 2, "communityRating": 8.436, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "In a world plagued by creatures known as Kaiju, Kafka Hibino aspired to enlist in The Defense Force. He makes a promise to enlist with his childhood friend, Mina Ashiro. Soon, life takes them in separate ways. While\u2026", "poster": "assets/tv-kaiju-no-8-2024-poster.jpg", "backdrop": "assets/tv-kaiju-no-8-2024-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-22T10:31:16.2646566Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 207468, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.4, "tmdbVotes": 836}}, {"id": "tv-my-hero-academia-2016", "title": "My Hero Academia", "year": 2016, "type": "tv", "runtimeSeconds": 1440, "seasonCount": 8, "communityRating": 8.607, "criticRating": null, "genres": ["Action & Adventure", "Animation", "Sci-Fi & Fantasy"], "overview": "After he saves a bully from a Villain, a normal student is granted a superpower that allows him to attend a high school training academy for Heroes.", "poster": "assets/tv-my-hero-academia-2016-poster.jpg", "backdrop": "assets/tv-my-hero-academia-2016-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-20T22:28:13.2089315Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 65930, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.6, "tmdbVotes": 5426}}, {"id": "tv-neon-genesis-evangelion-1995", "title": "Neon Genesis Evangelion", "year": 1995, "type": "tv", "runtimeSeconds": 1500, "seasonCount": 1, "communityRating": 8.568, "criticRating": null, "genres": ["Sci-Fi & Fantasy", "Animation", "Drama"], "overview": "At the turn of the century, the Angels returned to Earth, seeking to wipe out humanity in an apocalyptic fury. Devastated, mankind's last remnants moved underground to wait for the day when the Angels would come back\u2026", "poster": "assets/tv-neon-genesis-evangelion-1995-poster.jpg", "backdrop": "assets/tv-neon-genesis-evangelion-1995-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0340629Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 890, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.56, "tmdbVotes": 2205}}, {"id": "tv-record-of-ragnarok-2021", "title": "Record of Ragnarok", "year": 2021, "type": "tv", "runtimeSeconds": null, "seasonCount": 3, "communityRating": 8.402, "criticRating": null, "genres": ["Action & Adventure", "Animation", "Sci-Fi & Fantasy"], "overview": "Before eradicating humankind from the world, the gods give them one last chance to prove themselves worthy of survival. Let the Ragnarok battles begin.", "poster": "assets/tv-record-of-ragnarok-2021-poster.jpg", "backdrop": "assets/tv-record-of-ragnarok-2021-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-20T22:28:13.2085766Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 114868, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.403, "tmdbVotes": 1929}}, {"id": "tv-sakamoto-days-2025", "title": "SAKAMOTO DAYS", "year": 2025, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 8.071, "criticRating": null, "genres": ["Animation", "Comedy", "Action & Adventure"], "overview": "Once the greatest hitman of all, Taro Sakamoto retired in the name of love. But when his past catches up, he must fight to protect his beloved family.", "poster": "assets/tv-sakamoto-days-2025-poster.jpg", "backdrop": "assets/tv-sakamoto-days-2025-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-22T10:31:16.266066Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 207332, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.057, "tmdbVotes": 375}}, {"id": "tv-sentenced-to-be-a-hero-2025", "title": "Sentenced to Be a Hero", "year": 2025, "type": "tv", "runtimeSeconds": 1440, "seasonCount": 1, "communityRating": 8.338, "criticRating": null, "genres": ["Animation", "Sci-Fi & Fantasy", "Action & Adventure"], "overview": "In a world where heroism is a punishment, Xylo Forbartz, a condemned goddess killer, battles endless hordes of monstrous abominations as part of Penal Hero Unit 9004. Death is no escape, only a cycle of resurrection\u2026", "poster": "assets/tv-sentenced-to-be-a-hero-2025-poster.jpg", "backdrop": "assets/tv-sentenced-to-be-a-hero-2025-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-22T10:31:16.2666791Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 249907, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.244, "tmdbVotes": 129}}, {"id": "tv-spy-x-family-2022", "title": "SPY x FAMILY", "year": 2022, "type": "tv", "runtimeSeconds": 1440, "seasonCount": 3, "communityRating": 8.506, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Comedy"], "overview": "A spy, an assassin and a telepath come together to pose as a family, each for their own reasons, while hiding their true identities from each other.", "poster": "assets/tv-spy-x-family-2022-poster.jpg", "backdrop": "assets/tv-spy-x-family-2022-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-22T10:31:16.2670364Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 120089, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.5, "tmdbVotes": 2382}}, {"id": "tv-the-tatami-galaxy-2010", "title": "The Tatami Galaxy", "year": 2010, "type": "tv", "runtimeSeconds": 1500, "seasonCount": 2, "communityRating": 8.271, "criticRating": null, "genres": ["Animation", "Comedy", "Drama"], "overview": "When a college dropout stops for a late night bite at a mysterious ramen stand, he crosses paths with a self-proclaimed deity of matrimony. This bizarre meeting sends the young man hurtling through a horrifying\u2026", "poster": "assets/tv-the-tatami-galaxy-2010-poster.jpg", "backdrop": "assets/tv-the-tatami-galaxy-2010-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-18T05:52:51.0023256Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 36243, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.3, "tmdbVotes": 152}}, {"id": "tv-vinland-saga-2019", "title": "Vinland Saga", "year": 2019, "type": "tv", "runtimeSeconds": 1500, "seasonCount": 2, "communityRating": 8.527, "criticRating": null, "genres": ["Animation", "War & Politics", "Action & Adventure"], "overview": "For a thousand years, the Vikings have made quite a name and reputation for themselves as the strongest families with a thirst for violence. Thorfinn, the son of one of the Vikings' greatest warriors, spends his\u2026", "poster": "assets/tv-vinland-saga-2019-poster.jpg", "backdrop": "assets/tv-vinland-saga-2019-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-20T22:28:13.207389Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 88803, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.509, "tmdbVotes": 1064}}, {"id": "tv-yu-yu-hakusho-1992", "title": "Yu Yu Hakusho", "year": 1992, "type": "tv", "runtimeSeconds": 1440, "seasonCount": 4, "communityRating": 8.5, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "After dying to save a boy, delinquent tough guy Yusuke Urameshi is granted another chance at life by redeeming himself as a \"Spirit Detective.\"", "poster": "assets/tv-yu-yu-hakusho-1992-poster.jpg", "backdrop": "assets/tv-yu-yu-hakusho-1992-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-19T21:46:01.5733049Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 30669, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.475, "tmdbVotes": 519}}], "resume": [], "nextUp": [{"id": "episode-three-monsters-1992-s1e6", "title": "Three Monsters", "year": 1992, "type": "episode", "runtimeSeconds": 1421, "seasonCount": null, "communityRating": 7.4, "criticRating": null, "genres": ["Animation", "Action", "Adventure"], "overview": "Yusuke receives his first real case as Spirit Detective. Three demon thieves have muscled their way into King Yama's sacred vault, stealing the three Artifacts of Darkness. Yusuke must recover the artifacts and bring\u2026", "poster": "assets/episode-three-monsters-1992-s1e6-poster.jpg", "backdrop": "assets/episode-three-monsters-1992-s1e6-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-19T21:59:21.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "Yu Yu Hakusho", "seasonNumber": 1, "episodeNumber": 6, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}, {"id": "episode-all-hands-on-deck-class-1-a-2021-s5e1", "title": "All Hands on Deck! Class 1-A", "year": 2021, "type": "episode", "runtimeSeconds": 1433, "seasonCount": null, "communityRating": 6.938, "criticRating": null, "genres": ["Animation", "Action", "Adventure"], "overview": "There's an emergency drill at U.A. High School, and Class 1-A is requested to report for duty!", "poster": "assets/episode-all-hands-on-deck-class-1-a-2021-s5e1-poster.jpg", "backdrop": "assets/episode-all-hands-on-deck-class-1-a-2021-s5e1-backdrop.jpg", "played": false, "playCount": 2, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-22T04:04:50.0000000Z", "lastPlayedAt": "2026-10-19T17:47:09.3028025Z", "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "My Hero Academia", "seasonNumber": 5, "episodeNumber": 1, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}, {"id": "episode-erickerhead-2026-s9e6", "title": "Erickerhead", "year": 2026, "type": "episode", "runtimeSeconds": 1357, "seasonCount": null, "communityRating": 8.196, "criticRating": null, "genres": [], "overview": "Rick's stomach is mad, broh. But it's all-you-can-eat-and-drink here, broh!", "poster": "assets/episode-erickerhead-2026-s9e6-poster.jpg", "backdrop": "assets/episode-erickerhead-2026-s9e6-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-28T10:23:23.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "Rick and Morty", "seasonNumber": 9, "episodeNumber": 6, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}, {"id": "episode-girls-interrupted-2007-s1e7", "title": "Girls, Interrupted", "year": 2007, "type": "episode", "runtimeSeconds": 1642, "seasonCount": null, "communityRating": 7.4, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "Hank is disturbed by Becca's negative reaction towards the concept of happy endings, even more so when he finds out that it is partially his fault.\nMarcy comes up with the idea of a threesome with Charlie and Dani,\u2026", "poster": "assets/episode-girls-interrupted-2007-s1e7-poster.jpg", "backdrop": "assets/episode-girls-interrupted-2007-s1e7-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-05T02:46:18.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "Californication", "seasonNumber": 1, "episodeNumber": 7, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}, {"id": "episode-announcement-2022-s1e7", "title": "Announcement", "year": 2022, "type": "episode", "runtimeSeconds": 3012, "seasonCount": null, "communityRating": 7.8, "criticRating": null, "genres": ["Action", "Adventure", "Drama"], "overview": "The repercussions of the Aldhani heist reach all the way to Coruscant, while Cassian returns home.", "poster": "assets/episode-announcement-2022-s1e7-poster.jpg", "backdrop": "assets/episode-announcement-2022-s1e7-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T12:56:24.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "Andor", "seasonNumber": 1, "episodeNumber": 7, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}, {"id": "episode-south-american-biker-gangs-2026-s29e1", "title": "South American Biker Gangs", "year": 2026, "type": "episode", "runtimeSeconds": 1335, "seasonCount": null, "communityRating": 6.4, "criticRating": null, "genres": ["Animation", "Comedy"], "overview": "When e-bikes arrive in South America, the boys take over the streets and the parents of South America can hardly recognize South America.", "poster": "assets/episode-south-american-biker-gangs-2026-s29e1-poster.jpg", "backdrop": "assets/episode-south-american-biker-gangs-2026-s29e1-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-01T06:40:46.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "South Park", "seasonNumber": 29, "episodeNumber": 1, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}], "recentlyAdded": [{"id": "movie-steins-gate-the-movie-load-region-of-deja-vu-2013", "title": "Steins;Gate: The Movie - Load Region of D\u00e9j\u00e0 Vu", "year": 2013, "type": "movie", "runtimeSeconds": 5403, "seasonCount": null, "communityRating": 7.8, "criticRating": null, "genres": ["Animation", "Mystery", "Sci-Fi"], "overview": "After the events of the anime, Rintarou begins to feel the repercussions of extensive time travel, and eventually completely fades from reality. Kurisu, being the only companion to remember him, now must find a way\u2026", "poster": "assets/movie-steins-gate-the-movie-load-region-of-deja-vu-2013-poster.jpg", "backdrop": "assets/movie-steins-gate-the-movie-load-region-of-deja-vu-2013-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-22T14:55:54.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}, {"id": "tv-yu-yu-hakusho-1992", "title": "Yu Yu Hakusho", "year": 1992, "type": "tv", "runtimeSeconds": 1440, "seasonCount": 4, "communityRating": 8.5, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "After dying to save a boy, delinquent tough guy Yusuke Urameshi is granted another chance at life by redeeming himself as a \"Spirit Detective.\"", "poster": "assets/tv-yu-yu-hakusho-1992-poster.jpg", "backdrop": "assets/tv-yu-yu-hakusho-1992-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-19T21:46:01.5733049Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 30669, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.475, "tmdbVotes": 519}}, {"id": "movie-memories-1995", "title": "Memories", "year": 1995, "type": "movie", "runtimeSeconds": 6805, "seasonCount": null, "communityRating": 7.465, "criticRating": null, "genres": ["Fantasy", "Animation", "Science Fiction"], "overview": "Three back-to-back anime films by three different directors make up this sci-fi trilogy three years in the making.", "poster": "assets/movie-memories-1995-poster.jpg", "backdrop": "assets/movie-memories-1995-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-30T21:36:03.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 42994, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": 82, "rtAudienceLabel": "Upright", "imdb": 7.5, "imdbVotes": 26638, "tmdb": 7.459, "tmdbVotes": 622}}, {"id": "tv-firefly-2002", "title": "Firefly", "year": 2002, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 8.347, "criticRating": null, "genres": ["Drama", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "In the year 2517, the universe is a vast frontier where lawlessness reigns and adventure awaits! Join Captain Malcolm Reynolds and his ragtag crew aboard the spaceship Serenity as they navigate the fringes of\u2026", "poster": "assets/tv-firefly-2002-poster.jpg", "backdrop": "assets/tv-firefly-2002-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-20T11:40:08.4202369Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 1437, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 77, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.351, "tmdbVotes": 2550}}, {"id": "tv-love-death-robots-2019", "title": "Love, Death & Robots", "year": 2019, "type": "tv", "runtimeSeconds": null, "seasonCount": 4, "communityRating": 8.205, "criticRating": null, "genres": ["Animation", "Sci-Fi & Fantasy"], "overview": "Terrifying creatures, wicked surprises and dark comedy converge in this NSFW anthology of animated stories presented by Tim Miller and David Fincher.", "poster": "assets/tv-love-death-robots-2019-poster.jpg", "backdrop": "assets/tv-love-death-robots-2019-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-20T11:31:20.8818757Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 86831, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 89, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.203, "tmdbVotes": 4238}}, {"id": "tv-the-legend-of-korra-2012", "title": "The Legend of Korra", "year": 2012, "type": "tv", "runtimeSeconds": 1380, "seasonCount": 4, "communityRating": 8.2, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "Avatar Korra, a headstrong, rebellious, feisty young woman who continually challenges and breaks with tradition, is on her quest to become a fully realized Avatar. In this story, the Avatar struggles to find balance\u2026", "poster": "assets/tv-the-legend-of-korra-2012-poster.jpg", "backdrop": "assets/tv-the-legend-of-korra-2012-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-20T00:19:23.2494945Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 33880, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 88, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.221, "tmdbVotes": 2482}}, {"id": "tv-spy-x-family-2022", "title": "SPY x FAMILY", "year": 2022, "type": "tv", "runtimeSeconds": 1440, "seasonCount": 3, "communityRating": 8.506, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Comedy"], "overview": "A spy, an assassin and a telepath come together to pose as a family, each for their own reasons, while hiding their true identities from each other.", "poster": "assets/tv-spy-x-family-2022-poster.jpg", "backdrop": "assets/tv-spy-x-family-2022-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-22T10:31:16.2670364Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 120089, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.5, "tmdbVotes": 2382}}, {"id": "tv-sentenced-to-be-a-hero-2025", "title": "Sentenced to Be a Hero", "year": 2025, "type": "tv", "runtimeSeconds": 1440, "seasonCount": 1, "communityRating": 8.338, "criticRating": null, "genres": ["Animation", "Sci-Fi & Fantasy", "Action & Adventure"], "overview": "In a world where heroism is a punishment, Xylo Forbartz, a condemned goddess killer, battles endless hordes of monstrous abominations as part of Penal Hero Unit 9004. Death is no escape, only a cycle of resurrection\u2026", "poster": "assets/tv-sentenced-to-be-a-hero-2025-poster.jpg", "backdrop": "assets/tv-sentenced-to-be-a-hero-2025-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-22T10:31:16.2666791Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 249907, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.244, "tmdbVotes": 129}}, {"id": "tv-sakamoto-days-2025", "title": "SAKAMOTO DAYS", "year": 2025, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 8.071, "criticRating": null, "genres": ["Animation", "Comedy", "Action & Adventure"], "overview": "Once the greatest hitman of all, Taro Sakamoto retired in the name of love. But when his past catches up, he must fight to protect his beloved family.", "poster": "assets/tv-sakamoto-days-2025-poster.jpg", "backdrop": "assets/tv-sakamoto-days-2025-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-22T10:31:16.266066Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 207332, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.057, "tmdbVotes": 375}}, {"id": "tv-dan-da-dan-2024", "title": "Dan Da Dan", "year": 2024, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 8.538, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Comedy"], "overview": "In a bet to prove whether ghosts or aliens exist, two high schoolers face terrifying paranormal threats, gain superpowers and maybe even fall in love?!", "poster": "assets/tv-dan-da-dan-2024-poster.jpg", "backdrop": "assets/tv-dan-da-dan-2024-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-22T10:31:16.2652252Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 240411, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.517, "tmdbVotes": 986}}, {"id": "tv-kaiju-no-8-2024", "title": "Kaiju No. 8", "year": 2024, "type": "tv", "runtimeSeconds": 1440, "seasonCount": 2, "communityRating": 8.436, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "In a world plagued by creatures known as Kaiju, Kafka Hibino aspired to enlist in The Defense Force. He makes a promise to enlist with his childhood friend, Mina Ashiro. Soon, life takes them in separate ways. While\u2026", "poster": "assets/tv-kaiju-no-8-2024-poster.jpg", "backdrop": "assets/tv-kaiju-no-8-2024-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-22T10:31:16.2646566Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 207468, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.4, "tmdbVotes": 836}}, {"id": "tv-chainsaw-man-2022", "title": "Chainsaw Man", "year": 2022, "type": "tv", "runtimeSeconds": 1440, "seasonCount": 1, "communityRating": 8.515, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "Denji has a simple dream\u2014to live a happy and peaceful life, spending time with a girl he likes. This is a far cry from reality, however, as Denji is forced by the yakuza into killing devils in order to pay off his\u2026", "poster": "assets/tv-chainsaw-man-2022-poster.jpg", "backdrop": "assets/tv-chainsaw-man-2022-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-20T22:28:13.2095501Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 114410, "artwork": {"posterKind": "center_crop", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 97, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.508, "tmdbVotes": 2364}}], "discover": [{"id": "movie-the-amazing-spider-man-2012", "title": "The Amazing Spider-Man", "year": 2012, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action", "Adventure", "Science Fiction"], "overview": "A teenage Peter Parker grapples with both high school and amazing super-human crises as his alter-ego Spider-Man.", "poster": "assets/movie-the-amazing-spider-man-2012-poster.jpg", "backdrop": "assets/movie-the-amazing-spider-man-2012-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 1930, "ratings": {"rtCritics": 71, "rtCriticsLabel": "Certified Fresh", "rtAudience": 77, "rtAudienceLabel": "Upright", "imdb": 7, "imdbVotes": 791938, "tmdb": 6.768, "tmdbVotes": 19312}}, {"id": "movie-the-amazing-spider-man-2-2014", "title": "The Amazing Spider-Man 2", "year": 2014, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action", "Adventure", "Science Fiction"], "overview": "For Peter Parker, life is busy. Between taking out the bad guys as Spider-Man and spending time with the person he loves, Gwen Stacy, high school graduation cannot come quickly enough. Peter has not forgotten about\u2026", "poster": "assets/movie-the-amazing-spider-man-2-2014-poster.jpg", "backdrop": "assets/movie-the-amazing-spider-man-2-2014-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 102382, "ratings": {"rtCritics": 51, "rtCriticsLabel": "Rotten", "rtAudience": 64, "rtAudienceLabel": "Upright", "imdb": 6.6, "imdbVotes": 611981, "tmdb": 6.567, "tmdbVotes": 14919}}, {"id": "movie-the-animatrix-2003", "title": "The Animatrix", "year": 2003, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Animation", "Science Fiction"], "overview": "Straight from the creators of the groundbreaking Matrix trilogy, this collection of short animated films from the world's leading anime directors fuses computer graphics and Japanese anime to provide the background\u2026", "poster": "assets/movie-the-animatrix-2003-poster.jpg", "backdrop": "assets/movie-the-animatrix-2003-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 55931, "ratings": {"rtCritics": 86, "rtCriticsLabel": "Fresh", "rtAudience": 78, "rtAudienceLabel": "Upright", "imdb": 7.3, "imdbVotes": 91929, "tmdb": 7.221, "tmdbVotes": 1872}}, {"id": "movie-ant-man-and-the-wasp-quantumania-2023", "title": "Ant-Man and the Wasp: Quantumania", "year": 2023, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action", "Adventure", "Science Fiction"], "overview": "Super-Hero partners Scott Lang and Hope van Dyne, along with with Hope's parents Janet van Dyne and Hank Pym, and Scott's daughter Cassie Lang, find themselves exploring the Quantum Realm, interacting with strange\u2026", "poster": "assets/movie-ant-man-and-the-wasp-quantumania-2023-poster.jpg", "backdrop": "assets/movie-ant-man-and-the-wasp-quantumania-2023-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 640146, "ratings": {"rtCritics": 46, "rtCriticsLabel": "Rotten", "rtAudience": 81, "rtAudienceLabel": "Upright", "imdb": 6, "imdbVotes": 281738, "tmdb": 6.197, "tmdbVotes": 6236}}, {"id": "movie-appleseed-alpha-2014", "title": "Appleseed Alpha", "year": 2014, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Animation", "Science Fiction", "Action"], "overview": "The Third World War (2099\u20132126) devastated part of the Earth. Former nations are reforming while new powers emerge, and groups of humans struggle to survive in ruined cities. The story follows Deunan Knute and her\u2026", "poster": "assets/movie-appleseed-alpha-2014-poster.jpg", "backdrop": "assets/movie-appleseed-alpha-2014-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "center_crop", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 269650, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": 59, "rtAudienceLabel": "Spilled", "imdb": 6.5, "imdbVotes": 9689, "tmdb": 6.808, "tmdbVotes": 436}}, {"id": "movie-aquaman-and-the-lost-kingdom-2023", "title": "Aquaman and the Lost Kingdom", "year": 2023, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action", "Adventure", "Fantasy"], "overview": "Black Manta seeks revenge on Aquaman for his father's death. Wielding the Black Trident's power, he becomes a formidable foe. To defend Atlantis, Arthur (Aquaman) forges an alliance with his imprisoned brother. They\u2026", "poster": "assets/movie-aquaman-and-the-lost-kingdom-2023-poster.jpg", "backdrop": "assets/movie-aquaman-and-the-lost-kingdom-2023-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 572802, "ratings": {"rtCritics": 33, "rtCriticsLabel": "Rotten", "rtAudience": 79, "rtAudienceLabel": "Upright", "imdb": 5.6, "imdbVotes": 122422, "tmdb": 6.48, "tmdbVotes": 3748}}, {"id": "movie-the-avengers-2012", "title": "The Avengers", "year": 2012, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Science Fiction", "Action", "Adventure"], "overview": "When an unexpected enemy emerges and threatens global safety and security, Nick Fury, director of the international peacekeeping agency known as S.H.I.E.L.D., finds himself in need of a team to pull the world back\u2026", "poster": "assets/movie-the-avengers-2012-poster.jpg", "backdrop": "assets/movie-the-avengers-2012-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 24428, "ratings": {"rtCritics": 91, "rtCriticsLabel": "Certified Fresh", "rtAudience": 91, "rtAudienceLabel": "Upright", "imdb": 8, "imdbVotes": 1590693, "tmdb": 8.084, "tmdbVotes": 40262}}, {"id": "movie-avengers-confidential-black-widow-punisher-2014", "title": "Avengers Confidential: Black Widow & Punisher", "year": 2014, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Animation", "Science Fiction", "Action"], "overview": "When the Punisher takes out a black-market weapons dealer, he stumbles upon a far-reaching terrorist plot devised by a group known as Leviathan.", "poster": "assets/movie-avengers-confidential-black-widow-punisher-2014-poster.jpg", "backdrop": "assets/movie-avengers-confidential-black-widow-punisher-2014-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 257346, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": 55, "rtAudienceLabel": "Spilled", "imdb": 5.7, "imdbVotes": 5166, "tmdb": 6.368, "tmdbVotes": 303}}, {"id": "movie-avengers-age-of-ultron-2015", "title": "Avengers: Age of Ultron", "year": 2015, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action", "Adventure", "Science Fiction"], "overview": "When Tony Stark tries to jumpstart a dormant peacekeeping program, things go awry and Earth\u2019s Mightiest Heroes are put to the ultimate test as the fate of the planet hangs in the balance. As the villainous Ultron\u2026", "poster": "assets/movie-avengers-age-of-ultron-2015-poster.jpg", "backdrop": "assets/movie-avengers-age-of-ultron-2015-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 99861, "ratings": {"rtCritics": 75, "rtCriticsLabel": "Certified Fresh", "rtAudience": 82, "rtAudienceLabel": "Upright", "imdb": 7.3, "imdbVotes": 1025876, "tmdb": 7.278, "tmdbVotes": 25289}}, {"id": "movie-avengers-infinity-war-2018", "title": "Avengers: Infinity War", "year": 2018, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Adventure", "Action", "Science Fiction"], "overview": "As the Avengers and their allies have continued to protect the world from threats too large for any one hero to handle, a new danger has emerged from the cosmic shadows: Thanos. A despot of intergalactic infamy, his\u2026", "poster": "assets/movie-avengers-infinity-war-2018-poster.jpg", "backdrop": "assets/movie-avengers-infinity-war-2018-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 299536, "ratings": {"rtCritics": 85, "rtCriticsLabel": "Certified Fresh", "rtAudience": 92, "rtAudienceLabel": "Upright", "imdb": 8.4, "imdbVotes": 1421954, "tmdb": 8.246, "tmdbVotes": 33331}}, {"id": "movie-batman-ninja-2018", "title": "Batman Ninja", "year": 2018, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Animation", "Action", "Science Fiction"], "overview": "Batman, along with many of his allies and adversaries, finds himself transported to feudal Japan by Gorilla Grodd's time displacement machine.", "poster": "assets/movie-batman-ninja-2018-poster.jpg", "backdrop": "assets/movie-batman-ninja-2018-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 485942, "ratings": {"rtCritics": 84, "rtCriticsLabel": "Fresh", "rtAudience": 60, "rtAudienceLabel": "Upright", "imdb": 5.6, "imdbVotes": 24579, "tmdb": 5.9, "tmdbVotes": 1106}}, {"id": "movie-batman-v-superman-dawn-of-justice-2016", "title": "Batman v Superman: Dawn of Justice", "year": 2016, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action", "Adventure", "Fantasy"], "overview": "Fearing the actions of a god-like Super Hero left unchecked, Gotham City\u2019s own formidable, forceful vigilante takes on Metropolis\u2019s most revered, modern-day savior, while the world wrestles with what sort of hero it\u2026", "poster": "assets/movie-batman-v-superman-dawn-of-justice-2016-poster.jpg", "backdrop": "assets/movie-batman-v-superman-dawn-of-justice-2016-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 209112, "ratings": {"rtCritics": 28, "rtCriticsLabel": "Rotten", "rtAudience": 63, "rtAudienceLabel": "Upright", "imdb": 6.4, "imdbVotes": 801382, "tmdb": 6.014, "tmdbVotes": 19527}}, {"id": "movie-batman-the-dark-knight-returns-part-1-2012", "title": "Batman: The Dark Knight Returns, Part 1", "year": 2012, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Science Fiction", "Action", "Animation"], "overview": "Batman has not been seen for ten years. A new breed of criminal ravages Gotham City, forcing 55-year-old Bruce Wayne back into the cape and cowl. But, does he still have what it takes to fight crime in a new era?", "poster": "assets/movie-batman-the-dark-knight-returns-part-1-2012-poster.jpg", "backdrop": "assets/movie-batman-the-dark-knight-returns-part-1-2012-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 123025, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": 93, "rtAudienceLabel": "Upright", "imdb": 7.9, "imdbVotes": 68943, "tmdb": 7.742, "tmdbVotes": 1766}}, {"id": "movie-black-adam-2022", "title": "Black Adam", "year": 2022, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action", "Adventure", "Science Fiction"], "overview": "Nearly 5,000 years after he was bestowed with the almighty powers of the Egyptian gods\u2014and imprisoned just as quickly\u2014Black Adam is freed from his earthly tomb, ready to unleash his unique form of justice on the\u2026", "poster": "assets/movie-black-adam-2022-poster.jpg", "backdrop": "assets/movie-black-adam-2022-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 436270, "ratings": {"rtCritics": 39, "rtCriticsLabel": "Rotten", "rtAudience": 87, "rtAudienceLabel": "Upright", "imdb": 6.1, "imdbVotes": 309624, "tmdb": 6.747, "tmdbVotes": 7370}}, {"id": "movie-black-panther-2018", "title": "Black Panther", "year": 2018, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action", "Adventure", "Science Fiction"], "overview": "King T'Challa returns home to the reclusive, technologically advanced African nation of Wakanda to serve as his country's new leader. However, T'Challa soon finds that he is challenged for the throne by factions\u2026", "poster": "assets/movie-black-panther-2018-poster.jpg", "backdrop": "assets/movie-black-panther-2018-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 284054, "ratings": {"rtCritics": 96, "rtCriticsLabel": "Certified Fresh", "rtAudience": null, "rtAudienceLabel": "Spilled", "imdb": 7.3, "imdbVotes": 931120, "tmdb": 7.36, "tmdbVotes": 24190}}, {"id": "movie-black-panther-wakanda-forever-2022", "title": "Black Panther: Wakanda Forever", "year": 2022, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action", "Adventure", "Science Fiction"], "overview": "Queen Ramonda, Shuri, M\u2019Baku, Okoye and the Dora Milaje fight to protect their nation from intervening world powers in the wake of King T\u2019Challa\u2019s death. As the Wakandans strive to embrace their next chapter, the\u2026", "poster": "assets/movie-black-panther-wakanda-forever-2022-poster.jpg", "backdrop": "assets/movie-black-panther-wakanda-forever-2022-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 505642, "ratings": {"rtCritics": 84, "rtCriticsLabel": "Certified Fresh", "rtAudience": 93, "rtAudienceLabel": "Upright", "imdb": 6.6, "imdbVotes": 405088, "tmdb": 6.984, "tmdbVotes": 7920}}, {"id": "movie-blame-2017", "title": "BLAME!", "year": 2017, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action", "Drama", "Science Fiction"], "overview": "In the distant technological future, civilization has reached its ultimate Net-based form. An \"infection\" in the past caused the automated systems to spiral out of order, resulting in a multi-leveled city structure\u2026", "poster": "assets/movie-blame-2017-poster.jpg", "backdrop": "assets/movie-blame-2017-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 409421, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": 61, "rtAudienceLabel": "Upright", "imdb": 6.6, "imdbVotes": 10258, "tmdb": 6.523, "tmdbVotes": 370}}, {"id": "movie-bleach-the-movie-fade-to-black-2008", "title": "Bleach the Movie: Fade to Black", "year": 2008, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action", "Animation", "Fantasy"], "overview": "A strange disturbance in the World of the Living sends Ichigo and Kon to the Soul Society, where the Seireitei has been devastated by an explosion of reishi and Rukia is missing. Stranger still, none of the Soul\u2026", "poster": "assets/movie-bleach-the-movie-fade-to-black-2008-poster.jpg", "backdrop": "assets/movie-bleach-the-movie-fade-to-black-2008-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 17165, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": 67, "rtAudienceLabel": "Upright", "imdb": 7.1, "imdbVotes": 3693, "tmdb": 7.1, "tmdbVotes": 206}}, {"id": "tv-90-day-fiance-before-the-90-days-2017", "title": "90 Day Fianc\u00e9: Before the 90 Days", "year": 2017, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Reality"], "overview": "Follow couples who have an existing relationship online, but haven't met in person. We'll experience their journey as they travel to the other's foreign country for the first time in an attempt to establish an\u2026", "poster": "assets/tv-90-day-fiance-before-the-90-days-2017-poster.jpg", "backdrop": "assets/tv-90-day-fiance-before-the-90-days-2017-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 73319, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.5, "tmdbVotes": 45}}, {"id": "tv-90-day-fiance-the-other-way-2019", "title": "90 Day Fianc\u00e9: The Other Way", "year": 2019, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Reality"], "overview": "Americans move to a foreign country all in the name of love. Will uprooting their lives in the United States pay off, or will they be packing up and moving back to America brokenhearted?", "poster": "assets/tv-90-day-fiance-the-other-way-2019-poster.jpg", "backdrop": "assets/tv-90-day-fiance-the-other-way-2019-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 90046, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.8, "tmdbVotes": 34}}, {"id": "tv-the-100-2014", "title": "The 100", "year": 2014, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Sci-Fi & Fantasy", "Action & Adventure", "Drama"], "overview": "100 years in the future, when the Earth has been abandoned due to radioactivity, the last surviving humans live on an ark orbiting the planet \u2014 but the ark won't last forever. So the repressive regime picks 100\u2026", "poster": "assets/tv-the-100-2014-poster.jpg", "backdrop": "assets/tv-the-100-2014-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 48866, "ratings": {"rtCritics": 93, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.878, "tmdbVotes": 8855}}, {"id": "tv-the-abbott-and-costello-show-1952", "title": "The Abbott and Costello Show", "year": 1952, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Comedy"], "overview": "Bud and Lou are unemployed actors living in Mr. Fields\u2019 boarding house. Lou\u2019s girlfriend Hillary lives across the hall. Many situations arise leading to slapstick and puns.", "poster": "assets/tv-the-abbott-and-costello-show-1952-poster.jpg", "backdrop": "assets/tv-the-abbott-and-costello-show-1952-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 11821, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.2, "tmdbVotes": 22}}, {"id": "tv-accel-world-2012", "title": "Accel World", "year": 2012, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Drama"], "overview": "A short, overweight student uses the Neuro Link, an evolution of the Nerve Gear, to escape himself from the reality. But his skills in the virtual world brings him to the attention of Kuroyukihime, a popular student\u2026", "poster": "assets/tv-accel-world-2012-poster.jpg", "backdrop": "assets/tv-accel-world-2012-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "center_crop", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 43167, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.429, "tmdbVotes": 163}}, {"id": "tv-ahsoka-2023", "title": "Ahsoka", "year": 2023, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Sci-Fi & Fantasy", "Action & Adventure", "Drama"], "overview": "Former Jedi Knight Ahsoka Tano investigates an emerging threat to a vulnerable galaxy.", "poster": "assets/tv-ahsoka-2023-poster.jpg", "backdrop": "assets/tv-ahsoka-2023-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 114461, "ratings": {"rtCritics": 85, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.4, "tmdbVotes": 1351}}, {"id": "tv-american-dad-2005", "title": "American Dad!", "year": 2005, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Animation", "Comedy"], "overview": "The series focuses on an eccentric motley crew that is the Smith family and their three housemates: Father, husband, and breadwinner Stan Smith; his better half housewife, Francine Smith; their college-aged daughter,\u2026", "poster": "assets/tv-american-dad-2005-poster.jpg", "backdrop": "assets/tv-american-dad-2005-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 1433, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.022, "tmdbVotes": 2481}}, {"id": "tv-american-gods-2017", "title": "American Gods", "year": 2017, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Mystery", "Sci-Fi & Fantasy"], "overview": "An ex-con becomes the traveling partner of a conman who turns out to be one of the older gods trying to recruit troops to battle the upstart deities. Based on Neil Gaiman's fantasy novel.", "poster": "assets/tv-american-gods-2017-poster.jpg", "backdrop": "assets/tv-american-gods-2017-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 46639, "ratings": {"rtCritics": 75, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.1, "tmdbVotes": 1852}}, {"id": "tv-andromeda-2000", "title": "Andromeda", "year": 2000, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action & Adventure", "Drama", "Sci-Fi & Fantasy"], "overview": "Captain Dylan Hunt and his crew quest to restore a government that once presided over an extended peace and prosperity.", "poster": "assets/tv-andromeda-2000-poster.jpg", "backdrop": "assets/tv-andromeda-2000-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 2985, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.068, "tmdbVotes": 315}}, {"id": "tv-aqua-teen-hunger-force-2000", "title": "Aqua Teen Hunger Force", "year": 2000, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Animation", "Comedy"], "overview": "The surreal adventures of three anthropomorphic fast food items: Master Shake, Frylock and Meatwad, and their human nextdoor neighbor, Carl Brutananadilewski.", "poster": "assets/tv-aqua-teen-hunger-force-2000-poster.jpg", "backdrop": "assets/tv-aqua-teen-hunger-force-2000-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 251, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.5, "tmdbVotes": 272}}, {"id": "tv-arifureta-from-commonplace-to-world-s-strongest-2019", "title": "Arifureta: From Commonplace to World's Strongest", "year": 2019, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "Hajime Nagumo and his high school class are suddenly summoned to a fantastical land as heroes. But while most of his classmates have powerful stats and abilities, Hajime does not. Underappreciated and unprepared, he\u2026", "poster": "assets/tv-arifureta-from-commonplace-to-world-s-strongest-2019-poster.jpg", "backdrop": "assets/tv-arifureta-from-commonplace-to-world-s-strongest-2019-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 86034, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.382, "tmdbVotes": 662}}, {"id": "tv-arrow-2012", "title": "Arrow", "year": 2012, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Crime", "Drama", "Action & Adventure"], "overview": "Spoiled billionaire playboy Oliver Queen is missing and presumed dead when his yacht is lost at sea. He returns five years later a changed man, determined to clean up the city as a hooded vigilante armed with a bow.", "poster": "assets/tv-arrow-2012-poster.jpg", "backdrop": "assets/tv-arrow-2012-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 1412, "ratings": {"rtCritics": 86, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.834, "tmdbVotes": 6537}}, {"id": "tv-avatar-the-last-airbender-2024", "title": "Avatar: The Last Airbender", "year": 2024, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action & Adventure", "Sci-Fi & Fantasy", "Drama"], "overview": "A young boy known as the Avatar must master the four elemental powers to save a world at war \u2014 and fight a ruthless enemy bent on stopping him.", "poster": "assets/tv-avatar-the-last-airbender-2024-poster.jpg", "backdrop": "assets/tv-avatar-the-last-airbender-2024-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 82452, "ratings": {"rtCritics": 66, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.8, "tmdbVotes": 1406}}, {"id": "tv-avatar-seven-havens-2026", "title": "Avatar: Seven Havens", "year": 2026, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "In a world shattered by a devastating cataclysm, a young Earthbender discovers she's the new Avatar after Korra. But in this dangerous era, that title marks her as humanity's destroyer, not its savior. Hunted by both\u2026", "poster": "assets/tv-avatar-seven-havens-2026-poster.jpg", "backdrop": "assets/tv-avatar-seven-havens-2026-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 284833, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.9, "tmdbVotes": 183}}, {"id": "tv-batman-the-brave-and-the-bold-2008", "title": "Batman: The Brave and the Bold", "year": 2008, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "The Caped Crusader is teamed up with Blue Beetle, Green Arrow, Aquaman and countless others in his quest to uphold justice.", "poster": "assets/tv-batman-the-brave-and-the-bold-2008-poster.jpg", "backdrop": "assets/tv-batman-the-brave-and-the-bold-2008-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 15804, "ratings": {"rtCritics": 96, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.6, "tmdbVotes": 295}}, {"id": "tv-batwoman-2019", "title": "Batwoman", "year": 2019, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Sci-Fi & Fantasy", "Action & Adventure"], "overview": "Kate Kane, armed with a passion for social justice and a flair for speaking her mind, soars onto the streets of Gotham as Batwoman, an out lesbian and highly trained street fighter primed to snuff out the failing\u2026", "poster": "assets/tv-batwoman-2019-poster.jpg", "backdrop": "assets/tv-batwoman-2019-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 89247, "ratings": {"rtCritics": 83, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.8, "tmdbVotes": 1619}}, {"id": "tv-big-mouth-2017", "title": "Big Mouth", "year": 2017, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Comedy", "Animation"], "overview": "Teenage friends find their lives upended by the wonders and horrors of puberty in this edgy comedy from real-life pals Nick Kroll and Andrew Goldberg.", "poster": "assets/tv-big-mouth-2017-poster.jpg", "backdrop": "assets/tv-big-mouth-2017-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 74204, "ratings": {"rtCritics": 95, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.591, "tmdbVotes": 1274}}, {"id": "tv-black-lightning-2018", "title": "Black Lightning", "year": 2018, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action & Adventure", "Sci-Fi & Fantasy", "Drama"], "overview": "Jefferson Pierce is a man wrestling with a secret. As the father of two daughters and principal of a charter high school that also serves as a safe haven for young people in a New Orleans neighborhood overrun by gang\u2026", "poster": "assets/tv-black-lightning-2018-poster.jpg", "backdrop": "assets/tv-black-lightning-2018-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 71663, "ratings": {"rtCritics": 92, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.907, "tmdbVotes": 991}}], "discoverySource": {"state": "materialized_snapshot", "rankKnown": false, "selection": "First 18 alphabetically indexed movie stubs and first 18 series stubs, not ranked feed order", "observedAt": "2026-11-04T20:42:12.030108+00:00"}}, {"key": "mindel", "name": "Mindel", "initial": "M", "color": "#ff9d72", "destinations": {"Home": {"kind": "home"}, "Movies": {"kind": "library", "collection": "movies"}, "Shows": {"kind": "library", "collection": "shows"}, "Discover": {"kind": "discover", "collection": "discover"}}, "movies": [{"id": "movie-chicago-2002", "title": "Chicago", "year": 2002, "type": "movie", "runtimeSeconds": 6808, "seasonCount": null, "communityRating": 7.131, "criticRating": 87, "genres": ["Comedy", "Crime", "Drama"], "overview": "Murderesses Velma Kelly and Roxie Hart find themselves on death row together and fight for the fame that will keep them from the gallows in 1920s Chicago.", "poster": "assets/movie-chicago-2002-poster.jpg", "backdrop": "assets/movie-chicago-2002-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:24:53.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 1574, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 87, "rtCriticsLabel": "Certified Fresh", "rtAudience": 83, "rtAudienceLabel": "Upright", "imdb": 7.2, "imdbVotes": 259272, "tmdb": 7.135, "tmdbVotes": 3025}}, {"id": "movie-coherence-2014", "title": "Coherence", "year": 2014, "type": "movie", "runtimeSeconds": 5286, "seasonCount": null, "communityRating": 7.21, "criticRating": 89, "genres": ["Thriller", "Science Fiction"], "overview": "Four couples gather for dinner the night a mysterious and powerful comet passes overhead.", "poster": "assets/movie-coherence-2014-poster.jpg", "backdrop": "assets/movie-coherence-2014-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2017-08-12T23:49:00.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 220289, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 89, "rtCriticsLabel": "Certified Fresh", "rtAudience": 81, "rtAudienceLabel": "Upright", "imdb": 7.1, "imdbVotes": 180354, "tmdb": 7.208, "tmdbVotes": 3702}}, {"id": "movie-the-killing-of-a-sacred-deer-2017", "title": "The Killing of a Sacred Deer", "year": 2017, "type": "movie", "runtimeSeconds": 7262, "seasonCount": null, "communityRating": 7.003, "criticRating": 79, "genres": ["Drama", "Thriller", "Mystery"], "overview": "Dr. Steven Murphy is a renowned cardiovascular surgeon who presides over a spotless household with his wife and two children. Lurking at the margins of his idyllic suburban existence is Martin, a fatherless teen who\u2026", "poster": "assets/movie-the-killing-of-a-sacred-deer-2017-poster.jpg", "backdrop": "assets/movie-the-killing-of-a-sacred-deer-2017-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-22T21:49:26.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 399057, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 79, "rtCriticsLabel": "Certified Fresh", "rtAudience": 63, "rtAudienceLabel": "Upright", "imdb": 7, "imdbVotes": 219488, "tmdb": 7.001, "tmdbVotes": 4640}}, {"id": "movie-night-is-short-walk-on-girl-2017", "title": "Night Is Short, Walk On Girl", "year": 2017, "type": "movie", "runtimeSeconds": 5548, "seasonCount": null, "communityRating": 7.421, "criticRating": 90, "genres": ["Comedy", "Romance", "Animation"], "overview": "As a group of university students go out for a night on the town, a sophomore known only as \"The Girl with Black Hair\" experiences a series of surreal encounters with the local nightlife \u2013 all the while unaware of\u2026", "poster": "assets/movie-night-is-short-walk-on-girl-2017-poster.jpg", "backdrop": "assets/movie-night-is-short-walk-on-girl-2017-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T17:39:14.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 430214, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 90, "rtCriticsLabel": "Fresh", "rtAudience": 84, "rtAudienceLabel": "Upright", "imdb": 7.5, "imdbVotes": 7640, "tmdb": 7.4, "tmdbVotes": 267}}, {"id": "movie-thelma-louise-1991", "title": "Thelma & Louise", "year": 1991, "type": "movie", "runtimeSeconds": 7786, "seasonCount": null, "communityRating": 7.596, "criticRating": 87, "genres": ["Drama", "Crime", "Adventure"], "overview": "Taking a break from their dreary lives, close friends Thelma and Louise embark on a short weekend trip that ends in unforeseen incriminating circumstances. As fugitives, both women rediscover the strength of their\u2026", "poster": "assets/movie-thelma-louise-1991-poster.jpg", "backdrop": "assets/movie-thelma-louise-1991-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:24:40.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 1541, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 87, "rtCriticsLabel": "Certified Fresh", "rtAudience": 82, "rtAudienceLabel": "Upright", "imdb": 7.6, "imdbVotes": 197947, "tmdb": 7.594, "tmdbVotes": 4063}}, {"id": "movie-vicky-cristina-barcelona-2008", "title": "Vicky Cristina Barcelona", "year": 2008, "type": "movie", "runtimeSeconds": 5804, "seasonCount": null, "communityRating": 6.798, "criticRating": 80, "genres": ["Drama", "Romance"], "overview": "Two girlfriends on a summer holiday in Spain become enamored with the same painter, unaware that his ex-wife, with whom he has a tempestuous relationship, is about to re-enter the picture.", "poster": "assets/movie-vicky-cristina-barcelona-2008-poster.jpg", "backdrop": "assets/movie-vicky-cristina-barcelona-2008-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:25:34.0000000Z", "lastPlayedAt": "2026-08-11T20:12:57.3064089Z", "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 5038, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 80, "rtCriticsLabel": "Certified Fresh", "rtAudience": 74, "rtAudienceLabel": "Upright", "imdb": 7.1, "imdbVotes": 283286, "tmdb": 6.797, "tmdbVotes": 4164}}], "shows": [{"id": "tv-all-creatures-great-small-2020", "title": "All Creatures Great & Small", "year": 2020, "type": "tv", "runtimeSeconds": 3000, "seasonCount": 7, "communityRating": 8.2, "criticRating": null, "genres": ["Drama", "Comedy"], "overview": "The heartwarming and humorous adventures of a young country vet in the Yorkshire Dales in the 1930s. A remake of the 1978 series.", "poster": "assets/tv-all-creatures-great-small-2020-poster.jpg", "backdrop": "assets/tv-all-creatures-great-small-2020-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-11-04T20:13:03.4266156Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 108255, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 99, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.2, "tmdbVotes": 168}}, {"id": "tv-back-to-life-2019", "title": "Back to Life", "year": 2019, "type": "tv", "runtimeSeconds": 1500, "seasonCount": 2, "communityRating": 7.367, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "When Miri Matteson returns home after eighteen years, can she integrate back into her old life? With a terrible event from her past hanging over her, it won\u2019t be easy.", "poster": "assets/tv-back-to-life-2019-poster.jpg", "backdrop": "assets/tv-back-to-life-2019-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0688758Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 88510, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.4, "tmdbVotes": 65}}, {"id": "tv-big-boys-2022", "title": "Big Boys", "year": 2022, "type": "tv", "runtimeSeconds": 1440, "seasonCount": 3, "communityRating": 7.6, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "Two boys from very different ends of the 'spectrum of masculinity' become best friends at Brent University freshers' week; in their first year of uni, they explore, experiment and try to discover themselves, helping\u2026", "poster": "assets/tv-big-boys-2022-poster.jpg", "backdrop": "assets/tv-big-boys-2022-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-11-04T20:25:58.2156837Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 202851, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.6, "tmdbVotes": 49}}, {"id": "tv-call-the-midwife-2012", "title": "Call the Midwife", "year": 2012, "type": "tv", "runtimeSeconds": 3120, "seasonCount": 15, "communityRating": 7.5, "criticRating": null, "genres": ["Drama"], "overview": "Drama following the lives of a group of midwives working in the poverty-stricken East End of London during the 1950s, based on the best-selling memoirs of Jennifer Worth.", "poster": "assets/tv-call-the-midwife-2012-poster.jpg", "backdrop": "assets/tv-call-the-midwife-2012-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0377216Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 39793, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.577, "tmdbVotes": 267}}, {"id": "tv-derry-girls-2018", "title": "Derry Girls", "year": 2018, "type": "tv", "runtimeSeconds": 1380, "seasonCount": 3, "communityRating": 8.144, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "Amidst the political conflict of Northern Ireland in the 1990s, five secondary school students square off with the universal challenges of being a teenager.", "poster": "assets/tv-derry-girls-2018-poster.jpg", "backdrop": "assets/tv-derry-girls-2018-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-02T20:01:55.8955537Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 76148, "artwork": {"posterKind": "center_crop", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 99, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.138, "tmdbVotes": 454}}, {"id": "tv-desperate-housewives-2004", "title": "Desperate Housewives", "year": 2004, "type": "tv", "runtimeSeconds": 2520, "seasonCount": 8, "communityRating": 7.896, "criticRating": null, "genres": ["Mystery", "Drama", "Comedy"], "overview": "Looking down on her friends and family isn't a way of life for Mary Alice Young... it's a way of death. One day, in her perfect house, in the loveliest of suburbs, Mary Alice ended it all. Now she's taking us into\u2026", "poster": "assets/tv-desperate-housewives-2004-poster.jpg", "backdrop": "assets/tv-desperate-housewives-2004-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-29T20:56:40.3505596Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 693, "artwork": {"posterKind": "poster", "backdropKind": "center_crop"}, "ratings": {"rtCritics": 72, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.896, "tmdbVotes": 2171}}, {"id": "tv-the-diplomat-2023", "title": "The Diplomat", "year": 2023, "type": "tv", "runtimeSeconds": null, "seasonCount": 4, "communityRating": 7.569, "criticRating": null, "genres": ["Drama", "War & Politics"], "overview": "Amid an international crisis, a US diplomat contends with her high-profile job as ambassador to the UK and her strained marriage to a political star.", "poster": "assets/tv-the-diplomat-2023-poster.jpg", "backdrop": "assets/tv-the-diplomat-2023-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0640348Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 203857, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 93, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.652, "tmdbVotes": 521}}, {"id": "tv-the-durrells-2016", "title": "The Durrells", "year": 2016, "type": "tv", "runtimeSeconds": 2760, "seasonCount": 4, "communityRating": 7.402, "criticRating": null, "genres": ["Drama", "Comedy", "Family"], "overview": "In 1935, financially strapped widow Louisa Durrell, whose life has fallen apart, decides to move from England, with her four children (three sons, one daughter), to the island of Corfu, Greece. Once there, the family\u2026", "poster": "assets/tv-the-durrells-2016-poster.jpg", "backdrop": "assets/tv-the-durrells-2016-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0619436Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 66134, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 94, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.4, "tmdbVotes": 127}}, {"id": "tv-etoile-2025", "title": "\u00c9toile", "year": 2025, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.197, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "In an ambitious gambit to save their storied institutions, two world-renowned ballet companies in New York City and Paris swap their most talented stars.", "poster": "assets/tv-etoile-2025-poster.jpg", "backdrop": "assets/tv-etoile-2025-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0601383Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 225383, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 86, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.3, "tmdbVotes": 40}}, {"id": "tv-gilmore-girls-2000", "title": "Gilmore Girls", "year": 2000, "type": "tv", "runtimeSeconds": 2640, "seasonCount": 7, "communityRating": 7.893, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "Set in the charming town of Stars Hollow, Connecticut, the series follows the captivating lives of Lorelai and Rory Gilmore, a mother/daughter pair who have a relationship most people only dream of.", "poster": "assets/tv-gilmore-girls-2000-poster.jpg", "backdrop": "assets/tv-gilmore-girls-2000-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0631035Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 4586, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.9, "tmdbVotes": 1339}}, {"id": "tv-ginny-georgia-2021", "title": "Ginny & Georgia", "year": 2021, "type": "tv", "runtimeSeconds": null, "seasonCount": 3, "communityRating": 8.026, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "Free-spirited Georgia and her two kids, Ginny and Austin, move north in search of a fresh start but find that the road to new beginnings can be bumpy.", "poster": "assets/tv-ginny-georgia-2021-poster.jpg", "backdrop": "assets/tv-ginny-georgia-2021-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0694828Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 117581, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 68, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8, "tmdbVotes": 1840}}, {"id": "tv-hellcats-2010", "title": "Hellcats", "year": 2010, "type": "tv", "runtimeSeconds": 2460, "seasonCount": 1, "communityRating": 7.5, "criticRating": null, "genres": ["Drama"], "overview": "Pre-law student Marti Perkins' world is flipped upside down when she loses her scholarship, and realizes the only way she can stay in school is by reigniting her dormant teen gymnastic skills to win a place on Lancer\u2026", "poster": "assets/tv-hellcats-2010-poster.jpg", "backdrop": "assets/tv-hellcats-2010-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-22T20:39:02.7719318Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 32504, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 65, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.5, "tmdbVotes": 116}}, {"id": "tv-high-potential-2024", "title": "High Potential", "year": 2024, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 8.201, "criticRating": null, "genres": ["Drama", "Crime", "Mystery"], "overview": "Morgan is a single mom with an exceptional mind, whose unconventional knack for solving crimes leads to an unusual and unstoppable partnership with a by-the-book seasoned detective.", "poster": "assets/tv-high-potential-2024-poster.jpg", "backdrop": "assets/tv-high-potential-2024-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0686091Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 226637, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 98, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.3, "tmdbVotes": 707}}, {"id": "tv-how-to-get-to-heaven-from-belfast-2026", "title": "How to Get to Heaven from Belfast", "year": 2026, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.027, "criticRating": null, "genres": ["Mystery", "Comedy", "Drama"], "overview": "Three lifelong pals embark on a chaotic quest to solve the mystery of their old friend's suspicious death and keep their own dark secret under wraps.", "poster": "assets/tv-how-to-get-to-heaven-from-belfast-2026-poster.jpg", "backdrop": "assets/tv-how-to-get-to-heaven-from-belfast-2026-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0683192Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 233079, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 95, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.063, "tmdbVotes": 95}}, {"id": "tv-the-hunting-wives-2025", "title": "The Hunting Wives", "year": 2025, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 6.932, "criticRating": null, "genres": ["Drama", "Mystery"], "overview": "Sophie trades New England for East Texas and falls into a wealthy socialite's magnetic orbit \u2014 where a clique of housewives hide deadly secrets.", "poster": "assets/tv-the-hunting-wives-2025-poster.jpg", "backdrop": "assets/tv-the-hunting-wives-2025-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-20T19:42:46.3227892Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 244447, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 81, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.964, "tmdbVotes": 112}}, {"id": "tv-the-lost-flowers-of-alice-hart-2023", "title": "The Lost Flowers of Alice Hart", "year": 2023, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.634, "criticRating": null, "genres": ["Drama", "Mystery"], "overview": "After losing her parents in a mysterious fire, nine-year-old Alice Hart is raised by her grandmother June on a flower farm where she learns there are secrets within secrets. But years on, an unearthed betrayal sees\u2026", "poster": "assets/tv-the-lost-flowers-of-alice-hart-2023-poster.jpg", "backdrop": "assets/tv-the-lost-flowers-of-alice-hart-2023-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0607236Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 125816, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 82, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.64, "tmdbVotes": 161}}, {"id": "tv-love-is-blind-2020", "title": "Love Is Blind", "year": 2020, "type": "tv", "runtimeSeconds": null, "seasonCount": 11, "communityRating": 6.261, "criticRating": null, "genres": ["Reality"], "overview": "Nick and Vanessa Lachey host this social experiment where single men and women look for love and get engaged, all before meeting in person.", "poster": "assets/tv-love-is-blind-2020-poster.jpg", "backdrop": "assets/tv-love-is-blind-2020-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-22T17:11:08.2447226Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 99353, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 66, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.233, "tmdbVotes": 118}}, {"id": "tv-maximum-pleasure-guaranteed-2026", "title": "Maximum Pleasure Guaranteed", "year": 2026, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 6.676, "criticRating": null, "genres": ["Comedy"], "overview": "A newly divorced mom falls down a dangerous rabbit hole of blackmail, murder, and youth soccer.", "poster": "assets/tv-maximum-pleasure-guaranteed-2026-poster.jpg", "backdrop": "assets/tv-maximum-pleasure-guaranteed-2026-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-07T21:04:02.8277793Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 285404, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 93, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.799, "tmdbVotes": 92}}, {"id": "tv-minx-2022", "title": "Minx", "year": 2022, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 6.833, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "An earnest young feminist joins forces with a low-rent publisher to make the world's first erotic magazine for women.", "poster": "assets/tv-minx-2022-poster.jpg", "backdrop": "assets/tv-minx-2022-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0653613Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 118303, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 93, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.9, "tmdbVotes": 123}}, {"id": "tv-offspring-2010", "title": "Offspring", "year": 2010, "type": "tv", "runtimeSeconds": 3600, "seasonCount": 7, "communityRating": 6.9, "criticRating": null, "genres": ["Drama"], "overview": "An exuberant drama set in Melbourne's Fitzroy, centering on Nina Proudman and her struggle to deal with her fabulously messy family, her hunt for a decent love life and her tendency to overthink and fly off into fantasy.", "poster": "assets/tv-offspring-2010-poster.jpg", "backdrop": "assets/tv-offspring-2010-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0664581Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 33155, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.9, "tmdbVotes": 27}}, {"id": "tv-only-murders-in-the-building-2021", "title": "Only Murders in the Building", "year": 2021, "type": "tv", "runtimeSeconds": null, "seasonCount": 5, "communityRating": 8.398, "criticRating": null, "genres": ["Comedy", "Mystery", "Crime"], "overview": "Three strangers share an obsession with true crime and suddenly find themselves wrapped up in one.", "poster": "assets/tv-only-murders-in-the-building-2021-poster.jpg", "backdrop": "assets/tv-only-murders-in-the-building-2021-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-11-04T20:25:58.2163301Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 107113, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 95, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.398, "tmdbVotes": 2333}}, {"id": "tv-outlander-blood-of-my-blood-2025", "title": "Outlander: Blood of My Blood", "year": 2025, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 8.542, "criticRating": null, "genres": ["Drama"], "overview": "From the battlefields of World War I to the rugged Highlands of 18th century Scotland, two fated couples must defy the forces that seek to tear them apart, unfolding in surprising and unforeseen ways in this romantic\u2026", "poster": "assets/tv-outlander-blood-of-my-blood-2025-poster.jpg", "backdrop": "assets/tv-outlander-blood-of-my-blood-2025-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0691373Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 207484, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 94, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.738, "tmdbVotes": 124}}, {"id": "tv-rivals-2024", "title": "Rivals", "year": 2024, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 7.44, "criticRating": null, "genres": ["Drama"], "overview": "It is 1986 and Britain is booming. \"Rivals\" dives headfirst into the cutthroat world of TV where hair-dos are big and ambitions are even bigger. Deals are brokered in boardrooms, as well as bedrooms. Nobody can be\u2026", "poster": "assets/tv-rivals-2024-poster.jpg", "backdrop": "assets/tv-rivals-2024-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0645815Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 208921, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 96, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.4, "tmdbVotes": 93}}, {"id": "tv-rooster-2026", "title": "Rooster", "year": 2026, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.431, "criticRating": null, "genres": ["Comedy"], "overview": "On a college campus, an author navigates a complicated relationship with his daughter.", "poster": "assets/tv-rooster-2026-poster.jpg", "backdrop": "assets/tv-rooster-2026-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.063389Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 254953, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 88, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.423, "tmdbVotes": 144}}, {"id": "tv-sex-and-the-city-1998", "title": "Sex and the City", "year": 1998, "type": "tv", "runtimeSeconds": null, "seasonCount": 6, "communityRating": 7.365, "criticRating": null, "genres": ["Drama", "Comedy"], "overview": "Based on the bestselling book by Candace Bushnell, Sex and the City tells the story of four best friends, all single and in their late thirties, as they pursue their careers and talk about their sex lives, all while\u2026", "poster": "assets/tv-sex-and-the-city-1998-poster.jpg", "backdrop": "assets/tv-sex-and-the-city-1998-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0679324Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 105, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 70, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.351, "tmdbVotes": 2220}}, {"id": "tv-skymed-2022", "title": "SkyMed", "year": 2022, "type": "tv", "runtimeSeconds": 2640, "seasonCount": 4, "communityRating": 6.665, "criticRating": null, "genres": ["Drama"], "overview": "Life, death and drama at 20,000 feet. The series weaves together intense character journeys and high-stakes medical rescues, as we follow the triumphs, heartbreaks and tribulations of budding nurses and pilots flying\u2026", "poster": "assets/tv-skymed-2022-poster.jpg", "backdrop": "assets/tv-skymed-2022-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-22T19:44:29.2431354Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 133908, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.699, "tmdbVotes": 98}}, {"id": "tv-so-you-think-you-can-dance-2008", "title": "So You Think You Can Dance", "year": 2008, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 9.8, "criticRating": null, "genres": ["Family", "Reality"], "overview": "So You Think You Can Dance is a joint Belgian-Dutch dance competition show broadcast on RTL 5 and vtm television stations. The first season was broadcast only in the Netherlands, whereas starting with season 2, the\u2026", "poster": "assets/tv-so-you-think-you-can-dance-2008-poster.jpg", "backdrop": "assets/tv-so-you-think-you-can-dance-2008-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-23T11:11:35.4124418Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 40231, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 9.8, "tmdbVotes": 4}}, {"id": "tv-the-white-lotus-2021", "title": "The White Lotus", "year": 2021, "type": "tv", "runtimeSeconds": null, "seasonCount": 3, "communityRating": 7.597, "criticRating": null, "genres": ["Comedy", "Drama", "Mystery"], "overview": "Follow the exploits of various guests and employees at an exclusive tropical resort over the span of a week as with each passing day, a darker complexity emerges in these picture-perfect travelers, the hotel\u2019s\u2026", "poster": "assets/tv-the-white-lotus-2021-poster.jpg", "backdrop": "assets/tv-the-white-lotus-2021-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-20T02:45:52.8742674Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 111803, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 90, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.599, "tmdbVotes": 1604}}, {"id": "tv-yellowjackets-2021", "title": "Yellowjackets", "year": 2021, "type": "tv", "runtimeSeconds": null, "seasonCount": 3, "communityRating": 7.431, "criticRating": null, "genres": ["Drama", "Mystery"], "overview": "This equal parts survival epic, psychological horror story and coming-of-age drama tells the saga of a team of wildly talented high school girls soccer players who become the (un)lucky survivors of a plane crash deep\u2026", "poster": "assets/tv-yellowjackets-2021-poster.jpg", "backdrop": "assets/tv-yellowjackets-2021-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-11-04T20:31:47.4592756Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 117488, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 92, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.431, "tmdbVotes": 1070}}], "anime": [], "resume": [{"id": "episode-sex-and-the-country-2001-s4e9", "title": "Sex and the Country", "year": 2001, "type": "episode", "runtimeSeconds": 1751, "seasonCount": null, "communityRating": 5.9, "criticRating": null, "genres": ["Comedy", "Drama", "Romance"], "overview": "Carrie is dragged to Aidan's country home in Suffern, New York. Charlotte visits the MacDougal \"compound\" in Connecticut. Miranda yells at Steve when he tells her he has testicular cancer but has no clue about his\u2026", "poster": "assets/episode-sex-and-the-country-2001-s4e9-poster.jpg", "backdrop": "assets/episode-sex-and-the-country-2001-s4e9-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 96.08, "progress": 0.0549, "addedAt": "2026-07-17T10:53:15.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "Sex and the City", "seasonNumber": 4, "episodeNumber": 9, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}], "nextUp": [{"id": "episode-what-more-do-i-need-2008-s5e7", "title": "What More Do I Need?", "year": 2008, "type": "episode", "runtimeSeconds": 2521, "seasonCount": null, "communityRating": 8, "criticRating": null, "genres": ["Comedy", "Drama", "Mystery"], "overview": "Lynette and Tom uncover the unsettling truth about son Porter. Gabrielle suspects Carlos' best client, Virginia, has ulterior motives. Bree's moment of weakness could bring her great embarrassment and shame.\u2026", "poster": "assets/episode-what-more-do-i-need-2008-s5e7-poster.jpg", "backdrop": "assets/episode-what-more-do-i-need-2008-s5e7-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-29T14:37:28.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "Desperate Housewives", "seasonNumber": 5, "episodeNumber": 7, "artwork": {"posterKind": "center_crop", "backdropKind": "backdrop"}}, {"id": "episode-new-day-2021-s1e2", "title": "New Day", "year": 2021, "type": "episode", "runtimeSeconds": 3445, "seasonCount": null, "communityRating": 7.143, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "A cautiously optimistic Belinda walks a fine line with Tanya, while Armond brainstorms ways to deal with Shane. After her husband belittles her work, Rachel approaches Nicole for advice. Paula and Olivia lose track\u2026", "poster": "assets/episode-new-day-2021-s1e2-poster.jpg", "backdrop": "assets/episode-new-day-2021-s1e2-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-19T22:18:57.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "The White Lotus", "seasonNumber": 1, "episodeNumber": 2, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}, {"id": "episode-the-uncomfortability-2010-s1e2", "title": "The Uncomfortability", "year": 2010, "type": "episode", "runtimeSeconds": 2687, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "Nina's insecurities are revealed when a patient poses an awkward request. Meanwhile Geraldine decides to try online dating, and Jimmy is an unexpected saviour to Cherie and Darcy.", "poster": "assets/episode-the-uncomfortability-2010-s1e2-poster.jpg", "backdrop": "assets/episode-the-uncomfortability-2010-s1e2-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T11:47:42.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "Offspring", "seasonNumber": 1, "episodeNumber": 2, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}, {"id": "episode-episode-2-2016-s1e2", "title": "Episode 2", "year": 2016, "type": "episode", "runtimeSeconds": 2766, "seasonCount": null, "communityRating": 8.3, "criticRating": null, "genres": ["Biography", "Comedy", "Drama"], "overview": "Larry falls dangerously ill, and it falls to Theo and his neighbour Sven to put their rudimentary medical skills to the task of saving his life. The family's money worries continue, but Spiros brings them good news\u2026", "poster": "assets/episode-episode-2-2016-s1e2-poster.jpg", "backdrop": "assets/episode-episode-2-2016-s1e2-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-31T07:29:17.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "The Durrells", "seasonNumber": 1, "episodeNumber": 2, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}, {"id": "episode-remembrance-day-2026-s2e1", "title": "Remembrance Day", "year": 2026, "type": "episode", "runtimeSeconds": 3822, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Fantasy", "Romance"], "overview": "The fiery crosses have been lit across the Highlands; lovers must part, as the call to arms brings friends and enemies home and the Jacobite Rebellion begins in earnest.", "poster": "assets/episode-remembrance-day-2026-s2e1-poster.jpg", "backdrop": "assets/episode-remembrance-day-2026-s2e1-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-19T03:50:07.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "Outlander: Blood of My Blood", "seasonNumber": 2, "episodeNumber": 1, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}, {"id": "episode-one-of-us-2024-s1e7", "title": "One of Us", "year": 2024, "type": "episode", "runtimeSeconds": 2555, "seasonCount": null, "communityRating": 7.7, "criticRating": null, "genres": [], "overview": "Morgan agrees to show Ava around the LAPD, but things quickly take a dangerous turn when the precinct is held hostage by the friends of a recently convicted man. Can Morgan and the detectives outsmart their captors\u2026", "poster": "assets/episode-one-of-us-2024-s1e7-poster.jpg", "backdrop": "assets/episode-one-of-us-2024-s1e7-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T13:57:22.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "High Potential", "seasonNumber": 1, "episodeNumber": 7, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}, {"id": "episode-the-breakup-part-2-2001-s1e17", "title": "The Breakup, Part 2", "year": 2001, "type": "episode", "runtimeSeconds": 2669, "seasonCount": null, "communityRating": 7.4, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "After recent events, Rory keeps busy, refusing to give in to self-pity. Meanwhile, Stars Hollow's residents rally around her, much to her dismay.", "poster": "assets/episode-the-breakup-part-2-2001-s1e17-poster.jpg", "backdrop": "assets/episode-the-breakup-part-2-2001-s1e17-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T11:28:05.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "Gilmore Girls", "seasonNumber": 1, "episodeNumber": 17, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}, {"id": "episode-i-heart-ny-2002-s4e18", "title": "I Heart NY", "year": 2002, "type": "episode", "runtimeSeconds": 1905, "seasonCount": null, "communityRating": 6.667, "criticRating": null, "genres": ["Comedy", "Drama", "Romance"], "overview": "Carrie is shocked to find out that Big is moving to Napa, California and plans to give him a New York send-off. Charlotte begins dating another recent divorc\u00e9. Miranda prepares for the new baby as her delivery date\u2026", "poster": "assets/episode-i-heart-ny-2002-s4e18-poster.jpg", "backdrop": "assets/episode-i-heart-ny-2002-s4e18-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T12:35:14.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "Sex and the City", "seasonNumber": 4, "episodeNumber": 18, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}], "recentlyAdded": [{"id": "tv-yellowjackets-2021", "title": "Yellowjackets", "year": 2021, "type": "tv", "runtimeSeconds": null, "seasonCount": 3, "communityRating": 7.431, "criticRating": null, "genres": ["Drama", "Mystery"], "overview": "This equal parts survival epic, psychological horror story and coming-of-age drama tells the saga of a team of wildly talented high school girls soccer players who become the (un)lucky survivors of a plane crash deep\u2026", "poster": "assets/tv-yellowjackets-2021-poster.jpg", "backdrop": "assets/tv-yellowjackets-2021-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-11-04T20:31:47.4592756Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 117488, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 92, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.431, "tmdbVotes": 1070}}, {"id": "tv-only-murders-in-the-building-2021", "title": "Only Murders in the Building", "year": 2021, "type": "tv", "runtimeSeconds": null, "seasonCount": 5, "communityRating": 8.398, "criticRating": null, "genres": ["Comedy", "Mystery", "Crime"], "overview": "Three strangers share an obsession with true crime and suddenly find themselves wrapped up in one.", "poster": "assets/tv-only-murders-in-the-building-2021-poster.jpg", "backdrop": "assets/tv-only-murders-in-the-building-2021-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-11-04T20:25:58.2163301Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 107113, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 95, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.398, "tmdbVotes": 2333}}, {"id": "tv-big-boys-2022", "title": "Big Boys", "year": 2022, "type": "tv", "runtimeSeconds": 1440, "seasonCount": 3, "communityRating": 7.6, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "Two boys from very different ends of the 'spectrum of masculinity' become best friends at Brent University freshers' week; in their first year of uni, they explore, experiment and try to discover themselves, helping\u2026", "poster": "assets/tv-big-boys-2022-poster.jpg", "backdrop": "assets/tv-big-boys-2022-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-11-04T20:25:58.2156837Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 202851, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.6, "tmdbVotes": 49}}, {"id": "tv-all-creatures-great-small-2020", "title": "All Creatures Great & Small", "year": 2020, "type": "tv", "runtimeSeconds": 3000, "seasonCount": 7, "communityRating": 8.2, "criticRating": null, "genres": ["Drama", "Comedy"], "overview": "The heartwarming and humorous adventures of a young country vet in the Yorkshire Dales in the 1930s. A remake of the 1978 series.", "poster": "assets/tv-all-creatures-great-small-2020-poster.jpg", "backdrop": "assets/tv-all-creatures-great-small-2020-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-11-04T20:13:03.4266156Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 108255, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 99, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.2, "tmdbVotes": 168}}, {"id": "movie-the-killing-of-a-sacred-deer-2017", "title": "The Killing of a Sacred Deer", "year": 2017, "type": "movie", "runtimeSeconds": 7262, "seasonCount": null, "communityRating": 7.003, "criticRating": 79, "genres": ["Drama", "Thriller", "Mystery"], "overview": "Dr. Steven Murphy is a renowned cardiovascular surgeon who presides over a spotless household with his wife and two children. Lurking at the margins of his idyllic suburban existence is Martin, a fatherless teen who\u2026", "poster": "assets/movie-the-killing-of-a-sacred-deer-2017-poster.jpg", "backdrop": "assets/movie-the-killing-of-a-sacred-deer-2017-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-22T21:49:26.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 399057, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 79, "rtCriticsLabel": "Certified Fresh", "rtAudience": 63, "rtAudienceLabel": "Upright", "imdb": 7, "imdbVotes": 219488, "tmdb": 7.001, "tmdbVotes": 4640}}, {"id": "tv-derry-girls-2018", "title": "Derry Girls", "year": 2018, "type": "tv", "runtimeSeconds": 1380, "seasonCount": 3, "communityRating": 8.144, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "Amidst the political conflict of Northern Ireland in the 1990s, five secondary school students square off with the universal challenges of being a teenager.", "poster": "assets/tv-derry-girls-2018-poster.jpg", "backdrop": "assets/tv-derry-girls-2018-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-02T20:01:55.8955537Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 76148, "artwork": {"posterKind": "center_crop", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 99, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.138, "tmdbVotes": 454}}, {"id": "tv-so-you-think-you-can-dance-2008", "title": "So You Think You Can Dance", "year": 2008, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 9.8, "criticRating": null, "genres": ["Family", "Reality"], "overview": "So You Think You Can Dance is a joint Belgian-Dutch dance competition show broadcast on RTL 5 and vtm television stations. The first season was broadcast only in the Netherlands, whereas starting with season 2, the\u2026", "poster": "assets/tv-so-you-think-you-can-dance-2008-poster.jpg", "backdrop": "assets/tv-so-you-think-you-can-dance-2008-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-23T11:11:35.4124418Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 40231, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 9.8, "tmdbVotes": 4}}, {"id": "tv-hellcats-2010", "title": "Hellcats", "year": 2010, "type": "tv", "runtimeSeconds": 2460, "seasonCount": 1, "communityRating": 7.5, "criticRating": null, "genres": ["Drama"], "overview": "Pre-law student Marti Perkins' world is flipped upside down when she loses her scholarship, and realizes the only way she can stay in school is by reigniting her dormant teen gymnastic skills to win a place on Lancer\u2026", "poster": "assets/tv-hellcats-2010-poster.jpg", "backdrop": "assets/tv-hellcats-2010-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-22T20:39:02.7719318Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 32504, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 65, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.5, "tmdbVotes": 116}}, {"id": "tv-skymed-2022", "title": "SkyMed", "year": 2022, "type": "tv", "runtimeSeconds": 2640, "seasonCount": 4, "communityRating": 6.665, "criticRating": null, "genres": ["Drama"], "overview": "Life, death and drama at 20,000 feet. The series weaves together intense character journeys and high-stakes medical rescues, as we follow the triumphs, heartbreaks and tribulations of budding nurses and pilots flying\u2026", "poster": "assets/tv-skymed-2022-poster.jpg", "backdrop": "assets/tv-skymed-2022-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-22T19:44:29.2431354Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 133908, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.699, "tmdbVotes": 98}}, {"id": "tv-love-is-blind-2020", "title": "Love Is Blind", "year": 2020, "type": "tv", "runtimeSeconds": null, "seasonCount": 11, "communityRating": 6.261, "criticRating": null, "genres": ["Reality"], "overview": "Nick and Vanessa Lachey host this social experiment where single men and women look for love and get engaged, all before meeting in person.", "poster": "assets/tv-love-is-blind-2020-poster.jpg", "backdrop": "assets/tv-love-is-blind-2020-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-22T17:11:08.2447226Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 99353, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 66, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.233, "tmdbVotes": 118}}, {"id": "tv-the-hunting-wives-2025", "title": "The Hunting Wives", "year": 2025, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 6.932, "criticRating": null, "genres": ["Drama", "Mystery"], "overview": "Sophie trades New England for East Texas and falls into a wealthy socialite's magnetic orbit \u2014 where a clique of housewives hide deadly secrets.", "poster": "assets/tv-the-hunting-wives-2025-poster.jpg", "backdrop": "assets/tv-the-hunting-wives-2025-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-20T19:42:46.3227892Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 244447, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 81, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.964, "tmdbVotes": 112}}, {"id": "tv-the-white-lotus-2021", "title": "The White Lotus", "year": 2021, "type": "tv", "runtimeSeconds": null, "seasonCount": 3, "communityRating": 7.597, "criticRating": null, "genres": ["Comedy", "Drama", "Mystery"], "overview": "Follow the exploits of various guests and employees at an exclusive tropical resort over the span of a week as with each passing day, a darker complexity emerges in these picture-perfect travelers, the hotel\u2019s\u2026", "poster": "assets/tv-the-white-lotus-2021-poster.jpg", "backdrop": "assets/tv-the-white-lotus-2021-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-20T02:45:52.8742674Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 111803, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 90, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.599, "tmdbVotes": 1604}}], "discover": [{"id": "movie-across-the-hall-2009", "title": "Across the Hall", "year": 2009, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Thriller", "Mystery"], "overview": "Convinced that his fiancee is cheating on him, a man follows her to a hotel and calls his best friend to help him avoid a calamity.", "poster": "assets/movie-across-the-hall-2009-poster.jpg", "backdrop": "assets/movie-across-the-hall-2009-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 21469, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": 39, "rtAudienceLabel": "Spilled", "imdb": 5.8, "imdbVotes": 5130, "tmdb": 6, "tmdbVotes": 129}}, {"id": "movie-addicted-2014", "title": "Addicted", "year": 2014, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Thriller"], "overview": "A gallerist risks her family and flourishing career when she enters into an affair with a talented painter and slowly loses control of her life.", "poster": "assets/movie-addicted-2014-poster.jpg", "backdrop": "assets/movie-addicted-2014-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 235271, "ratings": {"rtCritics": 7, "rtCriticsLabel": "Rotten", "rtAudience": 51, "rtAudienceLabel": "Spilled", "imdb": 5, "imdbVotes": 13131, "tmdb": 5.928, "tmdbVotes": 466}}, {"id": "movie-adulterers-2016", "title": "Adulterers", "year": 2016, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Thriller", "Drama"], "overview": "On a steamy New Orleans afternoon, Sam Deuprey decides to surprise his beautiful wife, Ashley, for their anniversary and comes home early. But Ashley is not alone in the bedroom. She and her lover, Damien are about\u2026", "poster": "assets/movie-adulterers-2016-poster.jpg", "backdrop": "assets/movie-adulterers-2016-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 376004, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": 37, "rtAudienceLabel": "Spilled", "imdb": 5.1, "imdbVotes": 2144, "tmdb": 6.2, "tmdbVotes": 116}}, {"id": "movie-alone-with-her-2006", "title": "Alone With Her", "year": 2006, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Crime", "Drama", "Thriller"], "overview": "The harrowing story of a disturbed young man's attempts to win the affections of an unsuspecting young woman. When Doug first sees Amy, he instantly falls for her and begins to watch her every move, going so far as\u2026", "poster": "assets/movie-alone-with-her-2006-poster.jpg", "backdrop": "assets/movie-alone-with-her-2006-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 18206, "ratings": {"rtCritics": 70, "rtCriticsLabel": "Fresh", "rtAudience": 46, "rtAudienceLabel": "Spilled", "imdb": 6, "imdbVotes": 4359, "tmdb": 5.9, "tmdbVotes": 94}}, {"id": "movie-awake-2007", "title": "Awake", "year": 2007, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Thriller", "Crime", "Mystery"], "overview": "While undergoing heart surgery, a man experiences a phenomenon called \u2018anesthetic awareness\u2019, which leaves him awake but paralyzed throughout the operation. As various obstacles present themselves, his wife must make\u2026", "poster": "assets/movie-awake-2007-poster.jpg", "backdrop": "assets/movie-awake-2007-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 13483, "ratings": {"rtCritics": 23, "rtCriticsLabel": "Rotten", "rtAudience": 55, "rtAudienceLabel": "Spilled", "imdb": 6.5, "imdbVotes": 89389, "tmdb": 6.586, "tmdbVotes": 1649}}, {"id": "movie-black-bear-2020", "title": "Black Bear", "year": 2020, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Thriller"], "overview": "At a remote lake house in the Adirondack Mountains, a couple entertains an out-of-town guest looking for inspiration in her filmmaking. The group quickly falls into a calculated game of desire, manipulation, and\u2026", "poster": "assets/movie-black-bear-2020-poster.jpg", "backdrop": "assets/movie-black-bear-2020-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 624788, "ratings": {"rtCritics": 89, "rtCriticsLabel": "Certified Fresh", "rtAudience": 64, "rtAudienceLabel": "Upright", "imdb": 6.5, "imdbVotes": 18408, "tmdb": 6.337, "tmdbVotes": 315}}, {"id": "movie-butterfly-on-a-wheel-2007", "title": "Butterfly on a Wheel", "year": 2007, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Crime", "Drama", "Thriller"], "overview": "A sociopathic kidnapper methodically pushes a desperate pair of parents to their absolute breaking point.", "poster": "assets/movie-butterfly-on-a-wheel-2007-poster.jpg", "backdrop": "assets/movie-butterfly-on-a-wheel-2007-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 13250, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": 61, "rtAudienceLabel": "Upright", "imdb": 6.6, "imdbVotes": 35409, "tmdb": 6.457, "tmdbVotes": 595}}, {"id": "movie-careful-what-you-wish-for-2015", "title": "Careful What You Wish For", "year": 2015, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Thriller"], "overview": "A guy gets more than he bargained for after entering into an affair with the wife of an investment banker. Soon, a suspicious death and substantial life insurance policy embroil him in a scandal.", "poster": "assets/movie-careful-what-you-wish-for-2015-poster.jpg", "backdrop": "assets/movie-careful-what-you-wish-for-2015-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 317744, "ratings": {"rtCritics": 17, "rtCriticsLabel": "Rotten", "rtAudience": 61, "rtAudienceLabel": "Upright", "imdb": 5.6, "imdbVotes": 9452, "tmdb": 6.129, "tmdbVotes": 446}}, {"id": "movie-crime-of-passion-1956", "title": "Crime of Passion", "year": 1956, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Crime", "Thriller"], "overview": "Kathy leaves the newspaper business to marry homicide detective Bill, but is frustrated by his lack of ambition and the banality of life in the suburbs. Her drive to advance Bill's career soon takes her down a\u2026", "poster": "assets/movie-crime-of-passion-1956-poster.jpg", "backdrop": "assets/movie-crime-of-passion-1956-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "center_crop", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 1920, "ratings": {"rtCritics": 80, "rtCriticsLabel": "Fresh", "rtAudience": 34, "rtAudienceLabel": "Spilled", "imdb": 6.4, "imdbVotes": 3750, "tmdb": 6.1, "tmdbVotes": 57}}, {"id": "movie-deep-water-2022", "title": "Deep Water", "year": 2022, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Mystery", "Thriller"], "overview": "A well-to-do husband who allows his wife to have affairs in order to avoid a divorce becomes a prime suspect in the disappearance of her lovers.", "poster": "assets/movie-deep-water-2022-poster.jpg", "backdrop": "assets/movie-deep-water-2022-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 619979, "ratings": {"rtCritics": 35, "rtCriticsLabel": "Rotten", "rtAudience": 25, "rtAudienceLabel": "Spilled", "imdb": 5.5, "imdbVotes": 74098, "tmdb": 5.834, "tmdbVotes": 1755}}, {"id": "movie-derailed-2005", "title": "Derailed", "year": 2005, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Thriller"], "overview": "When two married business executives having an affair are blackmailed by a violent criminal, they are forced to turn the tables on him to save their families.", "poster": "assets/movie-derailed-2005-poster.jpg", "backdrop": "assets/movie-derailed-2005-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 8999, "ratings": {"rtCritics": 20, "rtCriticsLabel": "Rotten", "rtAudience": 58, "rtAudienceLabel": "Spilled", "imdb": 6.6, "imdbVotes": 79563, "tmdb": 6.405, "tmdbVotes": 1193}}, {"id": "movie-die-my-love-2025", "title": "Die My Love", "year": 2025, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama"], "overview": "After inheriting a remote Montana house, Jackson moves there from New York with his partner Grace, and the couple soon welcome a child. As Jackson becomes increasingly absent and rural isolation sets in, Grace\u2026", "poster": "assets/movie-die-my-love-2025-poster.jpg", "backdrop": "assets/movie-die-my-love-2025-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 1033148, "ratings": {"rtCritics": 74, "rtCriticsLabel": "Certified Fresh", "rtAudience": 45, "rtAudienceLabel": "Spilled", "imdb": 6, "imdbVotes": 50664, "tmdb": 6.1, "tmdbVotes": 683}}, {"id": "movie-dream-house-2011", "title": "Dream House", "year": 2011, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Mystery", "Drama", "Thriller"], "overview": "Publisher Will Atenton quits a lucrative job in New York to relocate his wife, Libby, and their daughters to a quaint town in New England. However, as they settle into their home the Atentons discover that a woman\u2026", "poster": "assets/movie-dream-house-2011-poster.jpg", "backdrop": "assets/movie-dream-house-2011-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 69668, "ratings": {"rtCritics": 7, "rtCriticsLabel": "Rotten", "rtAudience": 36, "rtAudienceLabel": "Spilled", "imdb": 6, "imdbVotes": 71386, "tmdb": 6.212, "tmdbVotes": 1480}}, {"id": "movie-dream-lover-1994", "title": "Dream Lover", "year": 1994, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Mystery", "Thriller"], "overview": "Not long after they cross paths at an art gallery, architect Ray Reardon and hypnotically sensual Lena are married with children. But as strange incidents occur, Ray begins to realize he may not really know the woman\u2026", "poster": "assets/movie-dream-lover-1994-poster.jpg", "backdrop": "assets/movie-dream-lover-1994-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 18190, "ratings": {"rtCritics": 57, "rtCriticsLabel": "Rotten", "rtAudience": 38, "rtAudienceLabel": "Spilled", "imdb": 6.2, "imdbVotes": 7865, "tmdb": 6.844, "tmdbVotes": 167}}, {"id": "movie-drop-2025", "title": "Drop", "year": 2025, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Mystery", "Thriller"], "overview": "Violet, a widowed mother on her first date in years, arrives at an upscale restaurant where she is relieved that her date, Henry, is more charming and handsome than she expected. But their chemistry begins to curdle\u2026", "poster": "assets/movie-drop-2025-poster.jpg", "backdrop": "assets/movie-drop-2025-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 1249213, "ratings": {"rtCritics": 83, "rtCriticsLabel": "Certified Fresh", "rtAudience": 79, "rtAudienceLabel": "Upright", "imdb": 6.1, "imdbVotes": 61018, "tmdb": 6.275, "tmdbVotes": 1023}}, {"id": "movie-eastern-promises-2007", "title": "Eastern Promises", "year": 2007, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Thriller", "Crime", "Mystery"], "overview": "A Russian teenager living in London dies during childbirth but leaves clues in her diary that could tie her child to a rape involving a violent Russian mob family.", "poster": "assets/movie-eastern-promises-2007-poster.jpg", "backdrop": "assets/movie-eastern-promises-2007-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 2252, "ratings": {"rtCritics": 89, "rtCriticsLabel": "Certified Fresh", "rtAudience": 83, "rtAudienceLabel": "Upright", "imdb": 7.6, "imdbVotes": 281015, "tmdb": 7.349, "tmdbVotes": 3900}}, {"id": "movie-faces-1968", "title": "Faces", "year": 1968, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama"], "overview": "Middle-aged suburban husband Richard abruptly tells his wife, Maria, that he wants a divorce. As Richard takes up with a younger woman, Maria enjoys a night on the town with her friends and meets a younger man. As\u2026", "poster": "assets/movie-faces-1968-poster.jpg", "backdrop": "assets/movie-faces-1968-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "center_crop", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 753, "ratings": {"rtCritics": 83, "rtCriticsLabel": "Fresh", "rtAudience": 86, "rtAudienceLabel": "Upright", "imdb": 7.4, "imdbVotes": 12950, "tmdb": 7.093, "tmdbVotes": 227}}, {"id": "movie-fatale-2020", "title": "Fatale", "year": 2020, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Thriller"], "overview": "After a wild one-night stand, successful sports agent Derrick Tyler watches his perfect life slowly disappear when he discovers the sexy and mysterious woman he risked everything for is determined police detective\u2026", "poster": "assets/movie-fatale-2020-poster.jpg", "backdrop": "assets/movie-fatale-2020-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 549514, "ratings": {"rtCritics": 46, "rtCriticsLabel": "Rotten", "rtAudience": 87, "rtAudienceLabel": "Upright", "imdb": 5.5, "imdbVotes": 16392, "tmdb": 6, "tmdbVotes": 401}}, {"id": "tv-56-days-2026", "title": "56 Days", "year": 2026, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Crime", "Mystery"], "overview": "When an unidentified body is found in a luxury apartment linked to Oliver Kennedy and his girlfriend Ciara Wyse, Detectives Lee Reardon and Karl Connolly reconstruct the couple's deadly romance across the past 56 days.", "poster": "assets/tv-56-days-2026-poster.jpg", "backdrop": "assets/tv-56-days-2026-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 241372, "ratings": {"rtCritics": 60, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.388, "tmdbVotes": 245}}, {"id": "tv-90-day-fiance-before-the-90-days-2017", "title": "90 Day Fianc\u00e9: Before the 90 Days", "year": 2017, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Reality"], "overview": "Follow couples who have an existing relationship online, but haven't met in person. We'll experience their journey as they travel to the other's foreign country for the first time in an attempt to establish an\u2026", "poster": "assets/tv-90-day-fiance-before-the-90-days-2017-poster.jpg", "backdrop": "assets/tv-90-day-fiance-before-the-90-days-2017-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 73319, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.5, "tmdbVotes": 45}}, {"id": "tv-90-day-fiance-the-other-way-2019", "title": "90 Day Fianc\u00e9: The Other Way", "year": 2019, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Reality"], "overview": "Americans move to a foreign country all in the name of love. Will uprooting their lives in the United States pay off, or will they be packing up and moving back to America brokenhearted?", "poster": "assets/tv-90-day-fiance-the-other-way-2019-poster.jpg", "backdrop": "assets/tv-90-day-fiance-the-other-way-2019-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 90046, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.8, "tmdbVotes": 34}}, {"id": "tv-absolutely-fabulous-1992", "title": "Absolutely Fabulous", "year": 1992, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Comedy"], "overview": "Set in the world of fashion and PR, immature fun-loving mother Edina Monsoon and her best friend Patsy drive Eddie's sensible daughter, Saffron, up the wall with their constant drug abuse and outrageous selfishness.\u2026", "poster": "assets/tv-absolutely-fabulous-1992-poster.jpg", "backdrop": "assets/tv-absolutely-fabulous-1992-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 4493, "ratings": {"rtCritics": 96, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.6, "tmdbVotes": 198}}, {"id": "tv-the-afterparty-2022", "title": "The Afterparty", "year": 2022, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Mystery", "Comedy", "Crime"], "overview": "Nothing is as it seems in this hilarious murder mystery where each suspect's story is told through a different film genre.", "poster": "assets/tv-the-afterparty-2022-poster.jpg", "backdrop": "assets/tv-the-afterparty-2022-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 106454, "ratings": {"rtCritics": 92, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.071, "tmdbVotes": 245}}, {"id": "tv-agatha-christie-s-marple-2004", "title": "Agatha Christie's Marple", "year": 2004, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Crime", "Mystery"], "overview": "The adventures of Miss Jane Marple, an elderly spinster living in the quiet little village of St Mary Mead. During her many visits to friends and relatives in other villages, Miss Marple often stumbles upon\u2026", "poster": "assets/tv-agatha-christie-s-marple-2004-poster.jpg", "backdrop": "assets/tv-agatha-christie-s-marple-2004-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 6127, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.9, "tmdbVotes": 152}}, {"id": "tv-all-american-homecoming-2022", "title": "All American: Homecoming", "year": 2022, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama"], "overview": "Follow the journeys of Simone Hicks, a tennis hopeful from Beverly Hills, and elite baseball player Damon Sims from Chicago, as they navigate life at the prestigious HBCU Bringston University.", "poster": "assets/tv-all-american-homecoming-2022-poster.jpg", "backdrop": "assets/tv-all-american-homecoming-2022-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 153723, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.3, "tmdbVotes": 70}}, {"id": "tv-and-just-like-that-2021", "title": "And Just Like That\u2026", "year": 2021, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "This new chapter of \u201cSex and the City\u201d follows Carrie, Miranda and Charlotte as they navigate the journey from the complicated reality of life and friendship in their 30s to the even more complicated reality of life\u2026", "poster": "assets/tv-and-just-like-that-2021-poster.jpg", "backdrop": "assets/tv-and-just-like-that-2021-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 116450, "ratings": {"rtCritics": 52, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.211, "tmdbVotes": 556}}, {"id": "tv-anne-with-an-e-2017", "title": "Anne with an E", "year": 2017, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Family"], "overview": "A coming-of-age story about an outsider who, against all odds and numerous challenges, fights for love and acceptance and for her place in the world. The series centers on a young orphaned girl in the late 1890s,\u2026", "poster": "assets/tv-anne-with-an-e-2017-poster.jpg", "backdrop": "assets/tv-anne-with-an-e-2017-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 70785, "ratings": {"rtCritics": 63, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.7, "tmdbVotes": 5019}}, {"id": "tv-awkward-2011", "title": "Awkward.", "year": 2011, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "An irreverent look at the conflict, chaos and humor that defines teenage life through the eyes of 15-year-old Jenna Hamilton whose life begins to change when a simple accident becomes an epic misunderstanding and is\u2026", "poster": "assets/tv-awkward-2011-poster.jpg", "backdrop": "assets/tv-awkward-2011-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 39859, "ratings": {"rtCritics": 78, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.4, "tmdbVotes": 427}}, {"id": "tv-the-baby-sitters-club-2020", "title": "The Baby-Sitters Club", "year": 2020, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Kids", "Drama"], "overview": "In this contemporary take on the beloved book series, five best friends launch a baby-sitting business that's big on fun and adventure.", "poster": "assets/tv-the-baby-sitters-club-2020-poster.jpg", "backdrop": "assets/tv-the-baby-sitters-club-2020-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 100412, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.9, "tmdbVotes": 506}}, {"id": "tv-ballers-2015", "title": "Ballers", "year": 2015, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Comedy"], "overview": "Looking at the lives of former and current football players, the show follows former superstar Spencer Strasmore as he gets his life on track in retirement while mentoring other current and former players through the\u2026", "poster": "assets/tv-ballers-2015-poster.jpg", "backdrop": "assets/tv-ballers-2015-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 62704, "ratings": {"rtCritics": 72, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.809, "tmdbVotes": 820}}, {"id": "tv-baretta-1975", "title": "Baretta", "year": 1975, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Crime", "Drama", "Mystery"], "overview": "Baretta is an American detective television series which ran on ABC from 1975 to 1978. The show was a milder version of a successful 1973\u201374 ABC series, Toma, starring Tony Musante as chameleon-like, real-life New\u2026", "poster": "assets/tv-baretta-1975-poster.jpg", "backdrop": "assets/tv-baretta-1975-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 3216, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.5, "tmdbVotes": 43}}, {"id": "tv-based-on-a-true-story-2023", "title": "Based on a True Story", "year": 2023, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "The lives of a realtor, a plumber and a former tennis star unexpectedly collide, exposing America\u2019s obsession with true crime, murder and the slow-close toilet seat.", "poster": "assets/tv-based-on-a-true-story-2023-poster.jpg", "backdrop": "assets/tv-based-on-a-true-story-2023-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 197373, "ratings": {"rtCritics": 79, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7, "tmdbVotes": 160}}, {"id": "tv-the-beast-in-me-2025", "title": "The Beast in Me", "year": 2025, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Mystery"], "overview": "A famous author is pulled into a twisted mind game with her rich, powerful new neighbor \u2014 who might be a murderer.", "poster": "assets/tv-the-beast-in-me-2025-poster.jpg", "backdrop": "assets/tv-the-beast-in-me-2025-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 250504, "ratings": {"rtCritics": 85, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.072, "tmdbVotes": 334}}, {"id": "tv-big-city-greens-2018", "title": "Big City Greens", "year": 2018, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Family", "Animation", "Comedy"], "overview": "The offbeat adventures of 10-year-old Cricket Green, a mischievous and optimistic country boy who moves to the big city with his wildly out of place family \u2013 older sister Tilly, father Bill and Gramma Alice.", "poster": "assets/tv-big-city-greens-2018-poster.jpg", "backdrop": "assets/tv-big-city-greens-2018-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 80587, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.555, "tmdbVotes": 82}}, {"id": "tv-the-bold-type-2017", "title": "The Bold Type", "year": 2017, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Comedy"], "overview": "A glimpse into the outrageous lives of Jane, Kat and Sutton, who are working at the nation's top women's magazine, Scarlet, while navigating their careers, identities and individual voices.", "poster": "assets/tv-the-bold-type-2017-poster.jpg", "backdrop": "assets/tv-the-bold-type-2017-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 69630, "ratings": {"rtCritics": 89, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.7, "tmdbVotes": 204}}, {"id": "tv-brassic-2019", "title": "Brassic", "year": 2019, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Comedy", "Drama", "Crime"], "overview": "A group of working-class friends finding unconventional ways to win at life in suburban northern England. These lads have dealt, scammed, bribed and conned their way through adolescence, but now, their dealing and\u2026", "poster": "assets/tv-brassic-2019-poster.jpg", "backdrop": "assets/tv-brassic-2019-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 92621, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.336, "tmdbVotes": 263}}], "discoverySource": {"state": "materialized_snapshot", "rankKnown": false, "selection": "First 18 alphabetically indexed movie stubs and first 18 series stubs, not ranked feed order", "observedAt": "2026-11-04T20:42:12.030108+00:00"}}, {"key": "shared", "name": "Shared", "initial": "S", "color": "#9be38f", "destinations": {"Home": {"kind": "home"}, "Movies": {"kind": "library", "collection": "movies"}, "Shows": {"kind": "library", "collection": "shows"}, "Discover": {"kind": "discover", "collection": "discover"}}, "movies": [{"id": "movie-american-gangster-2007", "title": "American Gangster", "year": 2007, "type": "movie", "runtimeSeconds": 10546, "seasonCount": null, "communityRating": 7.595, "criticRating": 81, "genres": ["Drama", "Crime"], "overview": "Loosely based on the criminal career of Frank Lucas, a gangster from La Grange, North Carolina, who smuggled heroin into the United States on American service planes returning from the Vietnam War, before being\u2026", "poster": "assets/movie-american-gangster-2007-poster.jpg", "backdrop": "assets/movie-american-gangster-2007-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-08-23T10:22:36.0000000Z", "lastPlayedAt": "2026-08-30T21:05:39.7952451Z", "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 4982, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 81, "rtCriticsLabel": "Certified Fresh", "rtAudience": 90, "rtAudienceLabel": "Upright", "imdb": 7.8, "imdbVotes": 495656, "tmdb": 7.599, "tmdbVotes": 6350}}, {"id": "movie-annie-hall-1977", "title": "Annie Hall", "year": 1977, "type": "movie", "runtimeSeconds": 5604, "seasonCount": null, "communityRating": 7.712, "criticRating": 97, "genres": ["Comedy", "Drama", "Romance"], "overview": "New York comedian Alvy Singer falls in love with the ditsy Annie Hall.", "poster": "assets/movie-annie-hall-1977-poster.jpg", "backdrop": "assets/movie-annie-hall-1977-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:24:23.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 703, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 97, "rtCriticsLabel": "Certified Fresh", "rtAudience": 92, "rtAudienceLabel": "Upright", "imdb": 7.9, "imdbVotes": 293349, "tmdb": 7.71, "tmdbVotes": 4391}}, {"id": "movie-apocalypse-now-1979", "title": "Apocalypse Now", "year": 1979, "type": "movie", "runtimeSeconds": 8835, "seasonCount": null, "communityRating": 8.261, "criticRating": 91, "genres": ["Drama", "War"], "overview": "At the height of the Vietnam war, Captain Benjamin Willard is sent on a dangerous mission that, officially, \"does not exist, nor will it ever exist.\" His goal is to locate - and eliminate - a mysterious Green Beret\u2026", "poster": "assets/movie-apocalypse-now-1979-poster.jpg", "backdrop": "assets/movie-apocalypse-now-1979-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:22:25.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 28, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 91, "rtCriticsLabel": "Certified Fresh", "rtAudience": 94, "rtAudienceLabel": "Upright", "imdb": 8.4, "imdbVotes": 781424, "tmdb": 8.3, "tmdbVotes": 9526}}, {"id": "movie-arrival-2016", "title": "Arrival", "year": 2016, "type": "movie", "runtimeSeconds": 6967, "seasonCount": null, "communityRating": 7.636, "criticRating": 94, "genres": ["Drama", "Science Fiction", "Mystery"], "overview": "Taking place after alien crafts land around the world, an expert linguist is recruited by the military to determine whether they come in peace or are a threat.", "poster": "assets/movie-arrival-2016-poster.jpg", "backdrop": "assets/movie-arrival-2016-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-14T19:54:12.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 329865, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 94, "rtCriticsLabel": "Certified Fresh", "rtAudience": 83, "rtAudienceLabel": "Upright", "imdb": 7.9, "imdbVotes": 883621, "tmdb": 7.638, "tmdbVotes": 20125}}, {"id": "movie-avatar-aang-the-last-airbender-2026", "title": "Avatar Aang: The Last Airbender", "year": 2026, "type": "movie", "runtimeSeconds": 5930, "seasonCount": null, "communityRating": 9.147, "criticRating": 90, "genres": ["Animation", "Adventure", "Fantasy"], "overview": "Avatar Aang, the world's last Airbender, learns of an ancient power that could save his culture from extinction. With the help of his friends, he embarks on a global quest to find it before it falls into the wrong\u2026", "poster": "assets/movie-avatar-aang-the-last-airbender-2026-poster.jpg", "backdrop": "assets/movie-avatar-aang-the-last-airbender-2026-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-25T09:53:09.0000000Z", "lastPlayedAt": "2026-08-02T19:22:33.6155383Z", "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 980431, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 90, "rtCriticsLabel": "Certified Fresh", "rtAudience": 99, "rtAudienceLabel": "Upright", "imdb": 7.7, "imdbVotes": 30792, "tmdb": 9, "tmdbVotes": 1417}}, {"id": "movie-bohemian-rhapsody-2018", "title": "Bohemian Rhapsody", "year": 2018, "type": "movie", "runtimeSeconds": 8077, "seasonCount": null, "communityRating": 7.95, "criticRating": 60, "genres": ["Music", "Drama"], "overview": "Singer Freddie Mercury, guitarist Brian May, drummer Roger Taylor and bass guitarist John Deacon take the music world by storm when they form the rock 'n' roll band Queen in 1970. Hit songs become instant classics.\u2026", "poster": "assets/movie-bohemian-rhapsody-2018-poster.jpg", "backdrop": "assets/movie-bohemian-rhapsody-2018-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:28:20.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 424694, "artwork": {"posterKind": "center_crop", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 60, "rtCriticsLabel": "Fresh", "rtAudience": 85, "rtAudienceLabel": "Upright", "imdb": 7.9, "imdbVotes": 655894, "tmdb": 7.947, "tmdbVotes": 18196}}, {"id": "movie-the-boy-and-the-heron-2023", "title": "The Boy and the Heron", "year": 2023, "type": "movie", "runtimeSeconds": 7437, "seasonCount": null, "communityRating": 7.4, "criticRating": 96, "genres": ["Animation", "Fantasy", "Drama"], "overview": "While the Second World War rages, the teenage Mahito, haunted by his mother's tragic death, is relocated from Tokyo to the serene rural home of his new stepmother Natsuko, a woman who bears a striking resemblance to\u2026", "poster": "assets/movie-the-boy-and-the-heron-2023-poster.jpg", "backdrop": "assets/movie-the-boy-and-the-heron-2023-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:25:15.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 508883, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 96, "rtCriticsLabel": "Certified Fresh", "rtAudience": 88, "rtAudienceLabel": "Upright", "imdb": 7.3, "imdbVotes": 152169, "tmdb": 7.387, "tmdbVotes": 2893}}, {"id": "movie-braveheart-1995", "title": "Braveheart", "year": 1995, "type": "movie", "runtimeSeconds": 10665, "seasonCount": null, "communityRating": 7.945, "criticRating": 74, "genres": ["Drama", "History", "War"], "overview": "Enraged at the slaughter of Murron, his new bride and childhood love, Scottish warrior William Wallace slays a platoon of the local English lord's soldiers. This leads the village to revolt and, eventually, the\u2026", "poster": "assets/movie-braveheart-1995-poster.jpg", "backdrop": "assets/movie-braveheart-1995-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-10T21:24:28.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 197, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 74, "rtCriticsLabel": "Certified Fresh", "rtAudience": 85, "rtAudienceLabel": "Upright", "imdb": 8.3, "imdbVotes": 1174990, "tmdb": 7.947, "tmdbVotes": 11584}}, {"id": "movie-the-breakfast-club-1985", "title": "The Breakfast Club", "year": 1985, "type": "movie", "runtimeSeconds": 5833, "seasonCount": null, "communityRating": 7.7, "criticRating": 87, "genres": ["Comedy", "Drama"], "overview": "Five high school students from different walks of life endure a Saturday detention under a power-hungry principal. The disparate group includes rebel John, princess Claire, outcast Allison, brainy Brian and Andrew,\u2026", "poster": "assets/movie-the-breakfast-club-1985-poster.jpg", "backdrop": "assets/movie-the-breakfast-club-1985-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:25:03.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 2108, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 87, "rtCriticsLabel": "Certified Fresh", "rtAudience": 92, "rtAudienceLabel": "Upright", "imdb": 7.8, "imdbVotes": 478743, "tmdb": 7.713, "tmdbVotes": 8815}}, {"id": "movie-castle-in-the-sky-1986", "title": "Castle in the Sky", "year": 1986, "type": "movie", "runtimeSeconds": 7474, "seasonCount": null, "communityRating": 8, "criticRating": 97, "genres": ["Adventure", "Fantasy", "Animation"], "overview": "A young boy and a girl with a magic crystal must race against pirates and foreign agents in a search for a legendary floating castle.", "poster": "assets/movie-castle-in-the-sky-1986-poster.jpg", "backdrop": "assets/movie-castle-in-the-sky-1986-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:23:09.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 10515, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 96, "rtCriticsLabel": "Fresh", "rtAudience": 91, "rtAudienceLabel": "Upright", "imdb": 8, "imdbVotes": 201545, "tmdb": 7.972, "tmdbVotes": 4868}}, {"id": "movie-citizen-kane-1941", "title": "Citizen Kane", "year": 1941, "type": "movie", "runtimeSeconds": 7173, "seasonCount": null, "communityRating": 7.966, "criticRating": 99, "genres": ["Mystery", "Drama"], "overview": "Newspaper magnate Charles Foster Kane is taken from his mother as a boy and made the ward of a rich industrialist. As a result, every well-meaning, tyrannical or self-destructive move he makes for the rest of his\u2026", "poster": "assets/movie-citizen-kane-1941-poster.jpg", "backdrop": "assets/movie-citizen-kane-1941-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:22:16.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 15, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 99, "rtCriticsLabel": "Certified Fresh", "rtAudience": 98, "rtAudienceLabel": "Upright", "imdb": 8.2, "imdbVotes": 498321, "tmdb": 7.962, "tmdbVotes": 6324}}, {"id": "movie-conclave-2024", "title": "Conclave", "year": 2024, "type": "movie", "runtimeSeconds": 7230, "seasonCount": null, "communityRating": 7.19, "criticRating": 93, "genres": ["Drama", "Thriller"], "overview": "After the unexpected death of the Pope, Cardinal Lawrence is tasked with managing the covert and ancient ritual of electing a new one. Sequestered in the Vatican with the Catholic Church\u2019s most powerful leaders until\u2026", "poster": "assets/movie-conclave-2024-poster.jpg", "backdrop": "assets/movie-conclave-2024-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:30:41.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 974576, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 93, "rtCriticsLabel": "Certified Fresh", "rtAudience": 86, "rtAudienceLabel": "Upright", "imdb": 7.4, "imdbVotes": 290498, "tmdb": 7.19, "tmdbVotes": 3744}}, {"id": "movie-the-dry-2021", "title": "The Dry", "year": 2021, "type": "movie", "runtimeSeconds": 7037, "seasonCount": null, "communityRating": 6.779, "criticRating": null, "genres": ["Crime", "Thriller", "Mystery"], "overview": "Aaron Falk returns to his drought-stricken hometown to attend a tragic funeral. But his return opens a decades-old wound - the unsolved death of a teenage girl.", "poster": "assets/movie-the-dry-2021-poster.jpg", "backdrop": "assets/movie-the-dry-2021-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:29:20.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 567797, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 90, "rtCriticsLabel": "Certified Fresh", "rtAudience": 89, "rtAudienceLabel": "Upright", "imdb": 6.8, "imdbVotes": 41935, "tmdb": 6.8, "tmdbVotes": 892}}, {"id": "movie-easy-a-2010", "title": "Easy A", "year": 2010, "type": "movie", "runtimeSeconds": 5545, "seasonCount": null, "communityRating": 6.8, "criticRating": 85, "genres": ["Comedy"], "overview": "Olive, an average high school student, sees her below-the-radar existence turn around overnight once she decides to use the school's gossip grapevine to advance her social standing. Now her classmates are turning\u2026", "poster": "assets/movie-easy-a-2010-poster.jpg", "backdrop": "assets/movie-easy-a-2010-backdrop.jpg", "played": true, "playCount": 1, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-17T19:59:04.0000000Z", "lastPlayedAt": "2026-10-17T20:02:51.1083337Z", "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 37735, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 85, "rtCriticsLabel": "Certified Fresh", "rtAudience": 77, "rtAudienceLabel": "Upright", "imdb": 7, "imdbVotes": 448780, "tmdb": 6.8, "tmdbVotes": 7619}}, {"id": "movie-el-camino-a-breaking-bad-movie-2019", "title": "El Camino: A Breaking Bad Movie", "year": 2019, "type": "movie", "runtimeSeconds": 7362, "seasonCount": null, "communityRating": 7.055, "criticRating": 92, "genres": ["Crime", "Drama", "Thriller"], "overview": "In the wake of his dramatic escape from captivity, Jesse Pinkman must come to terms with his past in order to forge some kind of future.", "poster": "assets/movie-el-camino-a-breaking-bad-movie-2019-poster.jpg", "backdrop": "assets/movie-el-camino-a-breaking-bad-movie-2019-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-21T23:31:11.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 559969, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 92, "rtCriticsLabel": "Certified Fresh", "rtAudience": 81, "rtAudienceLabel": "Upright", "imdb": 7.3, "imdbVotes": 354488, "tmdb": 7.056, "tmdbVotes": 5950}}, {"id": "movie-emancipation-2022", "title": "Emancipation", "year": 2022, "type": "movie", "runtimeSeconds": 7949, "seasonCount": null, "communityRating": 7.7, "criticRating": 45, "genres": ["Drama", "War", "History"], "overview": "Inspired by the gripping true story of a man who would do anything for his family\u2014and for freedom. When Peter, an enslaved man, risks his life to escape and return to his family, he embarks on a perilous journey of\u2026", "poster": "assets/movie-emancipation-2022-poster.jpg", "backdrop": "assets/movie-emancipation-2022-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-10T20:37:34.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 715931, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 45, "rtCriticsLabel": "Rotten", "rtAudience": 58, "rtAudienceLabel": "Spilled", "imdb": 6.3, "imdbVotes": 32079, "tmdb": 7.744, "tmdbVotes": 1319}}, {"id": "movie-fighting-with-my-family-2019", "title": "Fighting with My Family", "year": 2019, "type": "movie", "runtimeSeconds": 6509, "seasonCount": null, "communityRating": 6.84, "criticRating": 93, "genres": ["Comedy"], "overview": "Born into a tight-knit wrestling family, Paige and her brother Zak are ecstatic when they get the once-in-a-lifetime opportunity to try out for the WWE. But when only Paige earns a spot in the competitive training\u2026", "poster": "assets/movie-fighting-with-my-family-2019-poster.jpg", "backdrop": "assets/movie-fighting-with-my-family-2019-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-22T22:10:59.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 445629, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 93, "rtCriticsLabel": "Certified Fresh", "rtAudience": 86, "rtAudienceLabel": "Upright", "imdb": 7, "imdbVotes": 94576, "tmdb": 6.837, "tmdbVotes": 1952}}, {"id": "movie-force-of-nature-the-dry-2-2024", "title": "Force of Nature: The Dry 2", "year": 2024, "type": "movie", "runtimeSeconds": 6753, "seasonCount": null, "communityRating": 6.3, "criticRating": 66, "genres": ["Mystery", "Thriller"], "overview": "When five women take part in a corporate hiking retreat and only four come out on the other side, Federal Agents Aaron Falk and Carmen Cooper head deep into the Victorian mountain ranges to investigate in the hopes\u2026", "poster": "assets/movie-force-of-nature-the-dry-2-2024-poster.jpg", "backdrop": "assets/movie-force-of-nature-the-dry-2-2024-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:29:49.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 832262, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 66, "rtCriticsLabel": "Fresh", "rtAudience": 43, "rtAudienceLabel": "Spilled", "imdb": 5.9, "imdbVotes": 10343, "tmdb": 6.269, "tmdbVotes": 305}}, {"id": "movie-free-state-of-jones-2016", "title": "Free State of Jones", "year": 2016, "type": "movie", "runtimeSeconds": 8376, "seasonCount": null, "communityRating": 6.79, "criticRating": 48, "genres": ["Action", "Drama", "History"], "overview": "In 1863, Mississippi farmer Newt Knight serves as a medic for the Confederate Army. Opposed to slavery, Knight would rather help the wounded than fight the Union. After his nephew dies in battle, Newt returns home to\u2026", "poster": "assets/movie-free-state-of-jones-2016-poster.jpg", "backdrop": "assets/movie-free-state-of-jones-2016-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-11T17:56:53.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 316152, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 48, "rtCriticsLabel": "Rotten", "rtAudience": 64, "rtAudienceLabel": "Upright", "imdb": 6.9, "imdbVotes": 68931, "tmdb": 6.788, "tmdbVotes": 1730}}, {"id": "movie-from-up-on-poppy-hill-2011", "title": "From Up on Poppy Hill", "year": 2011, "type": "movie", "runtimeSeconds": 5482, "seasonCount": null, "communityRating": 7.5, "criticRating": 87, "genres": ["Animation", "Drama"], "overview": "Yokohama, 1963. Japan is picking itself up from the devastation of World War II and preparing to host the 1964 Olympics\u2014and the mood is one of both optimism and conflict as the young generation struggles to throw off\u2026", "poster": "assets/movie-from-up-on-poppy-hill-2011-poster.jpg", "backdrop": "assets/movie-from-up-on-poppy-hill-2011-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-07T14:41:03.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 83389, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 87, "rtCriticsLabel": "Certified Fresh", "rtAudience": 80, "rtAudienceLabel": "Upright", "imdb": 7.4, "imdbVotes": 60769, "tmdb": 7.509, "tmdbVotes": 2026}}, {"id": "movie-ghost-in-the-shell-1995", "title": "Ghost in the Shell", "year": 1995, "type": "movie", "runtimeSeconds": 4959, "seasonCount": null, "communityRating": 7.929, "criticRating": 95, "genres": ["Action", "Animation", "Science Fiction"], "overview": "In the year 2029, the barriers of our world have been broken down by the net and by cybernetics, but this brings new vulnerability to humans in the form of brain-hacking. When a highly-wanted hacker known as 'The\u2026", "poster": "assets/movie-ghost-in-the-shell-1995-poster.jpg", "backdrop": "assets/movie-ghost-in-the-shell-1995-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:22:57.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 9323, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 97, "rtCriticsLabel": "Certified Fresh", "rtAudience": 90, "rtAudienceLabel": "Upright", "imdb": 7.9, "imdbVotes": 178061, "tmdb": 7.928, "tmdbVotes": 4130}}, {"id": "movie-ghost-in-the-shell-2-innocence-2004", "title": "Ghost in the Shell 2: Innocence", "year": 2004, "type": "movie", "runtimeSeconds": 5950, "seasonCount": null, "communityRating": 7.352, "criticRating": 65, "genres": ["Animation", "Drama", "Science Fiction"], "overview": "Cyborg detective Batou is assigned to investigate a series of murders committed by gynoids\u2014doll-like cyborgs, which all malfunctioned, killed, then self-destructed afterwards. The brains of the gynoids initialize in\u2026", "poster": "assets/movie-ghost-in-the-shell-2-innocence-2004-poster.jpg", "backdrop": "assets/movie-ghost-in-the-shell-2-innocence-2004-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:23:38.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 12140, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 65, "rtCriticsLabel": "Fresh", "rtAudience": 80, "rtAudienceLabel": "Upright", "imdb": 7.4, "imdbVotes": 43280, "tmdb": 7.356, "tmdbVotes": 1049}}, {"id": "movie-the-godfather-1972", "title": "The Godfather", "year": 1972, "type": "movie", "runtimeSeconds": 10603, "seasonCount": null, "communityRating": 8.687, "criticRating": 97, "genres": ["Drama", "Crime"], "overview": "Spanning the years 1945 to 1955, a chronicle of the fictional Italian-American Corleone crime family. When organized crime family patriarch, Vito Corleone barely survives an attempt on his life, his youngest son,\u2026", "poster": "assets/movie-the-godfather-1972-poster.jpg", "backdrop": "assets/movie-the-godfather-1972-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:24:12.0000000Z", "lastPlayedAt": "2026-09-18T19:24:44.9855867Z", "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 238, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 97, "rtCriticsLabel": "Certified Fresh", "rtAudience": 98, "rtAudienceLabel": "Upright", "imdb": 9.2, "imdbVotes": 2262024, "tmdb": 8.688, "tmdbVotes": 23907}}, {"id": "movie-the-godfather-part-ii-1974", "title": "The Godfather Part II", "year": 1974, "type": "movie", "runtimeSeconds": 12031, "seasonCount": null, "communityRating": 8.573, "criticRating": 96, "genres": ["Drama", "Crime"], "overview": "In the continuing saga of the Corleone crime family, a young Vito Corleone grows up in Sicily and in 1910s New York. In the 1950s, Michael Corleone attempts to expand the family business into Las Vegas, Hollywood and\u2026", "poster": "assets/movie-the-godfather-part-ii-1974-poster.jpg", "backdrop": "assets/movie-the-godfather-part-ii-1974-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:24:18.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 240, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 96, "rtCriticsLabel": "Certified Fresh", "rtAudience": 97, "rtAudienceLabel": "Upright", "imdb": 9, "imdbVotes": 1521308, "tmdb": 8.571, "tmdbVotes": 14559}}, {"id": "movie-the-godfather-part-iii-1990", "title": "The Godfather Part III", "year": 1990, "type": "movie", "runtimeSeconds": 9476, "seasonCount": null, "communityRating": 7.416, "criticRating": 67, "genres": ["Crime", "Drama", "Thriller"], "overview": "In the midst of trying to legitimize his business dealings in 1979 New York and Italy, aging mafia don, Michael Corleone seeks forgiveness for his sins while taking a young protege under his wing.", "poster": "assets/movie-the-godfather-part-iii-1990-poster.jpg", "backdrop": "assets/movie-the-godfather-part-iii-1990-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:26:29.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 242, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 68, "rtCriticsLabel": "Fresh", "rtAudience": 68, "rtAudienceLabel": "Upright", "imdb": 7.5, "imdbVotes": 462448, "tmdb": 7.413, "tmdbVotes": 7159}}, {"id": "movie-gosford-park-2001", "title": "Gosford Park", "year": 2001, "type": "movie", "runtimeSeconds": 8247, "seasonCount": null, "communityRating": 6.815, "criticRating": 87, "genres": ["Drama", "Mystery", "Thriller"], "overview": "In 1930s England, a group of pretentious rich and famous gather together for a weekend of relaxation at a hunting resort. But when a murder occurs, each one of these interesting characters becomes a suspect.", "poster": "assets/movie-gosford-park-2001-poster.jpg", "backdrop": "assets/movie-gosford-park-2001-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:25:49.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 5279, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 87, "rtCriticsLabel": "Certified Fresh", "rtAudience": 78, "rtAudienceLabel": "Upright", "imdb": 7.2, "imdbVotes": 103883, "tmdb": 6.822, "tmdbVotes": 1317}}, {"id": "movie-grave-of-the-fireflies-1988", "title": "Grave of the Fireflies", "year": 1988, "type": "movie", "runtimeSeconds": 5313, "seasonCount": null, "communityRating": 8.45, "criticRating": 100, "genres": ["Animation", "Drama", "War"], "overview": "In the final months of World War II, 14-year-old Seita and his sister Setsuko are orphaned when their mother is killed during an air raid in Kobe, Japan. After a falling out with their aunt, they move into an\u2026", "poster": "assets/movie-grave-of-the-fireflies-1988-poster.jpg", "backdrop": "assets/movie-grave-of-the-fireflies-1988-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:24:14.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 12477, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Certified Fresh", "rtAudience": 95, "rtAudienceLabel": "Upright", "imdb": 8.5, "imdbVotes": 399802, "tmdb": 8.45, "tmdbVotes": 6938}}, {"id": "movie-the-great-gatsby-2013", "title": "The Great Gatsby", "year": 2013, "type": "movie", "runtimeSeconds": 8525, "seasonCount": null, "communityRating": 7.346, "criticRating": 49, "genres": ["Drama", "Romance"], "overview": "Nick Carraway arrives in New York in 1922, an era of loose morals, glittering jazz and bootleg kings. Chasing his own American Dream, Nick encounters the mysterious millionaire Gatsby and his bewitching cousin Daisy.\u2026", "poster": "assets/movie-the-great-gatsby-2013-poster.jpg", "backdrop": "assets/movie-the-great-gatsby-2013-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:26:50.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 64682, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 48, "rtCriticsLabel": "Rotten", "rtAudience": 67, "rtAudienceLabel": "Upright", "imdb": 7.2, "imdbVotes": 651882, "tmdb": 7.346, "tmdbVotes": 13290}}, {"id": "movie-the-hours-2002", "title": "The Hours", "year": 2002, "type": "movie", "runtimeSeconds": 6887, "seasonCount": null, "communityRating": 7.25, "criticRating": 79, "genres": ["Drama"], "overview": "The story of three women searching for more potent, meaningful lives. Each is alive at a different time and place, all are linked by their yearnings and their fears. Their stories intertwine, and finally come\u2026", "poster": "assets/movie-the-hours-2002-poster.jpg", "backdrop": "assets/movie-the-hours-2002-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:23:27.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 590, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 79, "rtCriticsLabel": "Certified Fresh", "rtAudience": 84, "rtAudienceLabel": "Upright", "imdb": 7.5, "imdbVotes": 148367, "tmdb": 7.249, "tmdbVotes": 1931}}, {"id": "movie-howl-s-moving-castle-2004", "title": "Howl's Moving Castle", "year": 2004, "type": "movie", "runtimeSeconds": 7149, "seasonCount": null, "communityRating": 8.4, "criticRating": 88, "genres": ["Fantasy", "Animation", "Adventure"], "overview": "Sophie, a young milliner, is turned into an elderly woman by a witch who enters her shop and curses her. She encounters a wizard named Howl and gets caught up in his resistance to fighting for the king.", "poster": "assets/movie-howl-s-moving-castle-2004-poster.jpg", "backdrop": "assets/movie-howl-s-moving-castle-2004-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:22:47.0000000Z", "lastPlayedAt": "2026-05-21T18:46:08.0000000Z", "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 4935, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 87, "rtCriticsLabel": "Certified Fresh", "rtAudience": 93, "rtAudienceLabel": "Upright", "imdb": 8.2, "imdbVotes": 524520, "tmdb": 8.391, "tmdbVotes": 11642}}, {"id": "movie-in-the-heights-2021", "title": "In the Heights", "year": 2021, "type": "movie", "runtimeSeconds": 8579, "seasonCount": null, "communityRating": 7.111, "criticRating": null, "genres": ["Drama", "Romance"], "overview": "The story of Usnavi, a bodega owner who has mixed feelings about closing his store and retiring to the Dominican Republic or staying in Washington Heights.", "poster": "assets/movie-in-the-heights-2021-poster.jpg", "backdrop": "assets/movie-in-the-heights-2021-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:29:11.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 467909, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 94, "rtCriticsLabel": "Certified Fresh", "rtAudience": 94, "rtAudienceLabel": "Upright", "imdb": 7.2, "imdbVotes": 56513, "tmdb": 7.104, "tmdbVotes": 826}}, {"id": "movie-jennifer-s-body-2009", "title": "Jennifer's Body", "year": 2009, "type": "movie", "runtimeSeconds": 6450, "seasonCount": null, "communityRating": 6.012, "criticRating": 47, "genres": ["Horror", "Comedy"], "overview": "Jennifer, a gorgeous, seductive cheerleader takes evil to a whole new level after she's possessed by a sinister demon. Now it's up to her best friend to stop Jennifer's reign of terror before it's too late.", "poster": "assets/movie-jennifer-s-body-2009-poster.jpg", "backdrop": "assets/movie-jennifer-s-body-2009-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-30T03:37:04.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 19994, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 47, "rtCriticsLabel": "Rotten", "rtAudience": 36, "rtAudienceLabel": "Spilled", "imdb": 5.6, "imdbVotes": 179710, "tmdb": 6.013, "tmdbVotes": 4481}}, {"id": "movie-kiki-s-delivery-service-1989", "title": "Kiki's Delivery Service", "year": 1989, "type": "movie", "runtimeSeconds": 6183, "seasonCount": null, "communityRating": 7.839, "criticRating": null, "genres": ["Animation", "Family", "Fantasy"], "overview": "A young witch, on her mandatory year of independent life, finds fitting into a new community difficult while she supports herself by running an air courier service.", "poster": "assets/movie-kiki-s-delivery-service-1989-poster.jpg", "backdrop": "assets/movie-kiki-s-delivery-service-1989-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:24:20.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 16859, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 98, "rtCriticsLabel": "Certified Fresh", "rtAudience": 89, "rtAudienceLabel": "Upright", "imdb": 7.8, "imdbVotes": 192477, "tmdb": 7.839, "tmdbVotes": 4811}}, {"id": "movie-the-last-of-the-mohicans-1992", "title": "The Last of the Mohicans", "year": 1992, "type": "movie", "runtimeSeconds": 6874, "seasonCount": null, "communityRating": 7.388, "criticRating": 88, "genres": ["History", "War", "Drama"], "overview": "In war-torn colonial America, in the midst of a bloody battle between British, the French and Native American allies, the aristocratic daughter of a British Colonel and her party are captured by a group of Huron\u2026", "poster": "assets/movie-the-last-of-the-mohicans-1992-poster.jpg", "backdrop": "assets/movie-the-last-of-the-mohicans-1992-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-10T20:59:22.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 9361, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 88, "rtCriticsLabel": "Certified Fresh", "rtAudience": 88, "rtAudienceLabel": "Upright", "imdb": 7.6, "imdbVotes": 210791, "tmdb": 7.39, "tmdbVotes": 3593}}, {"id": "movie-the-last-samurai-2003", "title": "The Last Samurai", "year": 2003, "type": "movie", "runtimeSeconds": 9251, "seasonCount": null, "communityRating": 7.61, "criticRating": 65, "genres": ["Drama", "Action", "War"], "overview": "Nathan Algren is an American hired to instruct the Japanese army in the ways of modern warfare, which finds him learning to respect the samurai and the honorable principles that rule them. Pressed to destroy the\u2026", "poster": "assets/movie-the-last-samurai-2003-poster.jpg", "backdrop": "assets/movie-the-last-samurai-2003-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-26T05:25:10.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 616, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 66, "rtCriticsLabel": "Fresh", "rtAudience": 83, "rtAudienceLabel": "Upright", "imdb": 7.8, "imdbVotes": 512982, "tmdb": 7.614, "tmdbVotes": 7887}}, {"id": "movie-lemony-snicket-s-a-series-of-unfortunate-events-2004", "title": "Lemony Snicket's A Series of Unfortunate Events", "year": 2004, "type": "movie", "runtimeSeconds": 6479, "seasonCount": null, "communityRating": 6.8, "criticRating": 72, "genres": ["Adventure", "Comedy", "Family"], "overview": "Three wealthy children's parents are killed in a fire. When they are sent to a distant relative, they find out that he is plotting to kill them and seize their fortune.", "poster": "assets/movie-lemony-snicket-s-a-series-of-unfortunate-events-2004-poster.jpg", "backdrop": "assets/movie-lemony-snicket-s-a-series-of-unfortunate-events-2004-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:26:09.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 11774, "artwork": {"posterKind": "center_crop", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 72, "rtCriticsLabel": "Fresh", "rtAudience": 63, "rtAudienceLabel": "Upright", "imdb": 6.8, "imdbVotes": 233636, "tmdb": 6.82, "tmdbVotes": 5447}}, {"id": "movie-the-lighthouse-2019", "title": "The Lighthouse", "year": 2019, "type": "movie", "runtimeSeconds": 6549, "seasonCount": null, "communityRating": 7.463, "criticRating": 90, "genres": ["Drama", "Fantasy", "Thriller"], "overview": "Two lighthouse keepers try to maintain their sanity while living on a remote and mysterious New England island in the 1890s.", "poster": "assets/movie-the-lighthouse-2019-poster.jpg", "backdrop": "assets/movie-the-lighthouse-2019-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:29:01.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 503919, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 90, "rtCriticsLabel": "Certified Fresh", "rtAudience": 72, "rtAudienceLabel": "Upright", "imdb": 7.3, "imdbVotes": 312344, "tmdb": 7.46, "tmdbVotes": 5895}}, {"id": "movie-locke-2014", "title": "Locke", "year": 2014, "type": "movie", "runtimeSeconds": 5090, "seasonCount": null, "communityRating": 6.888, "criticRating": 91, "genres": ["Drama", "Thriller"], "overview": "Ivan Locke has worked hard to craft a good life for himself. Tonight, that life will collapse around him. On the eve of the biggest challenge of his career, Ivan receives a phone call that sets in motion a series of\u2026", "poster": "assets/movie-locke-2014-poster.jpg", "backdrop": "assets/movie-locke-2014-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T17:38:48.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 210479, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 90, "rtCriticsLabel": "Certified Fresh", "rtAudience": 72, "rtAudienceLabel": "Upright", "imdb": 7.1, "imdbVotes": 171265, "tmdb": 6.889, "tmdbVotes": 3088}}, {"id": "movie-the-matrix-1999", "title": "The Matrix", "year": 1999, "type": "movie", "runtimeSeconds": 8179, "seasonCount": null, "communityRating": 8.259, "criticRating": 83, "genres": ["Action", "Science Fiction"], "overview": "Set in the 22nd century, The Matrix tells the story of a computer hacker who joins a group of underground insurgents fighting the vast and powerful computers who now rule the earth.", "poster": "assets/movie-the-matrix-1999-poster.jpg", "backdrop": "assets/movie-the-matrix-1999-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:18:12.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 603, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 83, "rtCriticsLabel": "Certified Fresh", "rtAudience": 85, "rtAudienceLabel": "Upright", "imdb": 8.7, "imdbVotes": 2289808, "tmdb": 8.262, "tmdbVotes": 29153}}, {"id": "movie-the-matrix-reloaded-2003", "title": "The Matrix Reloaded", "year": 2003, "type": "movie", "runtimeSeconds": 8298, "seasonCount": null, "communityRating": 7.085, "criticRating": 74, "genres": ["Adventure", "Action", "Thriller"], "overview": "The Resistance builds in numbers as humans are freed from the Matrix and brought to the city of Zion. Neo discovers his superpowers, including the ability to see the code inside the Matrix. With machine sentinels\u2026", "poster": "assets/movie-the-matrix-reloaded-2003-poster.jpg", "backdrop": "assets/movie-the-matrix-reloaded-2003-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:24:03.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 604, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 73, "rtCriticsLabel": "Certified Fresh", "rtAudience": 72, "rtAudienceLabel": "Upright", "imdb": 7.2, "imdbVotes": 678013, "tmdb": 7.087, "tmdbVotes": 12504}}, {"id": "movie-the-matrix-resurrections-2021", "title": "The Matrix Resurrections", "year": 2021, "type": "movie", "runtimeSeconds": 8875, "seasonCount": null, "communityRating": 6.303, "criticRating": 63, "genres": ["Science Fiction", "Action", "Adventure"], "overview": "Plagued by strange memories, Neo's life takes an unexpected turn when he finds himself back inside the Matrix.", "poster": "assets/movie-the-matrix-resurrections-2021-poster.jpg", "backdrop": "assets/movie-the-matrix-resurrections-2021-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:31:22.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 624860, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 63, "rtCriticsLabel": "Fresh", "rtAudience": 63, "rtAudienceLabel": "Upright", "imdb": 5.6, "imdbVotes": 307780, "tmdb": 6.294, "tmdbVotes": 6842}}, {"id": "movie-the-matrix-revolutions-2003", "title": "The Matrix Revolutions", "year": 2003, "type": "movie", "runtimeSeconds": 7756, "seasonCount": null, "communityRating": 6.758, "criticRating": 33, "genres": ["Adventure", "Action", "Thriller"], "overview": "The human city of Zion defends itself against the massive invasion of the machines as Neo fights to end the war at another front while also opposing the rogue Agent Smith.", "poster": "assets/movie-the-matrix-revolutions-2003-poster.jpg", "backdrop": "assets/movie-the-matrix-revolutions-2003-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:25:47.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 605, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 34, "rtCriticsLabel": "Rotten", "rtAudience": 60, "rtAudienceLabel": "Upright", "imdb": 6.8, "imdbVotes": 581553, "tmdb": 6.762, "tmdbVotes": 11292}}, {"id": "movie-mercy-2026", "title": "Mercy", "year": 2026, "type": "movie", "runtimeSeconds": 5968, "seasonCount": null, "communityRating": 7.077, "criticRating": null, "genres": ["Science Fiction", "Thriller", "Crime"], "overview": "In the near future, a detective stands on trial accused of murdering his wife. He has ninety minutes to prove his innocence to the advanced AI Judge he once championed, before it determines his fate.", "poster": "assets/movie-mercy-2026-poster.jpg", "backdrop": "assets/movie-mercy-2026-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:31:40.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 1236153, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 24, "rtCriticsLabel": "Rotten", "rtAudience": 81, "rtAudienceLabel": "Upright", "imdb": 6.2, "imdbVotes": 83878, "tmdb": 7.054, "tmdbVotes": 1812}}, {"id": "movie-normal-2026", "title": "Normal", "year": 2026, "type": "movie", "runtimeSeconds": 5514, "seasonCount": null, "communityRating": 7.267, "criticRating": 77, "genres": ["Action", "Crime", "Thriller"], "overview": "An unassuming substitute sheriff with a troubled past responds to a bank robbery in a small, sleepy town and unknowingly uncovers something far more explosive.", "poster": "assets/movie-normal-2026-poster.jpg", "backdrop": "assets/movie-normal-2026-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-08-21T08:33:18.0000000Z", "lastPlayedAt": "2026-09-24T23:07:52.1161581Z", "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 1242332, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 78, "rtCriticsLabel": "Certified Fresh", "rtAudience": 75, "rtAudienceLabel": "Upright", "imdb": 6.3, "imdbVotes": 37501, "tmdb": 7.241, "tmdbVotes": 786}}, {"id": "movie-outlaw-king-2018", "title": "Outlaw King", "year": 2018, "type": "movie", "runtimeSeconds": 7297, "seasonCount": null, "communityRating": 6.829, "criticRating": 63, "genres": ["Action", "History", "War"], "overview": "Forced into exile by the English after being crowned King of Scotland, legendary warrior Robert the Bruce fights to reclaim the throne.", "poster": "assets/movie-outlaw-king-2018-poster.jpg", "backdrop": "assets/movie-outlaw-king-2018-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:28:32.0000000Z", "lastPlayedAt": "2026-07-26T22:35:35.0000000Z", "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 454227, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 63, "rtCriticsLabel": "Fresh", "rtAudience": 69, "rtAudienceLabel": "Upright", "imdb": 6.9, "imdbVotes": 89876, "tmdb": 6.844, "tmdbVotes": 1780}}, {"id": "movie-panic-room-2002", "title": "Panic Room", "year": 2002, "type": "movie", "runtimeSeconds": 6717, "seasonCount": null, "communityRating": 6.794, "criticRating": 76, "genres": ["Crime", "Drama", "Thriller"], "overview": "Trapped in their New York brownstone's panic room, a hidden chamber built as a sanctuary in the event of break-ins, newly divorced Meg Altman and her young daughter Sarah play a deadly game of cat-and-mouse with\u2026", "poster": "assets/movie-panic-room-2002-poster.jpg", "backdrop": "assets/movie-panic-room-2002-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-19T20:50:01.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 4547, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 76, "rtCriticsLabel": "Certified Fresh", "rtAudience": 64, "rtAudienceLabel": "Upright", "imdb": 6.8, "imdbVotes": 317468, "tmdb": 6.796, "tmdbVotes": 5653}}, {"id": "movie-the-patriot-2000", "title": "The Patriot", "year": 2000, "type": "movie", "runtimeSeconds": 9887, "seasonCount": null, "communityRating": 7.214, "criticRating": 61, "genres": ["Drama", "History", "War"], "overview": "After proving himself on the field of battle in the French and Indian War, Benjamin Martin wants nothing more to do with such things, preferring the simple life of a farmer. But when his son Gabriel enlists in the\u2026", "poster": "assets/movie-the-patriot-2000-poster.jpg", "backdrop": "assets/movie-the-patriot-2000-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-10T20:50:00.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 2024, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 61, "rtCriticsLabel": "Fresh", "rtAudience": 81, "rtAudienceLabel": "Upright", "imdb": 7.2, "imdbVotes": 317639, "tmdb": 7.215, "tmdbVotes": 4535}}, {"id": "movie-peaky-blinders-the-immortal-man-2026", "title": "Peaky Blinders: The Immortal Man", "year": 2026, "type": "movie", "runtimeSeconds": 6844, "seasonCount": null, "communityRating": 7.187, "criticRating": 90, "genres": ["Crime", "Drama"], "overview": "After his estranged son gets embroiled in a Nazi plot, self-exiled gangster Tommy Shelby must return to Birmingham to save his family \u2014 and his nation.", "poster": "assets/movie-peaky-blinders-the-immortal-man-2026-poster.jpg", "backdrop": "assets/movie-peaky-blinders-the-immortal-man-2026-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:30:01.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 875828, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 90, "rtCriticsLabel": "Certified Fresh", "rtAudience": 87, "rtAudienceLabel": "Upright", "imdb": 6.5, "imdbVotes": 92130, "tmdb": 7.189, "tmdbVotes": 1304}}, {"id": "movie-ponyo-2008", "title": "Ponyo", "year": 2008, "type": "movie", "runtimeSeconds": 6530, "seasonCount": null, "communityRating": 7.763, "criticRating": 91, "genres": ["Animation", "Fantasy", "Family"], "overview": "When Sosuke, a young boy who lives on a clifftop overlooking the sea, rescues a stranded goldfish named Ponyo, he discovers more than he bargained for. Ponyo is a curious, energetic young creature who yearns to be\u2026", "poster": "assets/movie-ponyo-2008-poster.jpg", "backdrop": "assets/movie-ponyo-2008-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:23:53.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 12429, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 91, "rtCriticsLabel": "Certified Fresh", "rtAudience": 84, "rtAudienceLabel": "Upright", "imdb": 7.6, "imdbVotes": 190294, "tmdb": 7.759, "tmdbVotes": 5050}}, {"id": "movie-porco-rosso-1992", "title": "Porco Rosso", "year": 1992, "type": "movie", "runtimeSeconds": 5600, "seasonCount": null, "communityRating": 7.794, "criticRating": 96, "genres": ["Animation", "Adventure", "Fantasy"], "overview": "In Italy in the 1930s, sky pirates in biplanes terrorize wealthy cruise ships as they sail the Adriatic Sea. The only pilot brave enough to stop the scourge is the mysterious Porco Rosso, a former World War I flying\u2026", "poster": "assets/movie-porco-rosso-1992-poster.jpg", "backdrop": "assets/movie-porco-rosso-1992-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:23:22.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 11621, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 96, "rtCriticsLabel": "Fresh", "rtAudience": 87, "rtAudienceLabel": "Upright", "imdb": 7.7, "imdbVotes": 119396, "tmdb": 7.789, "tmdbVotes": 3879}}, {"id": "movie-princess-mononoke-1997", "title": "Princess Mononoke", "year": 1997, "type": "movie", "runtimeSeconds": 8003, "seasonCount": null, "communityRating": 8.321, "criticRating": 93, "genres": ["Adventure", "Fantasy", "Animation"], "overview": "Ashitaka, a prince of the disappearing Emishi people, is cursed by a demonized boar god and must journey to the west to find a cure. Along the way, he encounters San, a young human woman fighting to protect the\u2026", "poster": "assets/movie-princess-mononoke-1997-poster.jpg", "backdrop": "assets/movie-princess-mononoke-1997-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:22:28.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 128, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 94, "rtCriticsLabel": "Certified Fresh", "rtAudience": 99, "rtAudienceLabel": "Upright", "imdb": 8.3, "imdbVotes": 493735, "tmdb": 8.321, "tmdbVotes": 9438}}, {"id": "movie-prisoners-2013", "title": "Prisoners", "year": 2013, "type": "movie", "runtimeSeconds": 9192, "seasonCount": null, "communityRating": 8.106, "criticRating": 81, "genres": ["Drama", "Thriller", "Crime"], "overview": "After his six-year-old daughter is abducted, a desperate father takes justice into his own hands when he loses faith in the detective leading the investigation, setting both men on a collision course as the search\u2026", "poster": "assets/movie-prisoners-2013-poster.jpg", "backdrop": "assets/movie-prisoners-2013-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:27:33.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 146233, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 82, "rtCriticsLabel": "Certified Fresh", "rtAudience": 87, "rtAudienceLabel": "Upright", "imdb": 8.2, "imdbVotes": 963062, "tmdb": 8.105, "tmdbVotes": 13722}}, {"id": "movie-racing-stripes-2005", "title": "Racing Stripes", "year": 2005, "type": "movie", "runtimeSeconds": 6117, "seasonCount": null, "communityRating": 5.945, "criticRating": 35, "genres": ["Comedy", "Family"], "overview": "Shattered illusions are hard to repair -- especially for a good-hearted zebra named Stripes who's spent his life on a Kentucky farm amidst the sorely mistaken notion that he's a debonair thoroughbred. Once he faces\u2026", "poster": "assets/movie-racing-stripes-2005-poster.jpg", "backdrop": "assets/movie-racing-stripes-2005-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:26:02.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 6439, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 35, "rtCriticsLabel": "Rotten", "rtAudience": 42, "rtAudienceLabel": "Spilled", "imdb": 5.3, "imdbVotes": 19569, "tmdb": 5.962, "tmdbVotes": 705}}, {"id": "movie-requiem-for-a-dream-2000", "title": "Requiem for a Dream", "year": 2000, "type": "movie", "runtimeSeconds": 6086, "seasonCount": null, "communityRating": 8.005, "criticRating": 80, "genres": ["Crime", "Drama"], "overview": "The drug-induced utopias of four Coney Island residents are shattered when their addictions run deep.", "poster": "assets/movie-requiem-for-a-dream-2000-poster.jpg", "backdrop": "assets/movie-requiem-for-a-dream-2000-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:24:15.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 641, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 81, "rtCriticsLabel": "Certified Fresh", "rtAudience": 93, "rtAudienceLabel": "Upright", "imdb": 8.3, "imdbVotes": 989090, "tmdb": 8, "tmdbVotes": 11454}}, {"id": "movie-rogue-one-a-star-wars-story-2016", "title": "Rogue One: A Star Wars Story", "year": 2016, "type": "movie", "runtimeSeconds": 8038, "seasonCount": null, "communityRating": 7.51, "criticRating": 84, "genres": ["Action", "Adventure", "Science Fiction"], "overview": "A rogue band of resistance fighters unite for a mission to steal the Death Star plans and bring a new hope to the galaxy.", "poster": "assets/movie-rogue-one-a-star-wars-story-2016-poster.jpg", "backdrop": "assets/movie-rogue-one-a-star-wars-story-2016-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:28:00.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 330459, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 84, "rtCriticsLabel": "Certified Fresh", "rtAudience": 87, "rtAudienceLabel": "Upright", "imdb": 7.8, "imdbVotes": 768365, "tmdb": 7.512, "tmdbVotes": 16937}}, {"id": "movie-secondhand-lions-2003", "title": "Secondhand Lions", "year": 2003, "type": "movie", "runtimeSeconds": 6547, "seasonCount": null, "communityRating": 7.237, "criticRating": 60, "genres": ["Family", "Comedy", "Drama"], "overview": "The comedic adventures of an introverted boy left on the doorstep of a pair of reluctant, eccentric great-uncles, whose exotic remembrances stir the boy's spirit and re-ignite the men's lives.", "poster": "assets/movie-secondhand-lions-2003-poster.jpg", "backdrop": "assets/movie-secondhand-lions-2003-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-12T07:16:13.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 13156, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 59, "rtCriticsLabel": "Rotten", "rtAudience": 84, "rtAudienceLabel": "Upright", "imdb": 7.5, "imdbVotes": 66911, "tmdb": 7.242, "tmdbVotes": 872}}, {"id": "movie-the-secret-life-of-pets-2-2019", "title": "The Secret Life of Pets 2", "year": 2019, "type": "movie", "runtimeSeconds": 5164, "seasonCount": null, "communityRating": 6.95, "criticRating": 60, "genres": ["Animation", "Comedy", "Family"], "overview": "Max the terrier must cope with some major life changes when his owner gets married and has a baby. When the family takes a trip to the countryside, nervous Max has numerous run-ins with canine-intolerant cows,\u2026", "poster": "assets/movie-the-secret-life-of-pets-2-2019-poster.jpg", "backdrop": "assets/movie-the-secret-life-of-pets-2-2019-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-05T07:00:53.0000000Z", "lastPlayedAt": "2026-09-17T18:07:00.7024231Z", "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 412117, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 60, "rtCriticsLabel": "Fresh", "rtAudience": 90, "rtAudienceLabel": "Upright", "imdb": 6.4, "imdbVotes": 80464, "tmdb": 6.948, "tmdbVotes": 3450}}, {"id": "movie-self-reliance-2024", "title": "Self Reliance", "year": 2024, "type": "movie", "runtimeSeconds": 5461, "seasonCount": null, "communityRating": 5.888, "criticRating": 73, "genres": ["Comedy", "Thriller"], "overview": "When a man is offered a million dollars to play a game in which hunters try to kill him, he thinks he has found the perfect loophole: they can only attack when he\u2019s alone. His only problem is that none of his friends\u2026", "poster": "assets/movie-self-reliance-2024-poster.jpg", "backdrop": "assets/movie-self-reliance-2024-backdrop.jpg", "played": false, "playCount": 1, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:31:00.0000000Z", "lastPlayedAt": "2026-10-02T19:59:16.9286868Z", "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 1072876, "artwork": {"posterKind": "center_crop", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 73, "rtCriticsLabel": "Certified Fresh", "rtAudience": 56, "rtAudienceLabel": "Spilled", "imdb": 6, "imdbVotes": 23771, "tmdb": 5.866, "tmdbVotes": 346}}, {"id": "movie-serpico-1973", "title": "Serpico", "year": 1973, "type": "movie", "runtimeSeconds": 7805, "seasonCount": null, "communityRating": 7.5, "criticRating": 93, "genres": ["Crime", "Drama", "History"], "overview": "New York cop Frank Serpico blows the whistle on the rampant corruption in the force only to have his comrades turn against him.", "poster": "assets/movie-serpico-1973-poster.jpg", "backdrop": "assets/movie-serpico-1973-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-10T21:45:02.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 9040, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 93, "rtCriticsLabel": "Certified Fresh", "rtAudience": 88, "rtAudienceLabel": "Upright", "imdb": 7.7, "imdbVotes": 149750, "tmdb": 7.525, "tmdbVotes": 2323}}, {"id": "movie-shaft-2000", "title": "Shaft", "year": 2000, "type": "movie", "runtimeSeconds": 5960, "seasonCount": null, "communityRating": 6.026, "criticRating": 67, "genres": ["Action", "Adventure", "Crime"], "overview": "New York police detective John Shaft arrests Walter Wade Jr. for a racially motivated slaying. But the only eyewitness disappears, and Wade jumps bail for Switzerland. Two years later Wade returns to face trial,\u2026", "poster": "assets/movie-shaft-2000-poster.jpg", "backdrop": "assets/movie-shaft-2000-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-10T21:30:40.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 479, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 68, "rtCriticsLabel": "Fresh", "rtAudience": 40, "rtAudienceLabel": "Spilled", "imdb": 6, "imdbVotes": 86257, "tmdb": 6.024, "tmdbVotes": 1531}}, {"id": "movie-a-silent-voice-the-movie-2016", "title": "A Silent Voice: The Movie", "year": 2016, "type": "movie", "runtimeSeconds": 7804, "seasonCount": null, "communityRating": 8.398, "criticRating": null, "genres": ["Animation", "Drama", "Romance"], "overview": "Shouya Ishida starts bullying the new girl in class, Shouko Nishimiya, because she is deaf. But as the teasing continues, the rest of the class starts to turn on Shouya for his lack of compassion. When they leave\u2026", "poster": "assets/movie-a-silent-voice-the-movie-2016-poster.jpg", "backdrop": "assets/movie-a-silent-voice-the-movie-2016-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T17:39:46.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 378064, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 95, "rtCriticsLabel": "Fresh", "rtAudience": 94, "rtAudienceLabel": "Upright", "imdb": 8.2, "imdbVotes": 151926, "tmdb": 8.396, "tmdbVotes": 4764}}, {"id": "movie-sinbad-legend-of-the-seven-seas-2003", "title": "Sinbad: Legend of the Seven Seas", "year": 2003, "type": "movie", "runtimeSeconds": 5143, "seasonCount": null, "communityRating": 7.067, "criticRating": 44, "genres": ["Action", "Adventure", "Animation"], "overview": "The sailor of legend is framed by the goddess Eris for the theft of the Book of Peace, and must travel to her realm at the end of the world to retrieve it and save the life of his childhood friend Prince Proteus.", "poster": "assets/movie-sinbad-legend-of-the-seven-seas-2003-poster.jpg", "backdrop": "assets/movie-sinbad-legend-of-the-seven-seas-2003-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:26:25.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 14411, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 46, "rtCriticsLabel": "Rotten", "rtAudience": 57, "rtAudienceLabel": "Spilled", "imdb": 6.8, "imdbVotes": 65298, "tmdb": 7.071, "tmdbVotes": 2323}}, {"id": "movie-sleeping-with-other-people-2015", "title": "Sleeping with Other People", "year": 2015, "type": "movie", "runtimeSeconds": 6076, "seasonCount": null, "communityRating": 6.274, "criticRating": 64, "genres": ["Comedy", "Romance"], "overview": "Can two serial cheaters get a second chance at love? After a one-night stand in college, New Yorkers Lainey and Jake meet by chance twelve years later and discover they each have the same problem: because of their\u2026", "poster": "assets/movie-sleeping-with-other-people-2015-poster.jpg", "backdrop": "assets/movie-sleeping-with-other-people-2015-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:27:42.0000000Z", "lastPlayedAt": "2026-07-17T17:50:44.0000000Z", "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 288036, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 64, "rtCriticsLabel": "Fresh", "rtAudience": 56, "rtAudienceLabel": "Spilled", "imdb": 6.5, "imdbVotes": 52275, "tmdb": 6.275, "tmdbVotes": 1020}}, {"id": "movie-snowpiercer-2013", "title": "Snowpiercer", "year": 2013, "type": "movie", "runtimeSeconds": 7573, "seasonCount": null, "communityRating": 6.909, "criticRating": 94, "genres": ["Action", "Science Fiction", "Drama"], "overview": "In a future where a failed global-warming experiment kills off most life on the planet, a class system evolves aboard the Snowpiercer; a train that travels around the globe via a perpetual-motion engine.", "poster": "assets/movie-snowpiercer-2013-poster.jpg", "backdrop": "assets/movie-snowpiercer-2013-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:27:07.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 110415, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 94, "rtCriticsLabel": "Certified Fresh", "rtAudience": 72, "rtAudienceLabel": "Upright", "imdb": 7.1, "imdbVotes": 426976, "tmdb": 6.9, "tmdbVotes": 10807}}, {"id": "movie-spider-man-brand-new-day-2026", "title": "Spider-Man: Brand New Day", "year": 2026, "type": "movie", "runtimeSeconds": 8701, "seasonCount": null, "communityRating": 8.374, "criticRating": 90, "genres": ["Science Fiction", "Action", "Adventure"], "overview": "Fighting crime full-time as Spider-Man in a world that doesn't remember him\u2014and the pressure of seeing his old friends move on without him\u2014sparks a change in Peter Parker he may not have the power to control. But\u2026", "poster": "assets/movie-spider-man-brand-new-day-2026-poster.jpg", "backdrop": "assets/movie-spider-man-brand-new-day-2026-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-10T14:14:27.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 969681, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 90, "rtCriticsLabel": "Certified Fresh", "rtAudience": 97, "rtAudienceLabel": "Upright", "imdb": 7.9, "imdbVotes": 366886, "tmdb": 8.5, "tmdbVotes": 6537}}, {"id": "movie-spider-man-far-from-home-2019", "title": "Spider-Man: Far From Home", "year": 2019, "type": "movie", "runtimeSeconds": 7762, "seasonCount": null, "communityRating": 7.389, "criticRating": 91, "genres": ["Action", "Adventure", "Science Fiction"], "overview": "Peter Parker and his friends go on a summer trip to Europe. However, they will hardly be able to rest - Peter will have to agree to help Nick Fury uncover the mystery of creatures that cause natural disasters and\u2026", "poster": "assets/movie-spider-man-far-from-home-2019-poster.jpg", "backdrop": "assets/movie-spider-man-far-from-home-2019-backdrop.jpg", "played": true, "playCount": 1, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-10T14:25:47.0000000Z", "lastPlayedAt": "2026-10-10T17:50:35.6193119Z", "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 429617, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 91, "rtCriticsLabel": "Certified Fresh", "rtAudience": 95, "rtAudienceLabel": "Upright", "imdb": 7.3, "imdbVotes": 682887, "tmdb": 7.387, "tmdbVotes": 17847}}, {"id": "movie-spider-man-homecoming-2017", "title": "Spider-Man: Homecoming", "year": 2017, "type": "movie", "runtimeSeconds": 8008, "seasonCount": null, "communityRating": 7.333, "criticRating": 92, "genres": ["Action", "Adventure", "Science Fiction"], "overview": "Following the events of Captain America: Civil War, Peter Parker, with the help of his mentor Tony Stark, tries to balance his life as an ordinary high school student in Queens, New York City, with fighting crime as\u2026", "poster": "assets/movie-spider-man-homecoming-2017-poster.jpg", "backdrop": "assets/movie-spider-man-homecoming-2017-backdrop.jpg", "played": true, "playCount": 1, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-10T14:33:13.0000000Z", "lastPlayedAt": "2026-10-10T20:31:23.4444213Z", "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 315635, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 92, "rtCriticsLabel": "Certified Fresh", "rtAudience": 87, "rtAudienceLabel": "Upright", "imdb": 7.4, "imdbVotes": 840974, "tmdb": 7.332, "tmdbVotes": 24183}}, {"id": "movie-spider-man-no-way-home-2021", "title": "Spider-Man: No Way Home", "year": 2021, "type": "movie", "runtimeSeconds": 8890, "seasonCount": null, "communityRating": 7.947, "criticRating": 93, "genres": ["Action", "Adventure", "Science Fiction"], "overview": "Peter Parker is unmasked and no longer able to separate his normal life from the high-stakes of being a super-hero. When he asks for help from Doctor Strange the stakes become even more dangerous, forcing him to\u2026", "poster": "assets/movie-spider-man-no-way-home-2021-poster.jpg", "backdrop": "assets/movie-spider-man-no-way-home-2021-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-10T14:21:05.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 634649, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 93, "rtCriticsLabel": "Certified Fresh", "rtAudience": 97, "rtAudienceLabel": "Upright", "imdb": 8.1, "imdbVotes": 1082660, "tmdb": 7.947, "tmdbVotes": 23505}}, {"id": "movie-spirited-away-2001", "title": "Spirited Away", "year": 2001, "type": "movie", "runtimeSeconds": 7472, "seasonCount": null, "communityRating": 8.535, "criticRating": 96, "genres": ["Animation", "Family", "Fantasy"], "overview": "A young girl, Chihiro, becomes trapped in a strange new world of spirits. When her parents undergo a mysterious transformation, she must call upon the courage she never knew she had to free her family.", "poster": "assets/movie-spirited-away-2001-poster.jpg", "backdrop": "assets/movie-spirited-away-2001-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:22:42.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 129, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 96, "rtCriticsLabel": "Certified Fresh", "rtAudience": 99, "rtAudienceLabel": "Upright", "imdb": 8.6, "imdbVotes": 987658, "tmdb": 8.536, "tmdbVotes": 19176}}, {"id": "movie-the-substance-2024", "title": "The Substance", "year": 2024, "type": "movie", "runtimeSeconds": 8531, "seasonCount": null, "communityRating": 7.135, "criticRating": 89, "genres": ["Horror", "Science Fiction"], "overview": "A fading celebrity decides to use a black market drug, a cell-replicating substance that temporarily creates a younger, better version of herself.", "poster": "assets/movie-the-substance-2024-poster.jpg", "backdrop": "assets/movie-the-substance-2024-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:30:22.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 933260, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 89, "rtCriticsLabel": "Certified Fresh", "rtAudience": 76, "rtAudienceLabel": "Upright", "imdb": 7.2, "imdbVotes": 466542, "tmdb": 7.13, "tmdbVotes": 6746}}, {"id": "movie-the-tale-of-the-princess-kaguya-2013", "title": "The Tale of The Princess Kaguya", "year": 2013, "type": "movie", "runtimeSeconds": 8218, "seasonCount": null, "communityRating": 8.1, "criticRating": 100, "genres": ["Animation", "Drama", "Fantasy"], "overview": "Found inside a shining stalk of bamboo by an old bamboo cutter and his wife, a tiny girl grows rapidly into an exquisite young lady. The mysterious young princess enthrals all who encounter her. But, ultimately, she\u2026", "poster": "assets/movie-the-tale-of-the-princess-kaguya-2013-poster.jpg", "backdrop": "assets/movie-the-tale-of-the-princess-kaguya-2013-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-07T13:40:15.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 149871, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Certified Fresh", "rtAudience": 90, "rtAudienceLabel": "Upright", "imdb": 8, "imdbVotes": 63574, "tmdb": 8.083, "tmdbVotes": 2079}}, {"id": "movie-taxi-driver-1976", "title": "Taxi Driver", "year": 1976, "type": "movie", "runtimeSeconds": 6831, "seasonCount": null, "communityRating": 8.121, "criticRating": 89, "genres": ["Crime", "Drama"], "overview": "Suffering from insomnia, disturbed loner Travis Bickle takes a job as a New York City cabbie, haunting the streets nightly, growing increasingly detached from reality as he dreams of cleaning up the filthy city.", "poster": "assets/movie-taxi-driver-1976-poster.jpg", "backdrop": "assets/movie-taxi-driver-1976-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:23:04.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 103, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 89, "rtCriticsLabel": "Certified Fresh", "rtAudience": 93, "rtAudienceLabel": "Upright", "imdb": 8.2, "imdbVotes": 1046700, "tmdb": 8.116, "tmdbVotes": 13973}}, {"id": "movie-triangle-of-sadness-2022", "title": "Triangle of Sadness", "year": 2022, "type": "movie", "runtimeSeconds": 8833, "seasonCount": null, "communityRating": 7.005, "criticRating": 71, "genres": ["Comedy", "Drama"], "overview": "A celebrity model couple are invited on a luxury cruise for the uber-rich, helmed by an unhinged, alcoholic captain. What first appears Instagrammable ends catastrophically, leaving the survivors stranded on a desert\u2026", "poster": "assets/movie-triangle-of-sadness-2022-poster.jpg", "backdrop": "assets/movie-triangle-of-sadness-2022-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:29:00.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 497828, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 72, "rtCriticsLabel": "Fresh", "rtAudience": 80, "rtAudienceLabel": "Upright", "imdb": 7.2, "imdbVotes": 221069, "tmdb": 7, "tmdbVotes": 3104}}, {"id": "movie-tsotsi-2005", "title": "Tsotsi", "year": 2005, "type": "movie", "runtimeSeconds": 5663, "seasonCount": null, "communityRating": 6.937, "criticRating": 82, "genres": ["Crime", "Drama"], "overview": "A young South African boy from the Johannesburg ghetto named Tsotsi, meaning Gangster, leaves home as a child to get away from his helpless parents. Now a teenage thug, Tsotsi finds a baby in the back seat of a car\u2026", "poster": "assets/movie-tsotsi-2005-poster.jpg", "backdrop": "assets/movie-tsotsi-2005-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:24:58.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 868, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 82, "rtCriticsLabel": "Certified Fresh", "rtAudience": 86, "rtAudienceLabel": "Upright", "imdb": 7.2, "imdbVotes": 32526, "tmdb": 6.941, "tmdbVotes": 372}}, {"id": "movie-unknown-number-the-high-school-catfish-2025", "title": "Unknown Number: The High School Catfish", "year": 2025, "type": "movie", "runtimeSeconds": 5691, "seasonCount": null, "communityRating": 6.746, "criticRating": 85, "genres": ["Documentary"], "overview": "Vulgar, taunting texts blow up the phones of a teen and her boyfriend. Who's sending them \u2014 and why? This twisty documentary reveals the shocking answer.", "poster": "assets/movie-unknown-number-the-high-school-catfish-2025-poster.jpg", "backdrop": "assets/movie-unknown-number-the-high-school-catfish-2025-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:32:10.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 1517772, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 85, "rtCriticsLabel": "Fresh", "rtAudience": 69, "rtAudienceLabel": "Upright", "imdb": 6.7, "imdbVotes": 23039, "tmdb": 6.737, "tmdbVotes": 257}}, {"id": "movie-the-uprising-2026", "title": "The Uprising", "year": 2026, "type": "movie", "runtimeSeconds": 7684, "seasonCount": null, "communityRating": 7.846, "criticRating": 55, "genres": ["Action", "Drama", "History"], "overview": "As war and plague devastate 14th-century England, a humble peasant ignites a rebellion, uniting an army of commoners to defy the King\u2019s might in a desperate fight for justice and survival.", "poster": "assets/movie-the-uprising-2026-poster.jpg", "backdrop": "assets/movie-the-uprising-2026-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-11-02T16:37:03.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 977942, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 57, "rtCriticsLabel": "Rotten", "rtAudience": 65, "rtAudienceLabel": "Upright", "imdb": 6.2, "imdbVotes": 6622, "tmdb": 7.8, "tmdbVotes": 404}}, {"id": "movie-vice-2018", "title": "Vice", "year": 2018, "type": "movie", "runtimeSeconds": 7948, "seasonCount": null, "communityRating": 7.013, "criticRating": 64, "genres": ["Drama", "Comedy", "History"], "overview": "George W. Bush picks Dick Cheney, the CEO of Halliburton Co., to be his Republican running mate in the 2000 presidential election. No stranger to politics, Cheney's impressive r\u00e9sum\u00e9 includes stints as White House\u2026", "poster": "assets/movie-vice-2018-poster.jpg", "backdrop": "assets/movie-vice-2018-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:28:30.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 429197, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 64, "rtCriticsLabel": "Fresh", "rtAudience": 61, "rtAudienceLabel": "Upright", "imdb": 7.2, "imdbVotes": 177299, "tmdb": 7.014, "tmdbVotes": 3723}}, {"id": "movie-warriors-of-the-wind-1984", "title": "Warriors of the Wind", "year": 1984, "type": "movie", "runtimeSeconds": 7022, "seasonCount": null, "communityRating": 7.941, "criticRating": 87, "genres": ["Adventure", "Animation", "Fantasy"], "overview": "After a global war, the seaside kingdom known as the Valley of the Wind remains one of the last strongholds on Earth untouched by a poisonous jungle and the powerful insects that guard it. Led by the courageous\u2026", "poster": "assets/movie-warriors-of-the-wind-1984-poster.jpg", "backdrop": "assets/movie-warriors-of-the-wind-1984-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:22:20.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 81, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 87, "rtCriticsLabel": "Fresh", "rtAudience": 91, "rtAudienceLabel": "Upright", "imdb": 8, "imdbVotes": 200154, "tmdb": 7.94, "tmdbVotes": 4260}}, {"id": "movie-we-bury-the-dead-2026", "title": "We Bury the Dead", "year": 2026, "type": "movie", "runtimeSeconds": 5693, "seasonCount": null, "communityRating": 6.153, "criticRating": 87, "genres": ["Horror", "Thriller"], "overview": "After a catastrophic military disaster reanimates the dead, Ava searches for her missing husband amidst an increasingly hostile world.", "poster": "assets/movie-we-bury-the-dead-2026-poster.jpg", "backdrop": "assets/movie-we-bury-the-dead-2026-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-08-26T05:36:00.4272328Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 1198984, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 87, "rtCriticsLabel": "Certified Fresh", "rtAudience": 45, "rtAudienceLabel": "Spilled", "imdb": 5.6, "imdbVotes": 20693, "tmdb": 6.137, "tmdbVotes": 433}}, {"id": "movie-white-hot-the-rise-fall-of-abercrombie-fitch-2022", "title": "White Hot: The Rise & Fall of Abercrombie & Fitch", "year": 2022, "type": "movie", "runtimeSeconds": 5187, "seasonCount": null, "communityRating": 5.663, "criticRating": 66, "genres": ["Documentary"], "overview": "All the cool kids were wearing it. This documentary explores A&F's pop culture reign in the late '90s and early 2000s and how it thrived on exclusion.", "poster": "assets/movie-white-hot-the-rise-fall-of-abercrombie-fitch-2022-poster.jpg", "backdrop": "assets/movie-white-hot-the-rise-fall-of-abercrombie-fitch-2022-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:30:34.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 953371, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 66, "rtCriticsLabel": "Fresh", "rtAudience": 29, "rtAudienceLabel": "Spilled", "imdb": 5.8, "imdbVotes": 5655, "tmdb": 5.7, "tmdbVotes": 102}}, {"id": "movie-the-wild-robot-2024", "title": "The Wild Robot", "year": 2024, "type": "movie", "runtimeSeconds": 6101, "seasonCount": null, "communityRating": 8.308, "criticRating": 97, "genres": ["Family", "Animation", "Science Fiction"], "overview": "After a shipwreck, an intelligent robot called Roz is stranded on an uninhabited island. To survive the harsh environment, Roz bonds with the island's animals and cares for an orphaned baby goose.", "poster": "assets/movie-the-wild-robot-2024-poster.jpg", "backdrop": "assets/movie-the-wild-robot-2024-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:31:49.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 1184918, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 97, "rtCriticsLabel": "Certified Fresh", "rtAudience": 98, "rtAudienceLabel": "Upright", "imdb": 8.1, "imdbVotes": 241134, "tmdb": 8.309, "tmdbVotes": 6819}}, {"id": "movie-the-wind-rises-2013", "title": "The Wind Rises", "year": 2013, "type": "movie", "runtimeSeconds": 8031, "seasonCount": null, "communityRating": 7.784, "criticRating": 88, "genres": ["Animation", "Drama", "History"], "overview": "A lifelong love of flight inspires Japanese aviation engineer Jiro Horikoshi, whose storied career includes the creation of the A-6M World War II fighter plane.", "poster": "assets/movie-the-wind-rises-2013-poster.jpg", "backdrop": "assets/movie-the-wind-rises-2013-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T10:24:38.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 149870, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 89, "rtCriticsLabel": "Certified Fresh", "rtAudience": 85, "rtAudienceLabel": "Upright", "imdb": 7.8, "imdbVotes": 115756, "tmdb": 7.783, "tmdbVotes": 3536}}, {"id": "movie-the-witcher-nightmare-of-the-wolf-2021", "title": "The Witcher: Nightmare of the Wolf", "year": 2021, "type": "movie", "runtimeSeconds": 5015, "seasonCount": null, "communityRating": 7.422, "criticRating": 100, "genres": ["Animation", "Action", "Fantasy"], "overview": "Escaping from poverty to become a witcher, Vesemir slays monsters for coin and glory, but when a new menace rises, he must face the demons of his past.", "poster": "assets/movie-the-witcher-nightmare-of-the-wolf-2021-poster.jpg", "backdrop": "assets/movie-the-witcher-nightmare-of-the-wolf-2021-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-26T04:42:03.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 666243, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": 83, "rtAudienceLabel": "Upright", "imdb": 7.2, "imdbVotes": 55759, "tmdb": 7.407, "tmdbVotes": 1159}}, {"id": "movie-the-witcher-sirens-of-the-deep-2025", "title": "The Witcher: Sirens of the Deep", "year": 2025, "type": "movie", "runtimeSeconds": 5517, "seasonCount": null, "communityRating": 6.8, "criticRating": 60, "genres": ["Animation", "Fantasy", "Action"], "overview": "When human sailors are attacked by mysterious creatures of the deep, only one person can stop the war between land and sea: the Witcher, Geralt of Rivia.", "poster": "assets/movie-the-witcher-sirens-of-the-deep-2025-poster.jpg", "backdrop": "assets/movie-the-witcher-sirens-of-the-deep-2025-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-26T05:03:26.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 1203329, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 60, "rtCriticsLabel": "Fresh", "rtAudience": 37, "rtAudienceLabel": "Spilled", "imdb": 6.1, "imdbVotes": 11799, "tmdb": 6.741, "tmdbVotes": 303}}], "shows": [{"id": "tv-adults-2025", "title": "Adults", "year": 2025, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 6.495, "criticRating": null, "genres": ["Comedy"], "overview": "A group of twenty-somethings in New York trying to be good people, despite being neither \"good\" nor \"people\" yet.", "poster": "assets/tv-adults-2025-poster.jpg", "backdrop": "assets/tv-adults-2025-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-23T21:01:41.1814765Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 260458, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 88, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.5, "tmdbVotes": 102}}, {"id": "tv-american-crime-story-2016", "title": "American Crime Story", "year": 2016, "type": "tv", "runtimeSeconds": null, "seasonCount": 3, "communityRating": 7.573, "criticRating": null, "genres": ["Crime", "Drama"], "overview": "An anthology series centered around some of history's most famous criminal investigations.", "poster": "assets/tv-american-crime-story-2016-poster.jpg", "backdrop": "assets/tv-american-crime-story-2016-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0490488Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 64513, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 84, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.585, "tmdbVotes": 1094}}, {"id": "tv-american-primeval-2025", "title": "American Primeval", "year": 2025, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.691, "criticRating": null, "genres": ["Western", "Drama", "Action & Adventure"], "overview": "A mother and son fleeing from their past form a found family while confronting a harsh landscape of freedom and cruelty in the American West.", "poster": "assets/tv-american-primeval-2025-poster.jpg", "backdrop": "assets/tv-american-primeval-2025-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0573221Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 215866, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 71, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.741, "tmdbVotes": 538}}, {"id": "tv-arrested-development-2003", "title": "Arrested Development", "year": 2003, "type": "tv", "runtimeSeconds": null, "seasonCount": 5, "communityRating": 7.925, "criticRating": null, "genres": ["Comedy"], "overview": "The story of a wealthy family that lost everything, and the one son who had no choice but to keep them all together.", "poster": "assets/tv-arrested-development-2003-poster.jpg", "backdrop": "assets/tv-arrested-development-2003-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0513048Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 4589, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 75, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.906, "tmdbVotes": 1793}}, {"id": "tv-avatar-the-last-airbender-2005", "title": "Avatar: The Last Airbender", "year": 2005, "type": "tv", "runtimeSeconds": 1440, "seasonCount": 3, "communityRating": 8.78, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "In a war-torn world of elemental magic, a young boy reawakens to undertake a dangerous mystic quest to fulfill his destiny as the Avatar, and bring peace to the world.", "poster": "assets/tv-avatar-the-last-airbender-2005-poster.jpg", "backdrop": "assets/tv-avatar-the-last-airbender-2005-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0504536Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 246, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.787, "tmdbVotes": 5215}}, {"id": "tv-b-b-vol-liefde-2021", "title": "B&B Vol Liefde", "year": 2021, "type": "tv", "runtimeSeconds": 3720, "seasonCount": 1, "communityRating": 7.2, "criticRating": null, "genres": ["Reality"], "overview": "B&B Vol Liefde is a heartwarming adventure, full of romance, excitement, and unforgettable moments. Adventurous Dutch B&B owners abroad throw their doors wide open and let their hearts speak, determined to find that\u2026", "poster": "assets/tv-b-b-vol-liefde-2021-poster.jpg", "backdrop": "assets/tv-b-b-vol-liefde-2021-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-31T22:30:11.129657Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 124428, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.2, "tmdbVotes": 10}}, {"id": "tv-the-bear-2022", "title": "The Bear", "year": 2022, "type": "tv", "runtimeSeconds": null, "seasonCount": 5, "communityRating": 8.139, "criticRating": null, "genres": ["Drama", "Comedy"], "overview": "Carmy, a young fine-dining chef, comes home to Chicago to run his family sandwich shop. As he fights to transform the shop and himself, he works alongside a rough-around-the-edges crew that ultimately reveal\u2026", "poster": "assets/tv-the-bear-2022-poster.jpg", "backdrop": "assets/tv-the-bear-2022-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0467371Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 136315, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 93, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.158, "tmdbVotes": 2025}}, {"id": "tv-blue-planet-ii-2017", "title": "Blue Planet II", "year": 2017, "type": "tv", "runtimeSeconds": 3600, "seasonCount": 1, "communityRating": 8.64, "criticRating": null, "genres": ["Documentary", "Family"], "overview": "There is nowhere more powerful and unforgiving yet more beautiful and compelling than the ocean. Join us and explore the greatest yet least known parts of our planet.", "poster": "assets/tv-blue-planet-ii-2017-poster.jpg", "backdrop": "assets/tv-blue-planet-ii-2017-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0634849Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 74313, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 97, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.6, "tmdbVotes": 380}}, {"id": "tv-breeders-2020", "title": "Breeders", "year": 2020, "type": "tv", "runtimeSeconds": 1500, "seasonCount": 4, "communityRating": 6.8, "criticRating": null, "genres": ["Comedy"], "overview": "Exposing the parental-paradox that it is possible, in the very same moment, to love your child to the horizon of the universe, while being apoplectically angry enough to want to send them there.", "poster": "assets/tv-breeders-2020-poster.jpg", "backdrop": "assets/tv-breeders-2020-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-28T18:54:21.8885435Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 93290, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 92, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.8, "tmdbVotes": 104}}, {"id": "tv-chernobyl-2019", "title": "Chernobyl", "year": 2019, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 8.718, "criticRating": null, "genres": ["Drama"], "overview": "The true story of one of the worst man-made catastrophes in history: the catastrophic nuclear accident at Chernobyl. A tale of the brave men and women who sacrificed to save Europe from unimaginable disaster.", "poster": "assets/tv-chernobyl-2019-poster.jpg", "backdrop": "assets/tv-chernobyl-2019-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0469903Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 87108, "artwork": {"posterKind": "poster", "backdropKind": "center_crop"}, "ratings": {"rtCritics": 95, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.731, "tmdbVotes": 8496}}, {"id": "tv-community-2009", "title": "Community", "year": 2009, "type": "tv", "runtimeSeconds": null, "seasonCount": 6, "communityRating": 7.997, "criticRating": null, "genres": ["Comedy"], "overview": "Follow the lives of a group of students at what is possibly the world\u2019s worst community college in the fictional locale of Greendale, Colorado.", "poster": "assets/tv-community-2009-poster.jpg", "backdrop": "assets/tv-community-2009-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0531416Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 18347, "artwork": {"posterKind": "center_crop", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 88, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.994, "tmdbVotes": 2226}}, {"id": "tv-dead-end-job-2026", "title": "Dead-End Job", "year": 2026, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.7, "criticRating": null, "genres": ["Mystery"], "overview": "Drowning in debt, a young man takes lucrative part-time jobs from a mysterious agency \u2014 only to find his hustle for more money turning nightmarish.", "poster": "assets/tv-dead-end-job-2026-poster.jpg", "backdrop": "assets/tv-dead-end-job-2026-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-11-04T18:58:01.8352857Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 289517, "artwork": {"posterKind": "center_crop", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.7, "tmdbVotes": 38}}, {"id": "tv-dopesick-2021", "title": "Dopesick", "year": 2021, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 8.015, "criticRating": null, "genres": ["Crime", "Drama"], "overview": "The story of how one company triggered the worst drug epidemic in American history. Look into the epicenter of America's struggle with opioid addiction, from a distressed Virginia mining community, to the hallways of\u2026", "poster": "assets/tv-dopesick-2021-poster.jpg", "backdrop": "assets/tv-dopesick-2021-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0580168Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 110695, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 89, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.035, "tmdbVotes": 565}}, {"id": "tv-dune-prophecy-2024", "title": "Dune: Prophecy", "year": 2024, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.213, "criticRating": null, "genres": ["Sci-Fi & Fantasy", "Drama", "Action & Adventure"], "overview": "Ten thousand years before the ascension of Paul Atreides, sisters Valya and Tula Harkonnen establish the fabled sect and female order that would become known as the Bene Gesserit to control the future of humankind.", "poster": "assets/tv-dune-prophecy-2024-poster.jpg", "backdrop": "assets/tv-dune-prophecy-2024-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-11-04T18:23:01.2908568Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 90228, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 64, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.213, "tmdbVotes": 677}}, {"id": "tv-east-of-eden-2026", "title": "East of Eden", "year": 2026, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.931, "criticRating": null, "genres": ["Drama", "Crime"], "overview": "In the early 1900s, a fiercely independent woman drives a rift between two brothers, igniting a saga that unfolds across two generations.", "poster": "assets/tv-east-of-eden-2026-poster.jpg", "backdrop": "assets/tv-east-of-eden-2026-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-23T18:07:11.3965096Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 258165, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 88, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.982, "tmdbVotes": 139}}, {"id": "tv-fallout-2024", "title": "Fallout", "year": 2024, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 8.124, "criticRating": null, "genres": ["Action & Adventure", "Sci-Fi & Fantasy", "Drama"], "overview": "The story of haves and have-nots in a world in which there's almost nothing left to have. 200 years after the apocalypse, the gentle denizens of luxury fallout shelters are forced to return to the irradiated\u2026", "poster": "assets/tv-fallout-2024-poster.jpg", "backdrop": "assets/tv-fallout-2024-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0669262Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 106379, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 94, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.106, "tmdbVotes": 3233}}, {"id": "tv-fawlty-towers-1975", "title": "Fawlty Towers", "year": 1975, "type": "tv", "runtimeSeconds": 1800, "seasonCount": 2, "communityRating": 8.295, "criticRating": null, "genres": ["Comedy"], "overview": "Owner Basil Fawlty, his wife Sybil, a chambermaid Polly, and Spanish waiter Manuel attempt to run their hotel amidst farcical situations and an array of demanding guests.", "poster": "assets/tv-fawlty-towers-1975-poster.jpg", "backdrop": "assets/tv-fawlty-towers-1975-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-19T23:26:39.7658344Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 2207, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.296, "tmdbVotes": 867}}, {"id": "tv-the-final-problem-2026", "title": "The Final Problem", "year": 2026, "type": "tv", "runtimeSeconds": 3420, "seasonCount": 1, "communityRating": 7.041, "criticRating": null, "genres": ["Crime", "Mystery"], "overview": "In the spring of 1959, a retired actor, who previously played Sherlock Holmes, must investigate a murder at a small hotel on a tiny island near Mallorca.", "poster": "assets/tv-the-final-problem-2026-poster.jpg", "backdrop": "assets/tv-the-final-problem-2026-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-11-04T19:16:12.4822791Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 290720, "artwork": {"posterKind": "center_crop", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.041, "tmdbVotes": 49}}, {"id": "tv-the-four-seasons-2025", "title": "The Four Seasons", "year": 2025, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 6.879, "criticRating": null, "genres": ["Comedy"], "overview": "The decades-long friendship between three married couples is tested when one divorces, complicating their tradition of quarterly weekend getaways.", "poster": "assets/tv-the-four-seasons-2025-poster.jpg", "backdrop": "assets/tv-the-four-seasons-2025-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-28T18:36:42.5326384Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 243316, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 81, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.892, "tmdbVotes": 204}}, {"id": "tv-the-get-down-2016", "title": "The Get Down", "year": 2016, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.3, "criticRating": null, "genres": ["Drama"], "overview": "In 1977 New York City, the talented and soulful youth of the South Bronx chase dreams and breakneck beats to transform music history.", "poster": "assets/tv-the-get-down-2016-poster.jpg", "backdrop": "assets/tv-the-get-down-2016-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0497737Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 65345, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 81, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.3, "tmdbVotes": 196}}, {"id": "tv-how-to-change-your-mind-2022", "title": "How to Change Your Mind", "year": 2022, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.76, "criticRating": null, "genres": ["Documentary", "Mystery"], "overview": "Author Michael Pollan leads the way in this docuseries exploring the history and uses of psychedelics, including LSD, psilocybin, MDMA and mescaline.", "poster": "assets/tv-how-to-change-your-mind-2022-poster.jpg", "backdrop": "assets/tv-how-to-change-your-mind-2022-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0601399Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 204304, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.8, "tmdbVotes": 53}}, {"id": "tv-interrogation-2020", "title": "Interrogation", "year": 2020, "type": "tv", "runtimeSeconds": 2700, "seasonCount": 1, "communityRating": 6.788, "criticRating": null, "genres": ["Drama", "Crime"], "overview": "Based on a true story that spanned more than 30 years in which a young man was charged and convicted of brutally murdering his mother. Each episode is structured around an interrogation taken directly from the real\u2026", "poster": "assets/tv-interrogation-2020-poster.jpg", "backdrop": "assets/tv-interrogation-2020-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-26T05:52:06.1068207Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 96488, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 57, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.9, "tmdbVotes": 54}}, {"id": "tv-it-s-always-sunny-in-philadelphia-2005", "title": "It's Always Sunny in Philadelphia", "year": 2005, "type": "tv", "runtimeSeconds": null, "seasonCount": 18, "communityRating": 8.2, "criticRating": null, "genres": ["Comedy"], "overview": "Four egocentric friends run a neighborhood Irish pub in Philadelphia and try to find their way through the adult world of work and relationships. Unfortunately, their warped views and precarious judgments often lead\u2026", "poster": "assets/tv-it-s-always-sunny-in-philadelphia-2005-poster.jpg", "backdrop": "assets/tv-it-s-always-sunny-in-philadelphia-2005-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0485774Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 2710, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 94, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.253, "tmdbVotes": 1457}}, {"id": "tv-a-knight-of-the-seven-kingdoms-2026", "title": "A Knight of the Seven Kingdoms", "year": 2026, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 8.431, "criticRating": null, "genres": ["Drama", "Sci-Fi & Fantasy", "Action & Adventure"], "overview": "A century before the events of Game of Thrones, two unlikely heroes wandered Westeros: a young, naive but courageous knight, Ser Duncan the Tall, and his diminutive squire, Egg. Set in an age when the Targaryen line\u2026", "poster": "assets/tv-a-knight-of-the-seven-kingdoms-2026-poster.jpg", "backdrop": "assets/tv-a-knight-of-the-seven-kingdoms-2026-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0493344Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 224372, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 94, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.4, "tmdbVotes": 1266}}, {"id": "tv-landman-2024", "title": "Landman", "year": 2024, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 8.194, "criticRating": null, "genres": ["Drama"], "overview": "Set in the proverbial boomtowns of West-Texas and a modern-day tale of fortune-seeking in the world of oil rigs, the series is an upstairs/downstairs story of roughnecks and wildcat billionaires that are fueling a\u2026", "poster": "assets/tv-landman-2024-poster.jpg", "backdrop": "assets/tv-landman-2024-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-22T21:38:18.0973875Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 157741, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 80, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.209, "tmdbVotes": 668}}, {"id": "tv-the-last-of-us-2023", "title": "The Last of Us", "year": 2023, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 8.419, "criticRating": null, "genres": ["Drama"], "overview": "Twenty years after modern civilization has been destroyed, Joel, a hardened survivor, is hired to smuggle Ellie, a 14-year-old girl, out of an oppressive quarantine zone. What starts as a small job soon becomes a\u2026", "poster": "assets/tv-the-last-of-us-2023-poster.jpg", "backdrop": "assets/tv-the-last-of-us-2023-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0640955Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 100088, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 94, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.4, "tmdbVotes": 7485}}, {"id": "tv-last-samurai-standing-2025", "title": "Last Samurai Standing", "year": 2025, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.805, "criticRating": null, "genres": ["Action & Adventure", "Drama"], "overview": "In the early Meiji era, Shujiro, once known as an undefeated samurai, decides to participate in a deadly survival game to save his family and villagers.", "poster": "assets/tv-last-samurai-standing-2025-poster.jpg", "backdrop": "assets/tv-last-samurai-standing-2025-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0622526Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 252193, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.812, "tmdbVotes": 271}}, {"id": "tv-lord-of-the-flies-2026", "title": "Lord of the Flies", "year": 2026, "type": "tv", "runtimeSeconds": 3480, "seasonCount": 1, "communityRating": 7.571, "criticRating": null, "genres": ["Drama", "Action & Adventure"], "overview": "After a plane crash, a group of schoolboys find themselves stranded on a tropical island without adults. Ralph is elected leader and, with the help of the intelligent Piggy, strives to maintain order and\u2026", "poster": "assets/tv-lord-of-the-flies-2026-poster.jpg", "backdrop": "assets/tv-lord-of-the-flies-2026-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0645648Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 270572, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 91, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.58, "tmdbVotes": 138}}, {"id": "tv-the-lord-of-the-rings-the-rings-of-power-2022", "title": "The Lord of the Rings: The Rings of Power", "year": 2022, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 7.233, "criticRating": null, "genres": ["Action & Adventure", "Sci-Fi & Fantasy", "Drama"], "overview": "Beginning in a time of relative peace, we follow an ensemble cast of characters as they confront the re-emergence of evil to Middle-earth. From the darkest depths of the Misty Mountains, to the majestic forests of\u2026", "poster": "assets/tv-the-lord-of-the-rings-the-rings-of-power-2022-poster.jpg", "backdrop": "assets/tv-the-lord-of-the-rings-the-rings-of-power-2022-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0618904Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 84773, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 84, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.211, "tmdbVotes": 4003}}, {"id": "tv-love-death-robots-2019", "title": "Love, Death & Robots", "year": 2019, "type": "tv", "runtimeSeconds": null, "seasonCount": 4, "communityRating": 8.21, "criticRating": null, "genres": ["Animation", "Sci-Fi & Fantasy"], "overview": "Terrifying creatures, wicked surprises and dark comedy converge in this NSFW anthology of animated stories presented by Tim Miller and David Fincher.", "poster": "assets/tv-love-death-robots-2019-poster.jpg", "backdrop": "assets/tv-love-death-robots-2019-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0460964Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 86831, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 89, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.203, "tmdbVotes": 4238}}, {"id": "tv-maniac-2018", "title": "Maniac", "year": 2018, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.338, "criticRating": null, "genres": ["Comedy", "Drama", "Sci-Fi & Fantasy"], "overview": "Two strangers are drawn to a mysterious pharmaceutical trial that will, they're assured, with no complications or side-effects whatsoever, solve all of their problems, permanently. Things do not go as planned.", "poster": "assets/tv-maniac-2018-poster.jpg", "backdrop": "assets/tv-maniac-2018-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-20T19:42:30.955548Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 73411, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 84, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.323, "tmdbVotes": 1073}}, {"id": "tv-mussolini-son-of-the-century-2024", "title": "Mussolini: Son of the Century", "year": 2024, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 8.135, "criticRating": null, "genres": ["Drama", "War & Politics"], "overview": "The rise of Benito Mussolini and the birth of fascism in Italy, chronicling a country\u2019s surrender to dictatorship and the relentless ascent of a man who rose from his ashes time and again.", "poster": "assets/tv-mussolini-son-of-the-century-2024-poster.jpg", "backdrop": "assets/tv-mussolini-son-of-the-century-2024-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0586588Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 212333, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 96, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.1, "tmdbVotes": 179}}, {"id": "tv-the-night-manager-2016", "title": "The Night Manager", "year": 2016, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 7.74, "criticRating": null, "genres": ["Drama", "Mystery", "Crime"], "overview": "Former British soldier Jonathan Pine navigates the shadowy recesses of Whitehall and Washington where an unholy alliance operates between the intelligence community and the secret arms trade. To infiltrate the inner\u2026", "poster": "assets/tv-the-night-manager-2016-poster.jpg", "backdrop": "assets/tv-the-night-manager-2016-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0663672Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 61859, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 88, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.7, "tmdbVotes": 1422}}, {"id": "tv-one-piece-2023", "title": "ONE PIECE", "year": 2023, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 8.118, "criticRating": null, "genres": ["Action & Adventure", "Sci-Fi & Fantasy"], "overview": "With his straw hat and ragtag crew, young pirate Monkey D. Luffy goes on an epic voyage for treasure.", "poster": "assets/tv-one-piece-2023-poster.jpg", "backdrop": "assets/tv-one-piece-2023-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0439378Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 111110, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 93, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.104, "tmdbVotes": 1988}}, {"id": "tv-only-murders-in-the-building-2021", "title": "Only Murders in the Building", "year": 2021, "type": "tv", "runtimeSeconds": null, "seasonCount": 5, "communityRating": 8.438, "criticRating": null, "genres": ["Comedy", "Mystery", "Crime"], "overview": "Three strangers share an obsession with true crime and suddenly find themselves wrapped up in one.", "poster": "assets/tv-only-murders-in-the-building-2021-poster.jpg", "backdrop": "assets/tv-only-murders-in-the-building-2021-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0594614Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 107113, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 95, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.398, "tmdbVotes": 2333}}, {"id": "tv-over-the-garden-wall-2014", "title": "Over the Garden Wall", "year": 2014, "type": "tv", "runtimeSeconds": 720, "seasonCount": 1, "communityRating": 8.6, "criticRating": null, "genres": ["Mystery", "Sci-Fi & Fantasy", "Animation"], "overview": "Two brothers, Wirt and Greg, find themselves lost in the Unknown; a strange forest adrift in time. With the help of a wise old Woodsman and a foul-tempered bluebird named Beatrice, Wirt and Greg must travel across\u2026", "poster": "assets/tv-over-the-garden-wall-2014-poster.jpg", "backdrop": "assets/tv-over-the-garden-wall-2014-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0455757Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 61617, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.6, "tmdbVotes": 1854}}, {"id": "tv-peaky-blinders-2013", "title": "Peaky Blinders", "year": 2013, "type": "tv", "runtimeSeconds": null, "seasonCount": 6, "communityRating": 8.5, "criticRating": null, "genres": ["Drama", "Crime"], "overview": "A gangster family epic set in 1919 Birmingham, England and centered on a gang who sew razor blades in the peaks of their caps, and their fierce boss Tommy Shelby, who means to move up in the world.", "poster": "assets/tv-peaky-blinders-2013-poster.jpg", "backdrop": "assets/tv-peaky-blinders-2013-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0539185Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 60574, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 93, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.5, "tmdbVotes": 11506}}, {"id": "tv-the-pitt-2025", "title": "The Pitt", "year": 2025, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 8.729, "criticRating": null, "genres": ["Drama"], "overview": "The staff of Pittsburgh's Trauma Medical Center work around the clock to save lives in an overcrowded and underfunded emergency department.", "poster": "assets/tv-the-pitt-2025-poster.jpg", "backdrop": "assets/tv-the-pitt-2025-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0582942Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 250307, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 96, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.731, "tmdbVotes": 1046}}, {"id": "tv-pluribus-2025", "title": "Pluribus", "year": 2025, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.936, "criticRating": null, "genres": ["Drama", "Sci-Fi & Fantasy"], "overview": "The most miserable person on Earth must save the world from happiness.", "poster": "assets/tv-pluribus-2025-poster.jpg", "backdrop": "assets/tv-pluribus-2025-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0674462Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 225171, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 99, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.921, "tmdbVotes": 1191}}, {"id": "tv-ripley-2024", "title": "RIPLEY", "year": 2024, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.911, "criticRating": null, "genres": ["Drama"], "overview": "A grifter in 1960s New York is hired to convince a wealthy man's son to return home from Italy and begins a life of deceit, fraud and murder.", "poster": "assets/tv-ripley-2024-poster.jpg", "backdrop": "assets/tv-ripley-2024-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0658942Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 94028, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 86, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.909, "tmdbVotes": 453}}, {"id": "tv-say-nothing-2024", "title": "Say Nothing", "year": 2024, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.462, "criticRating": null, "genres": ["Drama", "Crime"], "overview": "Through the eyes of various Irish Republican Army (IRA) members, explore the extremes some people will go to in the name of their beliefs, the way a deeply divided society can suddenly tip over into armed conflict,\u2026", "poster": "assets/tv-say-nothing-2024-poster.jpg", "backdrop": "assets/tv-say-nothing-2024-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0499752Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 245256, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 94, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.475, "tmdbVotes": 122}}, {"id": "tv-severance-2022", "title": "Severance", "year": 2022, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 8.396, "criticRating": null, "genres": ["Drama", "Mystery", "Sci-Fi & Fantasy"], "overview": "Mark leads a team of office workers whose memories have been surgically divided between their work and personal lives. When a mysterious colleague appears outside of work, it begins a journey to discover the truth\u2026", "poster": "assets/tv-severance-2022-poster.jpg", "backdrop": "assets/tv-severance-2022-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0598478Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 95396, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 95, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.389, "tmdbVotes": 3095}}, {"id": "tv-six-feet-under-2001", "title": "Six Feet Under", "year": 2001, "type": "tv", "runtimeSeconds": null, "seasonCount": 5, "communityRating": 8.115, "criticRating": null, "genres": ["Drama"], "overview": "When death is your business, what is your life? For the Fisher family, the world outside of their family-owned funeral home continues to be at least as challenging as\u2014and far less predictable than\u2014the one inside.", "poster": "assets/tv-six-feet-under-2001-poster.jpg", "backdrop": "assets/tv-six-feet-under-2001-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-09-26T04:04:05.108787Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 1274, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 81, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.1, "tmdbVotes": 1192}}, {"id": "tv-undercover-2019", "title": "Undercover", "year": 2019, "type": "tv", "runtimeSeconds": 3000, "seasonCount": 3, "communityRating": 7.5, "criticRating": null, "genres": ["Crime", "Drama"], "overview": "Undercover agents infiltrate a drug kingpin's operation by posing as a couple at the campground where he spends his weekends. Inspired by real events.", "poster": "assets/tv-undercover-2019-poster.jpg", "backdrop": "assets/tv-undercover-2019-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0570153Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 86942, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.5, "tmdbVotes": 186}}, {"id": "tv-upload-2020", "title": "Upload", "year": 2020, "type": "tv", "runtimeSeconds": null, "seasonCount": 4, "communityRating": 7.781, "criticRating": null, "genres": ["Comedy", "Sci-Fi & Fantasy", "Drama"], "overview": "In 2033, people who are near death can be \u201cuploaded\u201d into virtual reality hotels run by 6 tech firms. Cash-strapped Nora lives in Brooklyn and works customer service for the luxurious \u201cLakeview\u201d digital afterlife.\u2026", "poster": "assets/tv-upload-2020-poster.jpg", "backdrop": "assets/tv-upload-2020-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0566967Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 86248, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 87, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.757, "tmdbVotes": 1511}}, {"id": "tv-the-walk-in-2022", "title": "The Walk-In", "year": 2022, "type": "tv", "runtimeSeconds": 2760, "seasonCount": 1, "communityRating": 6.9, "criticRating": null, "genres": ["Drama", "Crime"], "overview": "Forced to flee the UK and go into hiding in the 1990s, when he became a mole from within the BNP, Matthew Collins returned to Britain to make a new life for himself, working with young white men in the fight against\u2026", "poster": "assets/tv-the-walk-in-2022-poster.jpg", "backdrop": "assets/tv-the-walk-in-2022-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0654569Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 210664, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 80, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7, "tmdbVotes": 50}}, {"id": "tv-the-white-lotus-2021", "title": "The White Lotus", "year": 2021, "type": "tv", "runtimeSeconds": null, "seasonCount": 3, "communityRating": 7.596, "criticRating": null, "genres": ["Comedy", "Drama", "Mystery"], "overview": "Follow the exploits of various guests and employees at an exclusive tropical resort over the span of a week as with each passing day, a darker complexity emerges in these picture-perfect travelers, the hotel\u2019s\u2026", "poster": "assets/tv-the-white-lotus-2021-poster.jpg", "backdrop": "assets/tv-the-white-lotus-2021-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0546438Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 111803, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 90, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.599, "tmdbVotes": 1604}}, {"id": "tv-widow-s-bay-2026", "title": "Widow's Bay", "year": 2026, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 8.172, "criticRating": null, "genres": ["Drama", "Comedy", "Mystery"], "overview": "The mayor of a New England town resolves to turn it into the next tourist hot spot, despite local warnings that it's cursed.", "poster": "assets/tv-widow-s-bay-2026-poster.jpg", "backdrop": "assets/tv-widow-s-bay-2026-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-20T10:27:12.7003979Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 270476, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 98, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8, "tmdbVotes": 585}}, {"id": "tv-the-witcher-2019", "title": "The Witcher", "year": 2019, "type": "tv", "runtimeSeconds": null, "seasonCount": 4, "communityRating": 7.905, "criticRating": null, "genres": ["Drama", "Action & Adventure"], "overview": "Geralt of Rivia, a mutated monster-hunter for hire, journeys toward his destiny in a turbulent world where people often prove more wicked than beasts.", "poster": "assets/tv-the-witcher-2019-poster.jpg", "backdrop": "assets/tv-the-witcher-2019-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0552369Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 71912, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 75, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.88, "tmdbVotes": 6997}}, {"id": "tv-yellowjackets-2021", "title": "Yellowjackets", "year": 2021, "type": "tv", "runtimeSeconds": null, "seasonCount": 3, "communityRating": 7.449, "criticRating": null, "genres": ["Drama", "Mystery"], "overview": "This equal parts survival epic, psychological horror story and coming-of-age drama tells the saga of a team of wildly talented high school girls soccer players who become the (un)lucky survivors of a plane crash deep\u2026", "poster": "assets/tv-yellowjackets-2021-poster.jpg", "backdrop": "assets/tv-yellowjackets-2021-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T15:45:22.0577612Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 117488, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 92, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.431, "tmdbVotes": 1070}}], "anime": [], "resume": [{"id": "episode-episode-1-2025-s1e1", "title": "Episode 1", "year": 2025, "type": "episode", "runtimeSeconds": 3618, "seasonCount": null, "communityRating": 7.357, "criticRating": null, "genres": ["Biography", "Drama", "History"], "overview": "Mussolini had just founded the Fasci di Combattimento when D'Annunzio took Fiume. Mussolini hoped to capitalize on the poet's achievement in the electoral arena.", "poster": "assets/episode-episode-1-2025-s1e1-poster.jpg", "backdrop": "assets/episode-episode-1-2025-s1e1-backdrop.jpg", "played": false, "playCount": 1, "resumeSeconds": 489.55, "progress": 0.1353, "addedAt": "2026-07-17T13:52:48.0000000Z", "lastPlayedAt": "2026-11-04T19:01:49.9731435Z", "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "Mussolini: Son of the Century", "seasonNumber": 1, "episodeNumber": 1, "artwork": {"posterKind": "center_crop", "backdropKind": "backdrop"}}], "nextUp": [{"id": "episode-no-honeymoon-2020-s1e8", "title": "No Honeymoon", "year": 2020, "type": "episode", "runtimeSeconds": 1499, "seasonCount": null, "communityRating": 6.7, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "Paul attempts to focus on his upcoming wedding but is constantly thwarted by his family; Ally is distracted by work, Luke is misbehaving at school and Leah (Stella Gonet) doesn\u2019t understand why they are even\u2026", "poster": "assets/episode-no-honeymoon-2020-s1e8-poster.jpg", "backdrop": "assets/episode-no-honeymoon-2020-s1e8-backdrop.jpg", "played": false, "playCount": 1, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-28T19:00:50.0000000Z", "lastPlayedAt": "2026-11-03T20:57:58.3314947Z", "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "Breeders", "seasonNumber": 1, "episodeNumber": 8, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}, {"id": "episode-notapusy-2005-s3e4", "title": "Notapusy", "year": 2005, "type": "episode", "runtimeSeconds": 1334, "seasonCount": null, "communityRating": 8.125, "criticRating": null, "genres": ["Comedy"], "overview": "To prove he's a man to Rita, Michael and his nephew Steve Holt compete in the Church And State Fair's annual triathlon. George Sr. tries to scare some at-risk youth, and Tobias tries to help George-Michael's\u2026", "poster": "assets/episode-notapusy-2005-s3e4-poster.jpg", "backdrop": "assets/episode-notapusy-2005-s3e4-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T12:17:58.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "Arrested Development", "seasonNumber": 3, "episodeNumber": 4, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}, {"id": "episode-the-man-who-would-be-vogue-2018-s2e1", "title": "The Man Who Would Be Vogue", "year": 2018, "type": "episode", "runtimeSeconds": 3203, "seasonCount": null, "communityRating": 7.459, "criticRating": null, "genres": ["Biography", "Crime", "Drama"], "overview": "The murder of Gianni Versace turns the eyes of the world onto Miami Beach.", "poster": "assets/episode-the-man-who-would-be-vogue-2018-s2e1-poster.jpg", "backdrop": "assets/episode-the-man-who-would-be-vogue-2018-s2e1-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T13:29:35.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "American Crime Story", "seasonNumber": 2, "episodeNumber": 1, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}, {"id": "episode-tomorrow-2024-s3e1", "title": "Tomorrow", "year": 2024, "type": "episode", "runtimeSeconds": 2207, "seasonCount": null, "communityRating": 7.6, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "The next day and the days that led to it.", "poster": "assets/episode-tomorrow-2024-s3e1-poster.jpg", "backdrop": "assets/episode-tomorrow-2024-s3e1-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-07-17T13:46:39.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "The Bear", "seasonNumber": 3, "episodeNumber": 1, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}}, {"id": "episode-episode-1-2025-s1e1", "title": "Episode 1", "year": 2025, "type": "episode", "runtimeSeconds": 3618, "seasonCount": null, "communityRating": 7.357, "criticRating": null, "genres": ["Biography", "Drama", "History"], "overview": "Mussolini had just founded the Fasci di Combattimento when D'Annunzio took Fiume. Mussolini hoped to capitalize on the poet's achievement in the electoral arena.", "poster": "assets/episode-episode-1-2025-s1e1-poster.jpg", "backdrop": "assets/episode-episode-1-2025-s1e1-backdrop.jpg", "played": false, "playCount": 1, "resumeSeconds": 489.55, "progress": 0.1353, "addedAt": "2026-07-17T13:52:48.0000000Z", "lastPlayedAt": "2026-11-04T19:01:49.9731435Z", "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "seriesTitle": "Mussolini: Son of the Century", "seasonNumber": 1, "episodeNumber": 1, "artwork": {"posterKind": "center_crop", "backdropKind": "backdrop"}}], "recentlyAdded": [{"id": "tv-the-final-problem-2026", "title": "The Final Problem", "year": 2026, "type": "tv", "runtimeSeconds": 3420, "seasonCount": 1, "communityRating": 7.041, "criticRating": null, "genres": ["Crime", "Mystery"], "overview": "In the spring of 1959, a retired actor, who previously played Sherlock Holmes, must investigate a murder at a small hotel on a tiny island near Mallorca.", "poster": "assets/tv-the-final-problem-2026-poster.jpg", "backdrop": "assets/tv-the-final-problem-2026-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-11-04T19:16:12.4822791Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 290720, "artwork": {"posterKind": "center_crop", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.041, "tmdbVotes": 49}}, {"id": "tv-dead-end-job-2026", "title": "Dead-End Job", "year": 2026, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.7, "criticRating": null, "genres": ["Mystery"], "overview": "Drowning in debt, a young man takes lucrative part-time jobs from a mysterious agency \u2014 only to find his hustle for more money turning nightmarish.", "poster": "assets/tv-dead-end-job-2026-poster.jpg", "backdrop": "assets/tv-dead-end-job-2026-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-11-04T18:58:01.8352857Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 289517, "artwork": {"posterKind": "center_crop", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.7, "tmdbVotes": 38}}, {"id": "tv-dune-prophecy-2024", "title": "Dune: Prophecy", "year": 2024, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.213, "criticRating": null, "genres": ["Sci-Fi & Fantasy", "Drama", "Action & Adventure"], "overview": "Ten thousand years before the ascension of Paul Atreides, sisters Valya and Tula Harkonnen establish the fabled sect and female order that would become known as the Bene Gesserit to control the future of humankind.", "poster": "assets/tv-dune-prophecy-2024-poster.jpg", "backdrop": "assets/tv-dune-prophecy-2024-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-11-04T18:23:01.2908568Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 90228, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 64, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.213, "tmdbVotes": 677}}, {"id": "movie-the-uprising-2026", "title": "The Uprising", "year": 2026, "type": "movie", "runtimeSeconds": 7684, "seasonCount": null, "communityRating": 7.846, "criticRating": 55, "genres": ["Action", "Drama", "History"], "overview": "As war and plague devastate 14th-century England, a humble peasant ignites a rebellion, uniting an army of commoners to defy the King\u2019s might in a desperate fight for justice and survival.", "poster": "assets/movie-the-uprising-2026-poster.jpg", "backdrop": "assets/movie-the-uprising-2026-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-11-02T16:37:03.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 977942, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 57, "rtCriticsLabel": "Rotten", "rtAudience": 65, "rtAudienceLabel": "Upright", "imdb": 6.2, "imdbVotes": 6622, "tmdb": 7.8, "tmdbVotes": 404}}, {"id": "movie-jennifer-s-body-2009", "title": "Jennifer's Body", "year": 2009, "type": "movie", "runtimeSeconds": 6450, "seasonCount": null, "communityRating": 6.012, "criticRating": 47, "genres": ["Horror", "Comedy"], "overview": "Jennifer, a gorgeous, seductive cheerleader takes evil to a whole new level after she's possessed by a sinister demon. Now it's up to her best friend to stop Jennifer's reign of terror before it's too late.", "poster": "assets/movie-jennifer-s-body-2009-poster.jpg", "backdrop": "assets/movie-jennifer-s-body-2009-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-30T03:37:04.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 19994, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 47, "rtCriticsLabel": "Rotten", "rtAudience": 36, "rtAudienceLabel": "Spilled", "imdb": 5.6, "imdbVotes": 179710, "tmdb": 6.013, "tmdbVotes": 4481}}, {"id": "tv-breeders-2020", "title": "Breeders", "year": 2020, "type": "tv", "runtimeSeconds": 1500, "seasonCount": 4, "communityRating": 6.8, "criticRating": null, "genres": ["Comedy"], "overview": "Exposing the parental-paradox that it is possible, in the very same moment, to love your child to the horizon of the universe, while being apoplectically angry enough to want to send them there.", "poster": "assets/tv-breeders-2020-poster.jpg", "backdrop": "assets/tv-breeders-2020-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-28T18:54:21.8885435Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 93290, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 92, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.8, "tmdbVotes": 104}}, {"id": "tv-the-four-seasons-2025", "title": "The Four Seasons", "year": 2025, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 6.879, "criticRating": null, "genres": ["Comedy"], "overview": "The decades-long friendship between three married couples is tested when one divorces, complicating their tradition of quarterly weekend getaways.", "poster": "assets/tv-the-four-seasons-2025-poster.jpg", "backdrop": "assets/tv-the-four-seasons-2025-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-28T18:36:42.5326384Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 243316, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 81, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.892, "tmdbVotes": 204}}, {"id": "tv-adults-2025", "title": "Adults", "year": 2025, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 6.495, "criticRating": null, "genres": ["Comedy"], "overview": "A group of twenty-somethings in New York trying to be good people, despite being neither \"good\" nor \"people\" yet.", "poster": "assets/tv-adults-2025-poster.jpg", "backdrop": "assets/tv-adults-2025-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-23T21:01:41.1814765Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 260458, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 88, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.5, "tmdbVotes": 102}}, {"id": "tv-east-of-eden-2026", "title": "East of Eden", "year": 2026, "type": "tv", "runtimeSeconds": null, "seasonCount": 1, "communityRating": 7.931, "criticRating": null, "genres": ["Drama", "Crime"], "overview": "In the early 1900s, a fiercely independent woman drives a rift between two brothers, igniting a saga that unfolds across two generations.", "poster": "assets/tv-east-of-eden-2026-poster.jpg", "backdrop": "assets/tv-east-of-eden-2026-backdrop.jpg", "played": true, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-23T18:07:11.3965096Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 258165, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 88, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.982, "tmdbVotes": 139}}, {"id": "movie-fighting-with-my-family-2019", "title": "Fighting with My Family", "year": 2019, "type": "movie", "runtimeSeconds": 6509, "seasonCount": null, "communityRating": 6.84, "criticRating": 93, "genres": ["Comedy"], "overview": "Born into a tight-knit wrestling family, Paige and her brother Zak are ecstatic when they get the once-in-a-lifetime opportunity to try out for the WWE. But when only Paige earns a spot in the competitive training\u2026", "poster": "assets/movie-fighting-with-my-family-2019-poster.jpg", "backdrop": "assets/movie-fighting-with-my-family-2019-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-22T22:10:59.0000000Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 445629, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 93, "rtCriticsLabel": "Certified Fresh", "rtAudience": 86, "rtAudienceLabel": "Upright", "imdb": 7, "imdbVotes": 94576, "tmdb": 6.837, "tmdbVotes": 1952}}, {"id": "tv-landman-2024", "title": "Landman", "year": 2024, "type": "tv", "runtimeSeconds": null, "seasonCount": 2, "communityRating": 8.194, "criticRating": null, "genres": ["Drama"], "overview": "Set in the proverbial boomtowns of West-Texas and a modern-day tale of fortune-seeking in the world of oil rigs, the series is an upstairs/downstairs story of roughnecks and wildcat billionaires that are fueling a\u2026", "poster": "assets/tv-landman-2024-poster.jpg", "backdrop": "assets/tv-landman-2024-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-22T21:38:18.0973875Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 157741, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 80, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.209, "tmdbVotes": 668}}, {"id": "tv-fawlty-towers-1975", "title": "Fawlty Towers", "year": 1975, "type": "tv", "runtimeSeconds": 1800, "seasonCount": 2, "communityRating": 8.295, "criticRating": null, "genres": ["Comedy"], "overview": "Owner Basil Fawlty, his wife Sybil, a chambermaid Polly, and Spanish waiter Manuel attempt to run their hotel amidst farcical situations and an array of demanding guests.", "poster": "assets/tv-fawlty-towers-1975-poster.jpg", "backdrop": "assets/tv-fawlty-towers-1975-backdrop.jpg", "played": false, "playCount": 0, "resumeSeconds": 0.0, "progress": 0, "addedAt": "2026-10-19T23:26:39.7658344Z", "lastPlayedAt": null, "availability": "in_library", "availabilityEvidence": "viewer_scoped_jellyfin_library", "source": "jellyfin_library", "tmdbId": 2207, "artwork": {"posterKind": "poster", "backdropKind": "backdrop"}, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.296, "tmdbVotes": 867}}], "discover": [{"id": "movie-12-years-a-slave-2013", "title": "12 Years a Slave", "year": 2013, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "History"], "overview": "In the pre-Civil War United States, Solomon Northup, a free black man from upstate New York, is abducted and sold into slavery. Facing cruelty as well as unexpected kindnesses Solomon struggles not only to stay\u2026", "poster": "assets/movie-12-years-a-slave-2013-poster.jpg", "backdrop": "assets/movie-12-years-a-slave-2013-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 76203, "ratings": {"rtCritics": 95, "rtCriticsLabel": "Certified Fresh", "rtAudience": 90, "rtAudienceLabel": "Upright", "imdb": 8.1, "imdbVotes": 796313, "tmdb": 7.927, "tmdbVotes": 12335}}, {"id": "movie-101-dalmatians-ii-patch-s-london-adventure-2003", "title": "101 Dalmatians II: Patch's London Adventure", "year": 2003, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Family", "Animation", "Adventure"], "overview": "Being one of 101 takes its toll on Patch, who doesn't feel unique. When he's accidentally left behind on moving day, he meets his idol, Thunderbolt, who enlists him on a publicity campaign.", "poster": "assets/movie-101-dalmatians-ii-patch-s-london-adventure-2003-poster.jpg", "backdrop": "assets/movie-101-dalmatians-ii-patch-s-london-adventure-2003-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 13654, "ratings": {"rtCritics": 67, "rtCriticsLabel": "Fresh", "rtAudience": 41, "rtAudienceLabel": "Spilled", "imdb": 5.7, "imdbVotes": 12343, "tmdb": 6.025, "tmdbVotes": 1274}}, {"id": "movie-absolution-2024", "title": "Absolution", "year": 2024, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action", "Crime", "Thriller"], "overview": "An aging ex-boxer gangster working as muscle for a Boston crime boss receives an upsetting diagnosis. Despite a faltering memory, he attempts to rectify the sins of his past and reconnect with his estranged\u2026", "poster": "assets/movie-absolution-2024-poster.jpg", "backdrop": "assets/movie-absolution-2024-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 974453, "ratings": {"rtCritics": 56, "rtCriticsLabel": "Rotten", "rtAudience": 32, "rtAudienceLabel": "Spilled", "imdb": 5.2, "imdbVotes": 11413, "tmdb": 5.906, "tmdbVotes": 564}}, {"id": "movie-addicted-2014", "title": "Addicted", "year": 2014, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Thriller"], "overview": "A gallerist risks her family and flourishing career when she enters into an affair with a talented painter and slowly loses control of her life.", "poster": "assets/movie-addicted-2014-poster.jpg", "backdrop": "assets/movie-addicted-2014-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 235271, "ratings": {"rtCritics": 7, "rtCriticsLabel": "Rotten", "rtAudience": 51, "rtAudienceLabel": "Spilled", "imdb": 5, "imdbVotes": 13131, "tmdb": 5.928, "tmdbVotes": 466}}, {"id": "movie-all-the-money-in-the-world-2017", "title": "All the Money in the World", "year": 2017, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Crime", "History", "Thriller"], "overview": "The story of the kidnapping of 16-year-old John Paul Getty III and the desperate attempt by his devoted mother to convince his billionaire grandfather Jean Paul Getty to pay the ransom.", "poster": "assets/movie-all-the-money-in-the-world-2017-poster.jpg", "backdrop": "assets/movie-all-the-money-in-the-world-2017-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 446791, "ratings": {"rtCritics": 79, "rtCriticsLabel": "Certified Fresh", "rtAudience": 66, "rtAudienceLabel": "Upright", "imdb": 6.8, "imdbVotes": 97448, "tmdb": 6.493, "tmdbVotes": 2493}}, {"id": "movie-the-alto-knights-2025", "title": "The Alto Knights", "year": 2025, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Crime", "Drama"], "overview": "Two of New York's most notorious organized crime bosses, Frank Costello and Vito Genovese, vie for control of the city's streets. Once the best of friends, petty jealousies and a series of betrayals place them on a\u2026", "poster": "assets/movie-the-alto-knights-2025-poster.jpg", "backdrop": "assets/movie-the-alto-knights-2025-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 1013601, "ratings": {"rtCritics": 39, "rtCriticsLabel": "Rotten", "rtAudience": 71, "rtAudienceLabel": "Upright", "imdb": 5.9, "imdbVotes": 23017, "tmdb": 6.223, "tmdbVotes": 485}}, {"id": "movie-the-amazing-spider-man-2-2014", "title": "The Amazing Spider-Man 2", "year": 2014, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action", "Adventure", "Science Fiction"], "overview": "For Peter Parker, life is busy. Between taking out the bad guys as Spider-Man and spending time with the person he loves, Gwen Stacy, high school graduation cannot come quickly enough. Peter has not forgotten about\u2026", "poster": "assets/movie-the-amazing-spider-man-2-2014-poster.jpg", "backdrop": "assets/movie-the-amazing-spider-man-2-2014-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 102382, "ratings": {"rtCritics": 51, "rtCriticsLabel": "Rotten", "rtAudience": 64, "rtAudienceLabel": "Upright", "imdb": 6.6, "imdbVotes": 611981, "tmdb": 6.567, "tmdbVotes": 14919}}, {"id": "movie-ant-man-and-the-wasp-quantumania-2023", "title": "Ant-Man and the Wasp: Quantumania", "year": 2023, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action", "Adventure", "Science Fiction"], "overview": "Super-Hero partners Scott Lang and Hope van Dyne, along with with Hope's parents Janet van Dyne and Hank Pym, and Scott's daughter Cassie Lang, find themselves exploring the Quantum Realm, interacting with strange\u2026", "poster": "assets/movie-ant-man-and-the-wasp-quantumania-2023-poster.jpg", "backdrop": "assets/movie-ant-man-and-the-wasp-quantumania-2023-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 640146, "ratings": {"rtCritics": 46, "rtCriticsLabel": "Rotten", "rtAudience": 81, "rtAudienceLabel": "Upright", "imdb": 6, "imdbVotes": 281738, "tmdb": 6.197, "tmdbVotes": 6236}}, {"id": "movie-arctic-dogs-2019", "title": "Arctic Dogs", "year": 2019, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Animation", "Adventure", "Comedy"], "overview": "Animals band together to save the day when the evil Otto Von Walrus hatches a sinister scheme to accelerate global warming and melt the Arctic Circle.", "poster": "assets/movie-arctic-dogs-2019-poster.jpg", "backdrop": "assets/movie-arctic-dogs-2019-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 416153, "ratings": {"rtCritics": 13, "rtCriticsLabel": "Rotten", "rtAudience": 60, "rtAudienceLabel": "Upright", "imdb": 4.9, "imdbVotes": 2580, "tmdb": 5.9, "tmdbVotes": 148}}, {"id": "movie-the-avengers-2012", "title": "The Avengers", "year": 2012, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Science Fiction", "Action", "Adventure"], "overview": "When an unexpected enemy emerges and threatens global safety and security, Nick Fury, director of the international peacekeeping agency known as S.H.I.E.L.D., finds himself in need of a team to pull the world back\u2026", "poster": "assets/movie-the-avengers-2012-poster.jpg", "backdrop": "assets/movie-the-avengers-2012-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 24428, "ratings": {"rtCritics": 91, "rtCriticsLabel": "Certified Fresh", "rtAudience": 91, "rtAudienceLabel": "Upright", "imdb": 8, "imdbVotes": 1590693, "tmdb": 8.084, "tmdbVotes": 40262}}, {"id": "movie-black-bear-2020", "title": "Black Bear", "year": 2020, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Thriller"], "overview": "At a remote lake house in the Adirondack Mountains, a couple entertains an out-of-town guest looking for inspiration in her filmmaking. The group quickly falls into a calculated game of desire, manipulation, and\u2026", "poster": "assets/movie-black-bear-2020-poster.jpg", "backdrop": "assets/movie-black-bear-2020-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 624788, "ratings": {"rtCritics": 89, "rtCriticsLabel": "Certified Fresh", "rtAudience": 64, "rtAudienceLabel": "Upright", "imdb": 6.5, "imdbVotes": 18408, "tmdb": 6.337, "tmdbVotes": 315}}, {"id": "movie-black-panther-2018", "title": "Black Panther", "year": 2018, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action", "Adventure", "Science Fiction"], "overview": "King T'Challa returns home to the reclusive, technologically advanced African nation of Wakanda to serve as his country's new leader. However, T'Challa soon finds that he is challenged for the throne by factions\u2026", "poster": "assets/movie-black-panther-2018-poster.jpg", "backdrop": "assets/movie-black-panther-2018-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 284054, "ratings": {"rtCritics": 96, "rtCriticsLabel": "Certified Fresh", "rtAudience": null, "rtAudienceLabel": "Spilled", "imdb": 7.3, "imdbVotes": 931120, "tmdb": 7.36, "tmdbVotes": 24190}}, {"id": "movie-a-bronx-tale-1993", "title": "A Bronx Tale", "year": 1993, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Crime"], "overview": "Set in the Bronx during the tumultuous 1960s, an adolescent boy is torn between his honest, working-class father and a violent yet charismatic crime boss. Complicating matters is the youngster's growing attraction -\u2026", "poster": "assets/movie-a-bronx-tale-1993-poster.jpg", "backdrop": "assets/movie-a-bronx-tale-1993-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 1607, "ratings": {"rtCritics": 97, "rtCriticsLabel": "Fresh", "rtAudience": 92, "rtAudienceLabel": "Upright", "imdb": 7.8, "imdbVotes": 191930, "tmdb": 7.913, "tmdbVotes": 3075}}, {"id": "movie-by-any-means-2026", "title": "By Any Means", "year": 2026, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Thriller", "History", "Crime"], "overview": "In 1960s Mississippi, a young Black FBI agent is forced to partner with a notorious mafia hitman to investigate a wave of brutal civil rights murders.", "poster": "assets/movie-by-any-means-2026-poster.jpg", "backdrop": "assets/movie-by-any-means-2026-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 1380417, "ratings": {"rtCritics": 49, "rtCriticsLabel": "Rotten", "rtAudience": 88, "rtAudienceLabel": "Upright", "imdb": 6.8, "imdbVotes": 3534, "tmdb": 6.6, "tmdbVotes": 92}}, {"id": "movie-captain-america-civil-war-2016", "title": "Captain America: Civil War", "year": 2016, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Adventure", "Action", "Science Fiction"], "overview": "Following the events of Age of Ultron, the collective governments of the world pass an act designed to regulate all superhuman activity. This polarizes opinion amongst the Avengers, causing two factions to side with\u2026", "poster": "assets/movie-captain-america-civil-war-2016-poster.jpg", "backdrop": "assets/movie-captain-america-civil-war-2016-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 271110, "ratings": {"rtCritics": 90, "rtCriticsLabel": "Certified Fresh", "rtAudience": 89, "rtAudienceLabel": "Upright", "imdb": 7.8, "imdbVotes": 954943, "tmdb": 7.455, "tmdbVotes": 24808}}, {"id": "movie-captain-america-the-first-avenger-2011", "title": "Captain America: The First Avenger", "year": 2011, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action", "Adventure", "Science Fiction"], "overview": "During World War II, Steve Rogers is a sickly man from Brooklyn who's transformed into super-soldier Captain America to aid in the war effort. Rogers must stop the Red Skull \u2013 Adolf Hitler's ruthless head of\u2026", "poster": "assets/movie-captain-america-the-first-avenger-2011-poster.jpg", "backdrop": "assets/movie-captain-america-the-first-avenger-2011-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 1771, "ratings": {"rtCritics": 80, "rtCriticsLabel": "Certified Fresh", "rtAudience": 75, "rtAudienceLabel": "Upright", "imdb": 6.9, "imdbVotes": 993453, "tmdb": 7.012, "tmdbVotes": 23473}}, {"id": "movie-captain-america-the-winter-soldier-2014", "title": "Captain America: The Winter Soldier", "year": 2014, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action", "Adventure", "Science Fiction"], "overview": "After the cataclysmic events in New York with The Avengers, Steve Rogers, aka Captain America is living quietly in Washington, D.C. and trying to adjust to the modern world. But when a S.H.I.E.L.D. colleague comes\u2026", "poster": "assets/movie-captain-america-the-winter-soldier-2014-poster.jpg", "backdrop": "assets/movie-captain-america-the-winter-soldier-2014-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 100402, "ratings": {"rtCritics": 90, "rtCriticsLabel": "Certified Fresh", "rtAudience": 92, "rtAudienceLabel": "Upright", "imdb": 7.7, "imdbVotes": 995514, "tmdb": 7.654, "tmdbVotes": 20688}}, {"id": "movie-careful-what-you-wish-for-2015", "title": "Careful What You Wish For", "year": 2015, "type": "movie", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Thriller"], "overview": "A guy gets more than he bargained for after entering into an affair with the wife of an investment banker. Soon, a suspicious death and substantial life insurance policy embroil him in a scandal.", "poster": "assets/movie-careful-what-you-wish-for-2015-poster.jpg", "backdrop": "assets/movie-careful-what-you-wish-for-2015-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 317744, "ratings": {"rtCritics": 17, "rtCriticsLabel": "Rotten", "rtAudience": 61, "rtAudienceLabel": "Upright", "imdb": 5.6, "imdbVotes": 9452, "tmdb": 6.129, "tmdbVotes": 446}}, {"id": "tv-12-monkeys-2015", "title": "12 Monkeys", "year": 2015, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Sci-Fi & Fantasy", "Drama"], "overview": "The provocative story of Cole, a time traveler from a decimated future in a high-stakes race against the clock. Utilizing a dangerous and untested method of time travel, he journeys from 2043 to the present day on a\u2026", "poster": "assets/tv-12-monkeys-2015-poster.jpg", "backdrop": "assets/tv-12-monkeys-2015-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 60948, "ratings": {"rtCritics": 88, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.441, "tmdbVotes": 1245}}, {"id": "tv-90-day-fiance-before-the-90-days-2017", "title": "90 Day Fianc\u00e9: Before the 90 Days", "year": 2017, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Reality"], "overview": "Follow couples who have an existing relationship online, but haven't met in person. We'll experience their journey as they travel to the other's foreign country for the first time in an attempt to establish an\u2026", "poster": "assets/tv-90-day-fiance-before-the-90-days-2017-poster.jpg", "backdrop": "assets/tv-90-day-fiance-before-the-90-days-2017-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 73319, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.5, "tmdbVotes": 45}}, {"id": "tv-90-day-fiance-the-other-way-2019", "title": "90 Day Fianc\u00e9: The Other Way", "year": 2019, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Reality"], "overview": "Americans move to a foreign country all in the name of love. Will uprooting their lives in the United States pay off, or will they be packing up and moving back to America brokenhearted?", "poster": "assets/tv-90-day-fiance-the-other-way-2019-poster.jpg", "backdrop": "assets/tv-90-day-fiance-the-other-way-2019-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 90046, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.8, "tmdbVotes": 34}}, {"id": "tv-the-100-2014", "title": "The 100", "year": 2014, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Sci-Fi & Fantasy", "Action & Adventure", "Drama"], "overview": "100 years in the future, when the Earth has been abandoned due to radioactivity, the last surviving humans live on an ark orbiting the planet \u2014 but the ark won't last forever. So the repressive regime picks 100\u2026", "poster": "assets/tv-the-100-2014-poster.jpg", "backdrop": "assets/tv-the-100-2014-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 48866, "ratings": {"rtCritics": 93, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.878, "tmdbVotes": 8855}}, {"id": "tv-accused-2023", "title": "Accused", "year": 2023, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Crime", "Drama"], "overview": "In this crime anthology series, viewers discover how an ordinary person got caught up in an extraordinary situation, ultimately revealing how one wrong turn leads to another, until it\u2019s too late to turn back. Told\u2026", "poster": "assets/tv-accused-2023-poster.jpg", "backdrop": "assets/tv-accused-2023-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 202097, "ratings": {"rtCritics": 61, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.851, "tmdbVotes": 87}}, {"id": "tv-after-life-2019", "title": "After Life", "year": 2019, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "Tony had a perfect life. But after his wife Lisa suddenly dies, Tony changes. After contemplating taking his own life, he decides instead to live long enough to punish the world by saying and doing whatever he likes\u2026", "poster": "assets/tv-after-life-2019-poster.jpg", "backdrop": "assets/tv-after-life-2019-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 79410, "ratings": {"rtCritics": 72, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.902, "tmdbVotes": 1169}}, {"id": "tv-all-creatures-great-and-small-1978", "title": "All Creatures Great and Small", "year": 1978, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Comedy", "Drama"], "overview": "The trials and misadventures of the staff at a country veterinary office in Yorkshire. James Herriot, a young animal surgeon, moves to a small Yorkshire town to begin his first job.", "poster": "assets/tv-all-creatures-great-and-small-1978-poster.jpg", "backdrop": "assets/tv-all-creatures-great-and-small-1978-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "center_crop", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 7406, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.8, "tmdbVotes": 50}}, {"id": "tv-american-housewife-2016", "title": "American Housewife", "year": 2016, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Comedy"], "overview": "A family comedy narrated by Katie, a strong-willed mother, raising her flawed family in a wealthy town filled with perfect wives and their perfect offspring.", "poster": "assets/tv-american-housewife-2016-poster.jpg", "backdrop": "assets/tv-american-housewife-2016-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 67117, "ratings": {"rtCritics": null, "rtCriticsLabel": "Rotten", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.7, "tmdbVotes": 187}}, {"id": "tv-atlantis-2013", "title": "Atlantis", "year": 2013, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action & Adventure", "Sci-Fi & Fantasy"], "overview": "A fantasy drama set in a world of legendary heroes and mythical creatures. Far from home and desperate for answers, Jason washes up on the shores of an ancient land. A mysterious place; a world of bull leaping, of\u2026", "poster": "assets/tv-atlantis-2013-poster.jpg", "backdrop": "assets/tv-atlantis-2013-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 47054, "ratings": {"rtCritics": 62, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.4, "tmdbVotes": 155}}, {"id": "tv-avatar-the-last-airbender-2024", "title": "Avatar: The Last Airbender", "year": 2024, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Action & Adventure", "Sci-Fi & Fantasy", "Drama"], "overview": "A young boy known as the Avatar must master the four elemental powers to save a world at war \u2014 and fight a ruthless enemy bent on stopping him.", "poster": "assets/tv-avatar-the-last-airbender-2024-poster.jpg", "backdrop": "assets/tv-avatar-the-last-airbender-2024-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 82452, "ratings": {"rtCritics": 66, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.8, "tmdbVotes": 1406}}, {"id": "tv-avatar-seven-havens-2026", "title": "Avatar: Seven Havens", "year": 2026, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "In a world shattered by a devastating cataclysm, a young Earthbender discovers she's the new Avatar after Korra. But in this dangerous era, that title marks her as humanity's destroyer, not its savior. Hunted by both\u2026", "poster": "assets/tv-avatar-seven-havens-2026-poster.jpg", "backdrop": "assets/tv-avatar-seven-havens-2026-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 284833, "ratings": {"rtCritics": 100, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.9, "tmdbVotes": 183}}, {"id": "tv-batman-the-brave-and-the-bold-2008", "title": "Batman: The Brave and the Bold", "year": 2008, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Animation", "Action & Adventure", "Sci-Fi & Fantasy"], "overview": "The Caped Crusader is teamed up with Blue Beetle, Green Arrow, Aquaman and countless others in his quest to uphold justice.", "poster": "assets/tv-batman-the-brave-and-the-bold-2008-poster.jpg", "backdrop": "assets/tv-batman-the-brave-and-the-bold-2008-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 15804, "ratings": {"rtCritics": 96, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.6, "tmdbVotes": 295}}, {"id": "tv-beat-bobby-flay-2013", "title": "Beat Bobby Flay", "year": 2013, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Reality"], "overview": "Two talented chefs go head-to-head for the chance to Beat Bobby Flay. To get to Bobby the chefs must first face off against each other, creating a spectacular dish with a secret ingredient of Bobby's choice. Judges\u2026", "poster": "assets/tv-beat-bobby-flay-2013-poster.jpg", "backdrop": "assets/tv-beat-bobby-flay-2013-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 62481, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.5, "tmdbVotes": 31}}, {"id": "tv-benson-1979", "title": "Benson", "year": 1979, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Comedy"], "overview": "A butler deals with life at the governor's mansion.", "poster": "assets/tv-benson-1979-poster.jpg", "backdrop": "assets/tv-benson-1979-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 1849, "ratings": {"rtCritics": null, "rtCriticsLabel": null, "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7, "tmdbVotes": 46}}, {"id": "tv-black-rabbit-2025", "title": "Black Rabbit", "year": 2025, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Crime"], "overview": "A rising-star restaurateur is forced into New York's criminal underworld when his chaotic brother returns to town with loan sharks on his trail.", "poster": "assets/tv-black-rabbit-2025-poster.jpg", "backdrop": "assets/tv-black-rabbit-2025-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 249039, "ratings": {"rtCritics": 66, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 6.983, "tmdbVotes": 240}}, {"id": "tv-black-ish-2014", "title": "black-ish", "year": 2014, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Comedy"], "overview": "A family man struggles to gain a sense of cultural identity while raising his kids in a predominantly white, upper-middle-class neighborhood.", "poster": "assets/tv-black-ish-2014-poster.jpg", "backdrop": "assets/tv-black-ish-2014-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 61381, "ratings": {"rtCritics": 92, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.1, "tmdbVotes": 352}}, {"id": "tv-breaking-bad-2008", "title": "Breaking Bad", "year": 2008, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Drama", "Crime"], "overview": "Walter White, a New Mexico chemistry teacher, is diagnosed with Stage III cancer and given a prognosis of only two years left to live. He becomes filled with a sense of fearlessness and an unrelenting desire to\u2026", "poster": "assets/tv-breaking-bad-2008-poster.jpg", "backdrop": "assets/tv-breaking-bad-2008-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "center_crop", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 1396, "ratings": {"rtCritics": 96, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 8.959, "tmdbVotes": 19030}}, {"id": "tv-the-capture-2019", "title": "The Capture", "year": 2019, "type": "tv", "runtimeSeconds": null, "seasonCount": null, "communityRating": null, "criticRating": null, "genres": ["Crime", "Drama", "Mystery"], "overview": "When soldier Shaun Emery's conviction for a murder in Afghanistan is overturned due to flawed video evidence, he returns to life as a free man with his young daughter. But when damning CCTV footage from a night out\u2026", "poster": "assets/tv-the-capture-2019-poster.jpg", "backdrop": "assets/tv-the-capture-2019-backdrop.jpg", "played": null, "playCount": null, "resumeSeconds": null, "progress": null, "addedAt": null, "lastPlayedAt": null, "availability": "not_here", "availabilityEvidence": "retained_profile_membership_and_native_request_ledger", "source": "materialized_personal_recommendation", "rank": null, "watchStateKnown": false, "artwork": {"posterKind": "poster", "backdropKind": "poster_crop"}, "availabilityIsSnapshot": true, "tmdbId": 93166, "ratings": {"rtCritics": 97, "rtCriticsLabel": "Fresh", "rtAudience": null, "rtAudienceLabel": null, "imdb": null, "imdbVotes": null, "tmdb": 7.634, "tmdbVotes": 361}}], "discoverySource": {"state": "materialized_snapshot", "rankKnown": false, "selection": "First 18 alphabetically indexed movie stubs and first 18 series stubs, not ranked feed order", "observedAt": "2026-11-04T20:42:12.030108+00:00"}}], "notes": {"real": ["Profile keys and library membership derive from deployed Conductarr configuration and viewer-scoped Jellyfin GET responses.", "Names, years, overviews, library ratings, genres, season-container counts and watch/resume data come from actual Jellyfin metadata.", "All local artwork is copied from Jellyfin; discovery posters are the real materialized Conductarr recommendation artwork.", "Discover contains 36 real materialized personal recommendations per profile, with profile-scoped availability from read-only retained membership/request state.", "Justin has no playable resume items. Mindel and Shared each have one. No progress or watched flags were invented."], "approximations": ["Default profile initials and display capitalization are frontend presentation choices; colours reuse the existing PWA palette, not live user appearance configuration.", "Conductarr catalogue and recommendation GET endpoints both returned 401. Authentication was not bypassed. SQLite contains no retained recommendation feed/candidate snapshot tables; the source keeps ranked feeds in memory. Discovery therefore reads existing per-profile Jellyfin recommendation stubs as metadata only.", "Discovery selection is 18 alphabetically indexed movie suggestions plus 18 series suggestions, not personal rank order; rank is null. Materialization age and original feed ordering are unknown.", "Discovery stub runtime is synthetic (two seconds), so runtime, season count, rating and watch state are null rather than presenting stub values as real media facts.", "93 selected identities lack original landscape art in the materialized metadata; their backdrop is a marked crop of the real poster, not an original film backdrop. Existing artwork is reused; new artwork is centre-cropped to the required dimensions.", "Jellyfin server-side resizing requests maxWidth/maxHeight/quality. When the result had the wrong aspect ratio, sequential single-thread ffmpeg center crops produce exact 300x450 and 1280x720 JPEGs.", "Series seasonCount is Jellyfin ChildCount, including season containers for specials when present.", "Discover availability is a retained profile-membership/request snapshot, not a fresh playback or acquisition guarantee. not_here means absent from that profile in retained state, not absent from the entire household."], "missing": ["Justin Movies has seven live viewer-scoped films, not 200. No titles are invented or borrowed across profile boundaries.", "Discovery community/critic ratings, reliable runtime/season counts, personal feed ranking/freshness and 93 original landscape backdrops are unavailable through the permitted read paths."], "unmetRequirements": ["At least 200 real profile-scoped Justin Movies"], "mustNotBeShown": ["Recs Movies", "Recs Shows", "Justin Movies", "Justin Shows", "Mindel Movies", "Mindel Shows", "Shared Movies", "Shared Shows", "DGiC", "Stored names padded with spaces", "Internal bucket and acquisition-instance names"], "privacy": ["Includes actual watched and resume history for Justin, Mindel and Shared independently; Shared is not a union.", "No Jellyfin item/user IDs, source paths, service URLs, credentials, request actor identities, or private hotlinks are included. tmdbId is a public external title identity.", "Only the seven configured playable libraries are selected. Extra observed DGiC views and all recommendation stubs are excluded from playable collections.", "No profile is assumed to be a child or age-restricted. Each playable list and episode shelf is limited to that profile\u2019s configured libraries."], "sourceReadPaths": ["GET /Users (allowlisted mapping only)", "GET /Users/{userId}/Views", "GET /Users/{userId}/Items (parent-scoped playable libraries and metadata-only recommendation libraries)", "GET /Users/{userId}/Items/Resume", "GET /Shows/NextUp?UserId=...", "GET /Items/{itemId}/Images/Primary", "GET /Items/{itemId}/Images/Backdrop/0", "Conductarr GET /catalogue/discover?page=1&media_type=movie (401)", "Conductarr GET /api/v1/recommendations/profiles/justin/feed (401)", "SQLite file URI mode=ro plus PRAGMA query_only=ON: catalogue_metadata, bucket_memberships, native_requests; sqlite_master for schema inspection"], "productionMutations": 0, "artwork": {"files": 632, "bytes": 35201423, "posterDimensions": [300, 450], "backdropDimensions": [1280, 720], "posterQualityRequested": 70, "backdropQualityRequested": 65, "posterDerivedBackdropCount": 93}, "consumerContract": ["profiles is an array in Justin/Mindel/Shared order. Every profile owns movies/shows/anime/resume/nextUp/recentlyAdded/discover item arrays; empty shelves are intentional.", "Item paths are relative to fixture.json. Resolve assets against the fixture directory, not against the outer prototype document.", "Use destinations for visible navigation. No raw library display/stored names belong in UI.", "Deduplicate library/resume/discover by stable local id or (type,tmdbId). Never treat a materialized recommendation as a playable library item.", "played=null and watchStateKnown=false mean unknown, not unwatched. Null ratings are missing, not zero; communityRating source is Jellyfin, not an asserted TMDB/IMDb score.", "availability values are in_library/requested/not_here. No requested examples were observed in the selected discover set; do not fabricate them.", "Render artwork.backdropKind=poster_crop as a poster-derived landscape; prefer the poster over pretending it is original landscape art.", "This static fixture preserves actual current collection sizes, viewer-scoped watch state and unknown discovery ranking; request and playback demonstrations must remain labelled simulations."]}} \ No newline at end of file diff --git a/wolfskin-design/src/test/resources/wolfskin-home-presses.json b/wolfskin-design/src/test/resources/wolfskin-home-presses.json new file mode 100644 index 00000000..700edd60 --- /dev/null +++ b/wolfskin-design/src/test/resources/wolfskin-home-presses.json @@ -0,0 +1,126 @@ +[ + { + "goal": "Resume (Mindel, from launch)", + "keys": [ + "RIGHT", + "OK", + "OK" + ], + "presses": 3, + "note": "", + "start": "app launch: Who's watching with Justin focused (index.html:357)", + "replayed": "PASS", + "source": "index.html:2152-2174 PRESSES, replayed 2026-11-05" + }, + { + "goal": "Play next (Justin has no resume)", + "keys": [ + "OK", + "OK" + ], + "presses": 2, + "note": "", + "start": "app launch: Who's watching with Justin focused (index.html:357)", + "replayed": "PASS", + "source": "index.html:2152-2174 PRESSES, replayed 2026-11-05" + }, + { + "goal": "Round 3 \u00b7 Home hero \u2192 Trending (D2 split)", + "keys": [ + "OK", + "DOWN", + "DOWN", + "DOWN", + "DOWN", + "DOWN", + "DOWN", + "DOWN", + "DOWN", + "DOWN", + "DOWN", + "DOWN", + "DOWN" + ], + "presses": 13, + "note": "12 Downs after the launch OK", + "start": "app launch: Who's watching with Justin focused (index.html:357)", + "replayed": "PASS", + "source": "index.html:2152-2174 PRESSES, replayed 2026-11-05" + }, + { + "goal": "Round 3 \u00b7 Trending \u2192 its See all card (D3: 20 cards)", + "keys": [ + "OK", + "DOWN", + "DOWN", + "DOWN", + "DOWN", + "DOWN", + "DOWN", + "DOWN", + "DOWN", + "DOWN", + "DOWN", + "DOWN", + "DOWN", + "RIGHT", + "RIGHT", + "RIGHT", + "RIGHT", + "RIGHT", + "RIGHT", + "RIGHT", + "RIGHT", + "RIGHT", + "RIGHT", + "RIGHT", + "RIGHT", + "RIGHT", + "RIGHT", + "RIGHT", + "RIGHT", + "RIGHT", + "RIGHT", + "RIGHT", + "RIGHT" + ], + "presses": 33, + "note": "20 Rights from Trending", + "start": "app launch: Who's watching with Justin focused (index.html:357)", + "replayed": "PASS", + "source": "index.html:2152-2174 PRESSES, replayed 2026-11-05" + }, + { + "goal": "Round 3 \u00b7 deep Home row: Back to the nav, Down to the same card", + "keys": [ + "OK", + "DOWN", + "DOWN", + "DOWN", + "DOWN", + "RIGHT", + "RIGHT", + "BACK", + "DOWN" + ], + "presses": 9, + "note": "2: Back, Down", + "start": "app launch: Who's watching with Justin focused (index.html:357)", + "replayed": "PASS", + "source": "index.html:2152-2174 PRESSES, replayed 2026-11-05" + }, + { + "goal": "Open Discover", + "keys": [ + "OK", + "UP", + "RIGHT", + "OK" + ], + "presses": 4, + "note": "", + "start": "app launch: Who's watching with Justin focused (index.html:357)", + "replayed": "PASS", + "source": "index.html:2152-2174 PRESSES, replayed 2026-11-05" + } +] diff --git a/wolfskin-design/src/test/resources/wolfskin-library.json b/wolfskin-design/src/test/resources/wolfskin-library.json new file mode 100644 index 00000000..76617014 --- /dev/null +++ b/wolfskin-design/src/test/resources/wolfskin-library.json @@ -0,0 +1 @@ +{"profiles":[{"key":"justin","movies":[{"id":"movie-the-girl-who-leapt-through-time-2006","title":"The Girl Who Leapt Through Time","year":2006,"type":"movie","runtimeSeconds":5886,"seasonCount":null,"communityRating":7.772,"criticRating":87,"genres":["Fantasy","Animation","Drama"],"overview":"When 17-year-old Makoto Konno gains the ability to 'leap' backwards through time, she immediately sets about improving her grades and preventing personal mishaps. However, she soon realises that changing the past\u2026","poster":"assets/movie-the-girl-who-leapt-through-time-2006-poster.jpg","backdrop":"assets/movie-the-girl-who-leapt-through-time-2006-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T17:39:11.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":14069,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":87,"rtCriticsLabel":"Fresh","rtAudience":90,"rtAudienceLabel":"Upright","imdb":7.6,"imdbVotes":76917,"tmdb":7.775,"tmdbVotes":2345}},{"id":"movie-locke-2014","title":"Locke","year":2014,"type":"movie","runtimeSeconds":5090,"seasonCount":null,"communityRating":6.891,"criticRating":91,"genres":["Drama","Thriller"],"overview":"Ivan Locke has worked hard to craft a good life for himself. Tonight, that life will collapse around him. On the eve of the biggest challenge of his career, Ivan receives a phone call that sets in motion a series of\u2026","poster":"assets/movie-locke-2014-poster.jpg","backdrop":"assets/movie-locke-2014-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T17:38:48.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":210479,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":90,"rtCriticsLabel":"Certified Fresh","rtAudience":72,"rtAudienceLabel":"Upright","imdb":7.1,"imdbVotes":171265,"tmdb":6.889,"tmdbVotes":3088}},{"id":"movie-look-who-s-back-2015","title":"Look Who's Back","year":2015,"type":"movie","runtimeSeconds":6936,"seasonCount":null,"communityRating":6.793,"criticRating":null,"genres":["Comedy"],"overview":"When Adolf Hitler reawakens at the site of his former bunker in present-day Berlin, he is mistaken for a comedian and quickly becomes a media phenomenon.","poster":"assets/movie-look-who-s-back-2015-poster.jpg","backdrop":"assets/movie-look-who-s-back-2015-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:27:48.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":318917,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":81,"rtAudienceLabel":"Upright","imdb":7,"imdbVotes":54672,"tmdb":6.796,"tmdbVotes":1990}},{"id":"movie-memories-1995","title":"Memories","year":1995,"type":"movie","runtimeSeconds":6805,"seasonCount":null,"communityRating":7.465,"criticRating":null,"genres":["Fantasy","Animation","Science Fiction"],"overview":"Three back-to-back anime films by three different directors make up this sci-fi trilogy three years in the making.","poster":"assets/movie-memories-1995-poster.jpg","backdrop":"assets/movie-memories-1995-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-30T21:36:03.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":42994,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":82,"rtAudienceLabel":"Upright","imdb":7.5,"imdbVotes":26638,"tmdb":7.459,"tmdbVotes":622}},{"id":"movie-reincarnated-2012","title":"Reincarnated","year":2012,"type":"movie","runtimeSeconds":5759,"seasonCount":null,"communityRating":6.145,"criticRating":28,"genres":["Music","Documentary"],"overview":"Evolution as an artist is often times what separates legends from the more mundane. After being heavily influenced by his experience in Jamaica \u2013 and his subsequent name change from Snoop Dogg to Snoop Lion \u2013 the LBC\u2026","poster":"assets/movie-reincarnated-2012-poster.jpg","backdrop":"assets/movie-reincarnated-2012-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:27:26.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":123431,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":28,"rtCriticsLabel":"Rotten","rtAudience":41,"rtAudienceLabel":"Spilled","imdb":6.2,"imdbVotes":2563,"tmdb":6.1,"tmdbVotes":69}},{"id":"movie-shipwrecked-nightmare-at-sea-2026","title":"Shipwrecked: Nightmare at Sea","year":2026,"type":"movie","runtimeSeconds":5385,"seasonCount":null,"communityRating":7.181,"criticRating":null,"genres":["Documentary"],"overview":"Never-before-seen footage and survivor accounts trace the 2012 shipwreck of a luxury cruise and the disaster that ensued, in this immersive documentary.","poster":"assets/movie-shipwrecked-nightmare-at-sea-2026-poster.jpg","backdrop":"assets/movie-shipwrecked-nightmare-at-sea-2026-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-20T20:11:43.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":1715492,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":6.5,"imdbVotes":5080,"tmdb":7.172,"tmdbVotes":87}},{"id":"movie-steins-gate-the-movie-load-region-of-deja-vu-2013","title":"Steins;Gate: The Movie - Load Region of D\u00e9j\u00e0 Vu","year":2013,"type":"movie","runtimeSeconds":5403,"seasonCount":null,"communityRating":7.8,"criticRating":null,"genres":["Animation","Mystery","Sci-Fi"],"overview":"After the events of the anime, Rintarou begins to feel the repercussions of extensive time travel, and eventually completely fades from reality. Kurisu, being the only companion to remember him, now must find a way\u2026","poster":"assets/movie-steins-gate-the-movie-load-region-of-deja-vu-2013-poster.jpg","backdrop":"assets/movie-steins-gate-the-movie-load-region-of-deja-vu-2013-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-22T14:55:54.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","artwork":{"posterKind":"poster","backdropKind":"backdrop"}}],"shows":[{"id":"tv-andor-2022","title":"Andor","year":2022,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":8.293,"criticRating":null,"genres":["Sci-Fi & Fantasy","Action & Adventure","Drama"],"overview":"In an era filled with danger, deception and intrigue, Cassian Andor will discover the difference he can make in the struggle against the tyrannical Galactic Empire. He embarks on a path that is destined to turn him\u2026","poster":"assets/tv-andor-2022-poster.jpg","backdrop":"assets/tv-andor-2022-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0432996Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":83867,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":96,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.321,"tmdbVotes":2312}},{"id":"tv-the-boys-2019","title":"The Boys","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":5,"communityRating":8.443,"criticRating":null,"genres":["Sci-Fi & Fantasy","Action & Adventure"],"overview":"A group of vigilantes known informally as \u201cThe Boys\u201d set out to take down corrupt superheroes with no more than blue-collar grit and a willingness to fight dirty.","poster":"assets/tv-the-boys-2019-poster.jpg","backdrop":"assets/tv-the-boys-2019-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0410131Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":76479,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":92,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.4,"tmdbVotes":13628}},{"id":"tv-californication-2007","title":"Californication","year":2007,"type":"tv","runtimeSeconds":1680,"seasonCount":7,"communityRating":7.632,"criticRating":null,"genres":["Comedy","Drama"],"overview":"A self-loathing, alcoholic writer attempts to repair his damaged relationships with his daughter and her mother while combating sex addiction, a budding drug problem, and the seeming inability to avoid making bad\u2026","poster":"assets/tv-californication-2007-poster.jpg","backdrop":"assets/tv-californication-2007-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0428037Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":1215,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":57,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.62,"tmdbVotes":1406}},{"id":"tv-firefly-2002","title":"Firefly","year":2002,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":8.347,"criticRating":null,"genres":["Drama","Action & Adventure","Sci-Fi & Fantasy"],"overview":"In the year 2517, the universe is a vast frontier where lawlessness reigns and adventure awaits! Join Captain Malcolm Reynolds and his ragtag crew aboard the spaceship Serenity as they navigate the fringes of\u2026","poster":"assets/tv-firefly-2002-poster.jpg","backdrop":"assets/tv-firefly-2002-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-20T11:40:08.4202369Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":1437,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":77,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.351,"tmdbVotes":2550}},{"id":"tv-fleabag-2016","title":"Fleabag","year":2016,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":8.278,"criticRating":null,"genres":["Comedy","Drama"],"overview":"A portrait into the mind of a dry-witted, sexual, angry, porn-watching, grief-riddled woman, trying to make sense of the world. As she hurls herself headlong at modern living, Fleabag is thrown roughly up against the\u2026","poster":"assets/tv-fleabag-2016-poster.jpg","backdrop":"assets/tv-fleabag-2016-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T17:42:25.4848214Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":67070,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.3,"tmdbVotes":1993}},{"id":"tv-gravity-falls-2012","title":"Gravity Falls","year":2012,"type":"tv","runtimeSeconds":1320,"seasonCount":2,"communityRating":8.619,"criticRating":null,"genres":["Action & Adventure","Animation","Comedy"],"overview":"Twin brother and sister Dipper and Mabel Pines are in for an unexpected adventure when they spend the summer helping their great uncle Stan run a tourist trap in the mysterious town of Gravity Falls, Oregon.","poster":"assets/tv-gravity-falls-2012-poster.jpg","backdrop":"assets/tv-gravity-falls-2012-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0435827Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":40075,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.624,"tmdbVotes":3647}},{"id":"tv-invincible-2021","title":"INVINCIBLE","year":2021,"type":"tv","runtimeSeconds":null,"seasonCount":4,"communityRating":8.638,"criticRating":null,"genres":["Animation","Drama","Sci-Fi & Fantasy"],"overview":"Mark Grayson is a normal teenager except for the fact that his father is the most powerful superhero on the planet. Shortly after his seventeenth birthday, Mark begins to develop powers of his own and enters into his\u2026","poster":"assets/tv-invincible-2021-poster.jpg","backdrop":"assets/tv-invincible-2021-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.040159Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":95557,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":99,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.6,"tmdbVotes":6155}},{"id":"tv-the-legend-of-korra-2012","title":"The Legend of Korra","year":2012,"type":"tv","runtimeSeconds":1380,"seasonCount":4,"communityRating":8.2,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"Avatar Korra, a headstrong, rebellious, feisty young woman who continually challenges and breaks with tradition, is on her quest to become a fully realized Avatar. In this story, the Avatar struggles to find balance\u2026","poster":"assets/tv-the-legend-of-korra-2012-poster.jpg","backdrop":"assets/tv-the-legend-of-korra-2012-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-20T00:19:23.2494945Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":33880,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":88,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.221,"tmdbVotes":2482}},{"id":"tv-love-death-robots-2019","title":"Love, Death & Robots","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":4,"communityRating":8.205,"criticRating":null,"genres":["Animation","Sci-Fi & Fantasy"],"overview":"Terrifying creatures, wicked surprises and dark comedy converge in this NSFW anthology of animated stories presented by Tim Miller and David Fincher.","poster":"assets/tv-love-death-robots-2019-poster.jpg","backdrop":"assets/tv-love-death-robots-2019-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-20T11:31:20.8818757Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":86831,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":89,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.203,"tmdbVotes":4238}},{"id":"tv-norsemen-2016","title":"Norsemen","year":2016,"type":"tv","runtimeSeconds":1800,"seasonCount":3,"communityRating":7.177,"criticRating":null,"genres":["Comedy","Drama"],"overview":"Norsemen is an epic and humorous drama series set in the Viking Age. The residents of an 8th-century Viking village experience political rivalry, social change and innovations that upend their culture and way of life.","poster":"assets/tv-norsemen-2016-poster.jpg","backdrop":"assets/tv-norsemen-2016-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.034182Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":68126,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.2,"tmdbVotes":233}},{"id":"tv-rick-and-morty-2013","title":"Rick and Morty","year":2013,"type":"tv","runtimeSeconds":null,"seasonCount":9,"communityRating":8.679,"criticRating":null,"genres":["Animation","Comedy","Sci-Fi & Fantasy"],"overview":"Follows a sociopathic genius scientist who drags his inherently timid grandson on adventures across the universe.","poster":"assets/tv-rick-and-morty-2013-poster.jpg","backdrop":"assets/tv-rick-and-morty-2013-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0419581Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":60625,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":91,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.7,"tmdbVotes":11548}},{"id":"tv-secret-level-2024","title":"Secret Level","year":2024,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":7.411,"criticRating":null,"genres":["Animation","Sci-Fi & Fantasy","Action & Adventure"],"overview":"Adult animated series of original short stories which are set within the worlds of beloved video games. Each episode serves as a gateway to a new adventure, unlocking exciting worlds from beloved gaming classics and\u2026","poster":"assets/tv-secret-level-2024-poster.jpg","backdrop":"assets/tv-secret-level-2024-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0336417Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":261579,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":65,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.392,"tmdbVotes":612}},{"id":"tv-silo-2023","title":"Silo","year":2023,"type":"tv","runtimeSeconds":null,"seasonCount":3,"communityRating":8.178,"criticRating":null,"genres":["Sci-Fi & Fantasy","Drama"],"overview":"In a ruined and toxic future, thousands live in a giant silo deep underground. After its sheriff breaks a cardinal rule and residents die mysteriously, engineer Juliette starts to uncover shocking secrets and the\u2026","poster":"assets/tv-silo-2023-poster.jpg","backdrop":"assets/tv-silo-2023-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0346526Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":125988,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":92,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.232,"tmdbVotes":2881}},{"id":"tv-south-park-1997","title":"South Park","year":1997,"type":"tv","runtimeSeconds":null,"seasonCount":29,"communityRating":8.336,"criticRating":null,"genres":["Animation","Comedy"],"overview":"Follow the misadventures of four irreverent grade-schoolers in the quiet, dysfunctional town of South Park, Colorado.","poster":"assets/tv-south-park-1997-poster.jpg","backdrop":"assets/tv-south-park-1997-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0456124Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":2190,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":80,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.332,"tmdbVotes":5250}}],"anime":[{"id":"tv-bleach-2004","title":"Bleach","year":2004,"type":"tv","runtimeSeconds":1440,"seasonCount":17,"communityRating":8.363,"criticRating":null,"genres":["Action & Adventure","Animation","Sci-Fi & Fantasy"],"overview":"For as long as he can remember, Ichigo Kurosaki has been able to see ghosts. But when he meets Rukia, a Soul Reaper who battles evil spirits known as Hollows, he finds his life is changed forever. Now, with a\u2026","poster":"assets/tv-bleach-2004-poster.jpg","backdrop":"assets/tv-bleach-2004-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0359827Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":30984,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.4,"tmdbVotes":2331}},{"id":"tv-chainsaw-man-2022","title":"Chainsaw Man","year":2022,"type":"tv","runtimeSeconds":1440,"seasonCount":1,"communityRating":8.515,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"Denji has a simple dream\u2014to live a happy and peaceful life, spending time with a girl he likes. This is a far cry from reality, however, as Denji is forced by the yakuza into killing devils in order to pay off his\u2026","poster":"assets/tv-chainsaw-man-2022-poster.jpg","backdrop":"assets/tv-chainsaw-man-2022-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-20T22:28:13.2095501Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":114410,"artwork":{"posterKind":"center_crop","backdropKind":"backdrop"},"ratings":{"rtCritics":97,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.508,"tmdbVotes":2364}},{"id":"tv-cyberpunk-edgerunners-2022","title":"Cyberpunk: Edgerunners","year":2022,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":8.466,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"In a dystopia riddled with corruption and cybernetic implants, a talented but reckless street kid strives to become a mercenary outlaw \u2014 an edgerunner.","poster":"assets/tv-cyberpunk-edgerunners-2022-poster.jpg","backdrop":"assets/tv-cyberpunk-edgerunners-2022-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-20T22:28:13.2093107Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":105248,"artwork":{"posterKind":"center_crop","backdropKind":"backdrop"},"ratings":{"rtCritics":89,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.507,"tmdbVotes":2132}},{"id":"tv-dan-da-dan-2024","title":"Dan Da Dan","year":2024,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":8.538,"criticRating":null,"genres":["Animation","Action & Adventure","Comedy"],"overview":"In a bet to prove whether ghosts or aliens exist, two high schoolers face terrifying paranormal threats, gain superpowers and maybe even fall in love?!","poster":"assets/tv-dan-da-dan-2024-poster.jpg","backdrop":"assets/tv-dan-da-dan-2024-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-22T10:31:16.2652252Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":240411,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.517,"tmdbVotes":986}},{"id":"tv-dr-stone-2019","title":"Dr. STONE","year":2019,"type":"tv","runtimeSeconds":1440,"seasonCount":4,"communityRating":8.541,"criticRating":null,"genres":["Animation","Action & Adventure","Comedy"],"overview":"One fateful day, all of humanity was petrified by a blinding flash of light. After several millennia, high schooler Taiju awakens and finds himself lost in a world of statues. However, he\u2019s not alone! His\u2026","poster":"assets/tv-dr-stone-2019-poster.jpg","backdrop":"assets/tv-dr-stone-2019-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-20T22:28:13.2091579Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":86031,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.53,"tmdbVotes":1814}},{"id":"tv-frieren-beyond-journey-s-end-2023","title":"Frieren: Beyond Journey's End","year":2023,"type":"tv","runtimeSeconds":1500,"seasonCount":2,"communityRating":8.803,"criticRating":null,"genres":["Animation","Action & Adventure","Drama"],"overview":"After the party of heroes defeated the Demon King, they restored peace to the land and returned to lives of solitude. Generations pass, and the elven mage Frieren comes face to face with humanity\u2019s mortality. She\u2026","poster":"assets/tv-frieren-beyond-journey-s-end-2023-poster.jpg","backdrop":"assets/tv-frieren-beyond-journey-s-end-2023-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-20T22:28:13.2094435Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":209867,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.826,"tmdbVotes":1016}},{"id":"tv-fullmetal-alchemist-brotherhood-2009","title":"Fullmetal Alchemist: Brotherhood","year":2009,"type":"tv","runtimeSeconds":1500,"seasonCount":1,"communityRating":8.7,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"Disregard for alchemy\u2019s laws ripped half of Edward Elric\u2019s limbs from his body and left his brother Alphonse\u2019s soul clinging to a suit of armor. To restore what was lost, the brothers seek the Philosopher\u2019s Stone.\u2026","poster":"assets/tv-fullmetal-alchemist-brotherhood-2009-poster.jpg","backdrop":"assets/tv-fullmetal-alchemist-brotherhood-2009-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-20T10:27:12.3573939Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":31911,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.7,"tmdbVotes":2633}},{"id":"tv-jujutsu-kaisen-2020","title":"JUJUTSU KAISEN","year":2020,"type":"tv","runtimeSeconds":1440,"seasonCount":3,"communityRating":8.583,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"Yuji Itadori is a boy with tremendous physical strength, though he lives a completely ordinary high school life. One day, to save a classmate who has been attacked by curses, he eats the finger of Ryomen Sukuna,\u2026","poster":"assets/tv-jujutsu-kaisen-2020-poster.jpg","backdrop":"assets/tv-jujutsu-kaisen-2020-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-20T22:28:13.207573Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":95479,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.574,"tmdbVotes":4735}},{"id":"tv-kaiju-no-8-2024","title":"Kaiju No. 8","year":2024,"type":"tv","runtimeSeconds":1440,"seasonCount":2,"communityRating":8.436,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"In a world plagued by creatures known as Kaiju, Kafka Hibino aspired to enlist in The Defense Force. He makes a promise to enlist with his childhood friend, Mina Ashiro. Soon, life takes them in separate ways. While\u2026","poster":"assets/tv-kaiju-no-8-2024-poster.jpg","backdrop":"assets/tv-kaiju-no-8-2024-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-22T10:31:16.2646566Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":207468,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.4,"tmdbVotes":836}},{"id":"tv-my-hero-academia-2016","title":"My Hero Academia","year":2016,"type":"tv","runtimeSeconds":1440,"seasonCount":8,"communityRating":8.607,"criticRating":null,"genres":["Action & Adventure","Animation","Sci-Fi & Fantasy"],"overview":"After he saves a bully from a Villain, a normal student is granted a superpower that allows him to attend a high school training academy for Heroes.","poster":"assets/tv-my-hero-academia-2016-poster.jpg","backdrop":"assets/tv-my-hero-academia-2016-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-20T22:28:13.2089315Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":65930,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.6,"tmdbVotes":5426}},{"id":"tv-neon-genesis-evangelion-1995","title":"Neon Genesis Evangelion","year":1995,"type":"tv","runtimeSeconds":1500,"seasonCount":1,"communityRating":8.568,"criticRating":null,"genres":["Sci-Fi & Fantasy","Animation","Drama"],"overview":"At the turn of the century, the Angels returned to Earth, seeking to wipe out humanity in an apocalyptic fury. Devastated, mankind's last remnants moved underground to wait for the day when the Angels would come back\u2026","poster":"assets/tv-neon-genesis-evangelion-1995-poster.jpg","backdrop":"assets/tv-neon-genesis-evangelion-1995-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0340629Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":890,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.56,"tmdbVotes":2205}},{"id":"tv-record-of-ragnarok-2021","title":"Record of Ragnarok","year":2021,"type":"tv","runtimeSeconds":null,"seasonCount":3,"communityRating":8.402,"criticRating":null,"genres":["Action & Adventure","Animation","Sci-Fi & Fantasy"],"overview":"Before eradicating humankind from the world, the gods give them one last chance to prove themselves worthy of survival. Let the Ragnarok battles begin.","poster":"assets/tv-record-of-ragnarok-2021-poster.jpg","backdrop":"assets/tv-record-of-ragnarok-2021-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-20T22:28:13.2085766Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":114868,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.403,"tmdbVotes":1929}},{"id":"tv-sakamoto-days-2025","title":"SAKAMOTO DAYS","year":2025,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":8.071,"criticRating":null,"genres":["Animation","Comedy","Action & Adventure"],"overview":"Once the greatest hitman of all, Taro Sakamoto retired in the name of love. But when his past catches up, he must fight to protect his beloved family.","poster":"assets/tv-sakamoto-days-2025-poster.jpg","backdrop":"assets/tv-sakamoto-days-2025-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-22T10:31:16.266066Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":207332,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.057,"tmdbVotes":375}},{"id":"tv-sentenced-to-be-a-hero-2025","title":"Sentenced to Be a Hero","year":2025,"type":"tv","runtimeSeconds":1440,"seasonCount":1,"communityRating":8.338,"criticRating":null,"genres":["Animation","Sci-Fi & Fantasy","Action & Adventure"],"overview":"In a world where heroism is a punishment, Xylo Forbartz, a condemned goddess killer, battles endless hordes of monstrous abominations as part of Penal Hero Unit 9004. Death is no escape, only a cycle of resurrection\u2026","poster":"assets/tv-sentenced-to-be-a-hero-2025-poster.jpg","backdrop":"assets/tv-sentenced-to-be-a-hero-2025-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-22T10:31:16.2666791Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":249907,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.244,"tmdbVotes":129}},{"id":"tv-spy-x-family-2022","title":"SPY x FAMILY","year":2022,"type":"tv","runtimeSeconds":1440,"seasonCount":3,"communityRating":8.506,"criticRating":null,"genres":["Animation","Action & Adventure","Comedy"],"overview":"A spy, an assassin and a telepath come together to pose as a family, each for their own reasons, while hiding their true identities from each other.","poster":"assets/tv-spy-x-family-2022-poster.jpg","backdrop":"assets/tv-spy-x-family-2022-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-22T10:31:16.2670364Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":120089,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.5,"tmdbVotes":2382}},{"id":"tv-the-tatami-galaxy-2010","title":"The Tatami Galaxy","year":2010,"type":"tv","runtimeSeconds":1500,"seasonCount":2,"communityRating":8.271,"criticRating":null,"genres":["Animation","Comedy","Drama"],"overview":"When a college dropout stops for a late night bite at a mysterious ramen stand, he crosses paths with a self-proclaimed deity of matrimony. This bizarre meeting sends the young man hurtling through a horrifying\u2026","poster":"assets/tv-the-tatami-galaxy-2010-poster.jpg","backdrop":"assets/tv-the-tatami-galaxy-2010-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-18T05:52:51.0023256Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":36243,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.3,"tmdbVotes":152}},{"id":"tv-vinland-saga-2019","title":"Vinland Saga","year":2019,"type":"tv","runtimeSeconds":1500,"seasonCount":2,"communityRating":8.527,"criticRating":null,"genres":["Animation","War & Politics","Action & Adventure"],"overview":"For a thousand years, the Vikings have made quite a name and reputation for themselves as the strongest families with a thirst for violence. Thorfinn, the son of one of the Vikings' greatest warriors, spends his\u2026","poster":"assets/tv-vinland-saga-2019-poster.jpg","backdrop":"assets/tv-vinland-saga-2019-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-20T22:28:13.207389Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":88803,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.509,"tmdbVotes":1064}},{"id":"tv-yu-yu-hakusho-1992","title":"Yu Yu Hakusho","year":1992,"type":"tv","runtimeSeconds":1440,"seasonCount":4,"communityRating":8.5,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"After dying to save a boy, delinquent tough guy Yusuke Urameshi is granted another chance at life by redeeming himself as a \"Spirit Detective.\"","poster":"assets/tv-yu-yu-hakusho-1992-poster.jpg","backdrop":"assets/tv-yu-yu-hakusho-1992-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-19T21:46:01.5733049Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":30669,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.475,"tmdbVotes":519}}],"discover":[{"id":"movie-the-amazing-spider-man-2012","title":"The Amazing Spider-Man","year":2012,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"A teenage Peter Parker grapples with both high school and amazing super-human crises as his alter-ego Spider-Man.","poster":"assets/movie-the-amazing-spider-man-2012-poster.jpg","backdrop":"assets/movie-the-amazing-spider-man-2012-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1930,"ratings":{"rtCritics":71,"rtCriticsLabel":"Certified Fresh","rtAudience":77,"rtAudienceLabel":"Upright","imdb":7,"imdbVotes":791938,"tmdb":6.768,"tmdbVotes":19312}},{"id":"movie-the-amazing-spider-man-2-2014","title":"The Amazing Spider-Man 2","year":2014,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"For Peter Parker, life is busy. Between taking out the bad guys as Spider-Man and spending time with the person he loves, Gwen Stacy, high school graduation cannot come quickly enough. Peter has not forgotten about\u2026","poster":"assets/movie-the-amazing-spider-man-2-2014-poster.jpg","backdrop":"assets/movie-the-amazing-spider-man-2-2014-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":102382,"ratings":{"rtCritics":51,"rtCriticsLabel":"Rotten","rtAudience":64,"rtAudienceLabel":"Upright","imdb":6.6,"imdbVotes":611981,"tmdb":6.567,"tmdbVotes":14919}},{"id":"movie-the-animatrix-2003","title":"The Animatrix","year":2003,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Science Fiction"],"overview":"Straight from the creators of the groundbreaking Matrix trilogy, this collection of short animated films from the world's leading anime directors fuses computer graphics and Japanese anime to provide the background\u2026","poster":"assets/movie-the-animatrix-2003-poster.jpg","backdrop":"assets/movie-the-animatrix-2003-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":55931,"ratings":{"rtCritics":86,"rtCriticsLabel":"Fresh","rtAudience":78,"rtAudienceLabel":"Upright","imdb":7.3,"imdbVotes":91929,"tmdb":7.221,"tmdbVotes":1872}},{"id":"movie-ant-man-and-the-wasp-quantumania-2023","title":"Ant-Man and the Wasp: Quantumania","year":2023,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"Super-Hero partners Scott Lang and Hope van Dyne, along with with Hope's parents Janet van Dyne and Hank Pym, and Scott's daughter Cassie Lang, find themselves exploring the Quantum Realm, interacting with strange\u2026","poster":"assets/movie-ant-man-and-the-wasp-quantumania-2023-poster.jpg","backdrop":"assets/movie-ant-man-and-the-wasp-quantumania-2023-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":640146,"ratings":{"rtCritics":46,"rtCriticsLabel":"Rotten","rtAudience":81,"rtAudienceLabel":"Upright","imdb":6,"imdbVotes":281738,"tmdb":6.197,"tmdbVotes":6236}},{"id":"movie-appleseed-alpha-2014","title":"Appleseed Alpha","year":2014,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Science Fiction","Action"],"overview":"The Third World War (2099\u20132126) devastated part of the Earth. Former nations are reforming while new powers emerge, and groups of humans struggle to survive in ruined cities. The story follows Deunan Knute and her\u2026","poster":"assets/movie-appleseed-alpha-2014-poster.jpg","backdrop":"assets/movie-appleseed-alpha-2014-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"center_crop","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":269650,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":59,"rtAudienceLabel":"Spilled","imdb":6.5,"imdbVotes":9689,"tmdb":6.808,"tmdbVotes":436}},{"id":"movie-aquaman-and-the-lost-kingdom-2023","title":"Aquaman and the Lost Kingdom","year":2023,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Fantasy"],"overview":"Black Manta seeks revenge on Aquaman for his father's death. Wielding the Black Trident's power, he becomes a formidable foe. To defend Atlantis, Arthur (Aquaman) forges an alliance with his imprisoned brother. They\u2026","poster":"assets/movie-aquaman-and-the-lost-kingdom-2023-poster.jpg","backdrop":"assets/movie-aquaman-and-the-lost-kingdom-2023-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":572802,"ratings":{"rtCritics":33,"rtCriticsLabel":"Rotten","rtAudience":79,"rtAudienceLabel":"Upright","imdb":5.6,"imdbVotes":122422,"tmdb":6.48,"tmdbVotes":3748}},{"id":"movie-the-avengers-2012","title":"The Avengers","year":2012,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Science Fiction","Action","Adventure"],"overview":"When an unexpected enemy emerges and threatens global safety and security, Nick Fury, director of the international peacekeeping agency known as S.H.I.E.L.D., finds himself in need of a team to pull the world back\u2026","poster":"assets/movie-the-avengers-2012-poster.jpg","backdrop":"assets/movie-the-avengers-2012-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":24428,"ratings":{"rtCritics":91,"rtCriticsLabel":"Certified Fresh","rtAudience":91,"rtAudienceLabel":"Upright","imdb":8,"imdbVotes":1590693,"tmdb":8.084,"tmdbVotes":40262}},{"id":"movie-avengers-confidential-black-widow-punisher-2014","title":"Avengers Confidential: Black Widow & Punisher","year":2014,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Science Fiction","Action"],"overview":"When the Punisher takes out a black-market weapons dealer, he stumbles upon a far-reaching terrorist plot devised by a group known as Leviathan.","poster":"assets/movie-avengers-confidential-black-widow-punisher-2014-poster.jpg","backdrop":"assets/movie-avengers-confidential-black-widow-punisher-2014-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":257346,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":55,"rtAudienceLabel":"Spilled","imdb":5.7,"imdbVotes":5166,"tmdb":6.368,"tmdbVotes":303}},{"id":"movie-avengers-age-of-ultron-2015","title":"Avengers: Age of Ultron","year":2015,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"When Tony Stark tries to jumpstart a dormant peacekeeping program, things go awry and Earth\u2019s Mightiest Heroes are put to the ultimate test as the fate of the planet hangs in the balance. As the villainous Ultron\u2026","poster":"assets/movie-avengers-age-of-ultron-2015-poster.jpg","backdrop":"assets/movie-avengers-age-of-ultron-2015-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":99861,"ratings":{"rtCritics":75,"rtCriticsLabel":"Certified Fresh","rtAudience":82,"rtAudienceLabel":"Upright","imdb":7.3,"imdbVotes":1025876,"tmdb":7.278,"tmdbVotes":25289}},{"id":"movie-avengers-infinity-war-2018","title":"Avengers: Infinity War","year":2018,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Adventure","Action","Science Fiction"],"overview":"As the Avengers and their allies have continued to protect the world from threats too large for any one hero to handle, a new danger has emerged from the cosmic shadows: Thanos. A despot of intergalactic infamy, his\u2026","poster":"assets/movie-avengers-infinity-war-2018-poster.jpg","backdrop":"assets/movie-avengers-infinity-war-2018-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":299536,"ratings":{"rtCritics":85,"rtCriticsLabel":"Certified Fresh","rtAudience":92,"rtAudienceLabel":"Upright","imdb":8.4,"imdbVotes":1421954,"tmdb":8.246,"tmdbVotes":33331}},{"id":"movie-batman-ninja-2018","title":"Batman Ninja","year":2018,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Action","Science Fiction"],"overview":"Batman, along with many of his allies and adversaries, finds himself transported to feudal Japan by Gorilla Grodd's time displacement machine.","poster":"assets/movie-batman-ninja-2018-poster.jpg","backdrop":"assets/movie-batman-ninja-2018-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":485942,"ratings":{"rtCritics":84,"rtCriticsLabel":"Fresh","rtAudience":60,"rtAudienceLabel":"Upright","imdb":5.6,"imdbVotes":24579,"tmdb":5.9,"tmdbVotes":1106}},{"id":"movie-batman-v-superman-dawn-of-justice-2016","title":"Batman v Superman: Dawn of Justice","year":2016,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Fantasy"],"overview":"Fearing the actions of a god-like Super Hero left unchecked, Gotham City\u2019s own formidable, forceful vigilante takes on Metropolis\u2019s most revered, modern-day savior, while the world wrestles with what sort of hero it\u2026","poster":"assets/movie-batman-v-superman-dawn-of-justice-2016-poster.jpg","backdrop":"assets/movie-batman-v-superman-dawn-of-justice-2016-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":209112,"ratings":{"rtCritics":28,"rtCriticsLabel":"Rotten","rtAudience":63,"rtAudienceLabel":"Upright","imdb":6.4,"imdbVotes":801382,"tmdb":6.014,"tmdbVotes":19527}},{"id":"movie-batman-the-dark-knight-returns-part-1-2012","title":"Batman: The Dark Knight Returns, Part 1","year":2012,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Science Fiction","Action","Animation"],"overview":"Batman has not been seen for ten years. A new breed of criminal ravages Gotham City, forcing 55-year-old Bruce Wayne back into the cape and cowl. But, does he still have what it takes to fight crime in a new era?","poster":"assets/movie-batman-the-dark-knight-returns-part-1-2012-poster.jpg","backdrop":"assets/movie-batman-the-dark-knight-returns-part-1-2012-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":123025,"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":93,"rtAudienceLabel":"Upright","imdb":7.9,"imdbVotes":68943,"tmdb":7.742,"tmdbVotes":1766}},{"id":"movie-black-adam-2022","title":"Black Adam","year":2022,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"Nearly 5,000 years after he was bestowed with the almighty powers of the Egyptian gods\u2014and imprisoned just as quickly\u2014Black Adam is freed from his earthly tomb, ready to unleash his unique form of justice on the\u2026","poster":"assets/movie-black-adam-2022-poster.jpg","backdrop":"assets/movie-black-adam-2022-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":436270,"ratings":{"rtCritics":39,"rtCriticsLabel":"Rotten","rtAudience":87,"rtAudienceLabel":"Upright","imdb":6.1,"imdbVotes":309624,"tmdb":6.747,"tmdbVotes":7370}},{"id":"movie-black-panther-2018","title":"Black Panther","year":2018,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"King T'Challa returns home to the reclusive, technologically advanced African nation of Wakanda to serve as his country's new leader. However, T'Challa soon finds that he is challenged for the throne by factions\u2026","poster":"assets/movie-black-panther-2018-poster.jpg","backdrop":"assets/movie-black-panther-2018-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":284054,"ratings":{"rtCritics":96,"rtCriticsLabel":"Certified Fresh","rtAudience":null,"rtAudienceLabel":"Spilled","imdb":7.3,"imdbVotes":931120,"tmdb":7.36,"tmdbVotes":24190}},{"id":"movie-black-panther-wakanda-forever-2022","title":"Black Panther: Wakanda Forever","year":2022,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"Queen Ramonda, Shuri, M\u2019Baku, Okoye and the Dora Milaje fight to protect their nation from intervening world powers in the wake of King T\u2019Challa\u2019s death. As the Wakandans strive to embrace their next chapter, the\u2026","poster":"assets/movie-black-panther-wakanda-forever-2022-poster.jpg","backdrop":"assets/movie-black-panther-wakanda-forever-2022-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":505642,"ratings":{"rtCritics":84,"rtCriticsLabel":"Certified Fresh","rtAudience":93,"rtAudienceLabel":"Upright","imdb":6.6,"imdbVotes":405088,"tmdb":6.984,"tmdbVotes":7920}},{"id":"movie-blame-2017","title":"BLAME!","year":2017,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Drama","Science Fiction"],"overview":"In the distant technological future, civilization has reached its ultimate Net-based form. An \"infection\" in the past caused the automated systems to spiral out of order, resulting in a multi-leveled city structure\u2026","poster":"assets/movie-blame-2017-poster.jpg","backdrop":"assets/movie-blame-2017-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":409421,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":61,"rtAudienceLabel":"Upright","imdb":6.6,"imdbVotes":10258,"tmdb":6.523,"tmdbVotes":370}},{"id":"movie-bleach-the-movie-fade-to-black-2008","title":"Bleach the Movie: Fade to Black","year":2008,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Animation","Fantasy"],"overview":"A strange disturbance in the World of the Living sends Ichigo and Kon to the Soul Society, where the Seireitei has been devastated by an explosion of reishi and Rukia is missing. Stranger still, none of the Soul\u2026","poster":"assets/movie-bleach-the-movie-fade-to-black-2008-poster.jpg","backdrop":"assets/movie-bleach-the-movie-fade-to-black-2008-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":17165,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":67,"rtAudienceLabel":"Upright","imdb":7.1,"imdbVotes":3693,"tmdb":7.1,"tmdbVotes":206}},{"id":"tv-90-day-fiance-before-the-90-days-2017","title":"90 Day Fianc\u00e9: Before the 90 Days","year":2017,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Reality"],"overview":"Follow couples who have an existing relationship online, but haven't met in person. We'll experience their journey as they travel to the other's foreign country for the first time in an attempt to establish an\u2026","poster":"assets/tv-90-day-fiance-before-the-90-days-2017-poster.jpg","backdrop":"assets/tv-90-day-fiance-before-the-90-days-2017-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":73319,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.5,"tmdbVotes":45}},{"id":"tv-90-day-fiance-the-other-way-2019","title":"90 Day Fianc\u00e9: The Other Way","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Reality"],"overview":"Americans move to a foreign country all in the name of love. Will uprooting their lives in the United States pay off, or will they be packing up and moving back to America brokenhearted?","poster":"assets/tv-90-day-fiance-the-other-way-2019-poster.jpg","backdrop":"assets/tv-90-day-fiance-the-other-way-2019-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":90046,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.8,"tmdbVotes":34}},{"id":"tv-the-100-2014","title":"The 100","year":2014,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Sci-Fi & Fantasy","Action & Adventure","Drama"],"overview":"100 years in the future, when the Earth has been abandoned due to radioactivity, the last surviving humans live on an ark orbiting the planet \u2014 but the ark won't last forever. So the repressive regime picks 100\u2026","poster":"assets/tv-the-100-2014-poster.jpg","backdrop":"assets/tv-the-100-2014-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":48866,"ratings":{"rtCritics":93,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.878,"tmdbVotes":8855}},{"id":"tv-the-abbott-and-costello-show-1952","title":"The Abbott and Costello Show","year":1952,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy"],"overview":"Bud and Lou are unemployed actors living in Mr. Fields\u2019 boarding house. Lou\u2019s girlfriend Hillary lives across the hall. Many situations arise leading to slapstick and puns.","poster":"assets/tv-the-abbott-and-costello-show-1952-poster.jpg","backdrop":"assets/tv-the-abbott-and-costello-show-1952-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":11821,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.2,"tmdbVotes":22}},{"id":"tv-accel-world-2012","title":"Accel World","year":2012,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Action & Adventure","Drama"],"overview":"A short, overweight student uses the Neuro Link, an evolution of the Nerve Gear, to escape himself from the reality. But his skills in the virtual world brings him to the attention of Kuroyukihime, a popular student\u2026","poster":"assets/tv-accel-world-2012-poster.jpg","backdrop":"assets/tv-accel-world-2012-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"center_crop","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":43167,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.429,"tmdbVotes":163}},{"id":"tv-ahsoka-2023","title":"Ahsoka","year":2023,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Sci-Fi & Fantasy","Action & Adventure","Drama"],"overview":"Former Jedi Knight Ahsoka Tano investigates an emerging threat to a vulnerable galaxy.","poster":"assets/tv-ahsoka-2023-poster.jpg","backdrop":"assets/tv-ahsoka-2023-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":114461,"ratings":{"rtCritics":85,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.4,"tmdbVotes":1351}},{"id":"tv-american-dad-2005","title":"American Dad!","year":2005,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Comedy"],"overview":"The series focuses on an eccentric motley crew that is the Smith family and their three housemates: Father, husband, and breadwinner Stan Smith; his better half housewife, Francine Smith; their college-aged daughter,\u2026","poster":"assets/tv-american-dad-2005-poster.jpg","backdrop":"assets/tv-american-dad-2005-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1433,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.022,"tmdbVotes":2481}},{"id":"tv-american-gods-2017","title":"American Gods","year":2017,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Mystery","Sci-Fi & Fantasy"],"overview":"An ex-con becomes the traveling partner of a conman who turns out to be one of the older gods trying to recruit troops to battle the upstart deities. Based on Neil Gaiman's fantasy novel.","poster":"assets/tv-american-gods-2017-poster.jpg","backdrop":"assets/tv-american-gods-2017-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":46639,"ratings":{"rtCritics":75,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.1,"tmdbVotes":1852}},{"id":"tv-andromeda-2000","title":"Andromeda","year":2000,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action & Adventure","Drama","Sci-Fi & Fantasy"],"overview":"Captain Dylan Hunt and his crew quest to restore a government that once presided over an extended peace and prosperity.","poster":"assets/tv-andromeda-2000-poster.jpg","backdrop":"assets/tv-andromeda-2000-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":2985,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.068,"tmdbVotes":315}},{"id":"tv-aqua-teen-hunger-force-2000","title":"Aqua Teen Hunger Force","year":2000,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Comedy"],"overview":"The surreal adventures of three anthropomorphic fast food items: Master Shake, Frylock and Meatwad, and their human nextdoor neighbor, Carl Brutananadilewski.","poster":"assets/tv-aqua-teen-hunger-force-2000-poster.jpg","backdrop":"assets/tv-aqua-teen-hunger-force-2000-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":251,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.5,"tmdbVotes":272}},{"id":"tv-arifureta-from-commonplace-to-world-s-strongest-2019","title":"Arifureta: From Commonplace to World's Strongest","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"Hajime Nagumo and his high school class are suddenly summoned to a fantastical land as heroes. But while most of his classmates have powerful stats and abilities, Hajime does not. Underappreciated and unprepared, he\u2026","poster":"assets/tv-arifureta-from-commonplace-to-world-s-strongest-2019-poster.jpg","backdrop":"assets/tv-arifureta-from-commonplace-to-world-s-strongest-2019-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":86034,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.382,"tmdbVotes":662}},{"id":"tv-arrow-2012","title":"Arrow","year":2012,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Crime","Drama","Action & Adventure"],"overview":"Spoiled billionaire playboy Oliver Queen is missing and presumed dead when his yacht is lost at sea. He returns five years later a changed man, determined to clean up the city as a hooded vigilante armed with a bow.","poster":"assets/tv-arrow-2012-poster.jpg","backdrop":"assets/tv-arrow-2012-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1412,"ratings":{"rtCritics":86,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.834,"tmdbVotes":6537}},{"id":"tv-avatar-the-last-airbender-2024","title":"Avatar: The Last Airbender","year":2024,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action & Adventure","Sci-Fi & Fantasy","Drama"],"overview":"A young boy known as the Avatar must master the four elemental powers to save a world at war \u2014 and fight a ruthless enemy bent on stopping him.","poster":"assets/tv-avatar-the-last-airbender-2024-poster.jpg","backdrop":"assets/tv-avatar-the-last-airbender-2024-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":82452,"ratings":{"rtCritics":66,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.8,"tmdbVotes":1406}},{"id":"tv-avatar-seven-havens-2026","title":"Avatar: Seven Havens","year":2026,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"In a world shattered by a devastating cataclysm, a young Earthbender discovers she's the new Avatar after Korra. But in this dangerous era, that title marks her as humanity's destroyer, not its savior. Hunted by both\u2026","poster":"assets/tv-avatar-seven-havens-2026-poster.jpg","backdrop":"assets/tv-avatar-seven-havens-2026-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":284833,"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.9,"tmdbVotes":183}},{"id":"tv-batman-the-brave-and-the-bold-2008","title":"Batman: The Brave and the Bold","year":2008,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"The Caped Crusader is teamed up with Blue Beetle, Green Arrow, Aquaman and countless others in his quest to uphold justice.","poster":"assets/tv-batman-the-brave-and-the-bold-2008-poster.jpg","backdrop":"assets/tv-batman-the-brave-and-the-bold-2008-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":15804,"ratings":{"rtCritics":96,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.6,"tmdbVotes":295}},{"id":"tv-batwoman-2019","title":"Batwoman","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Sci-Fi & Fantasy","Action & Adventure"],"overview":"Kate Kane, armed with a passion for social justice and a flair for speaking her mind, soars onto the streets of Gotham as Batwoman, an out lesbian and highly trained street fighter primed to snuff out the failing\u2026","poster":"assets/tv-batwoman-2019-poster.jpg","backdrop":"assets/tv-batwoman-2019-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":89247,"ratings":{"rtCritics":83,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.8,"tmdbVotes":1619}},{"id":"tv-big-mouth-2017","title":"Big Mouth","year":2017,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy","Animation"],"overview":"Teenage friends find their lives upended by the wonders and horrors of puberty in this edgy comedy from real-life pals Nick Kroll and Andrew Goldberg.","poster":"assets/tv-big-mouth-2017-poster.jpg","backdrop":"assets/tv-big-mouth-2017-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":74204,"ratings":{"rtCritics":95,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.591,"tmdbVotes":1274}},{"id":"tv-black-lightning-2018","title":"Black Lightning","year":2018,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action & Adventure","Sci-Fi & Fantasy","Drama"],"overview":"Jefferson Pierce is a man wrestling with a secret. As the father of two daughters and principal of a charter high school that also serves as a safe haven for young people in a New Orleans neighborhood overrun by gang\u2026","poster":"assets/tv-black-lightning-2018-poster.jpg","backdrop":"assets/tv-black-lightning-2018-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":71663,"ratings":{"rtCritics":92,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.907,"tmdbVotes":991}}]},{"key":"mindel","movies":[{"id":"movie-chicago-2002","title":"Chicago","year":2002,"type":"movie","runtimeSeconds":6808,"seasonCount":null,"communityRating":7.131,"criticRating":87,"genres":["Comedy","Crime","Drama"],"overview":"Murderesses Velma Kelly and Roxie Hart find themselves on death row together and fight for the fame that will keep them from the gallows in 1920s Chicago.","poster":"assets/movie-chicago-2002-poster.jpg","backdrop":"assets/movie-chicago-2002-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:24:53.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":1574,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":87,"rtCriticsLabel":"Certified Fresh","rtAudience":83,"rtAudienceLabel":"Upright","imdb":7.2,"imdbVotes":259272,"tmdb":7.135,"tmdbVotes":3025}},{"id":"movie-coherence-2014","title":"Coherence","year":2014,"type":"movie","runtimeSeconds":5286,"seasonCount":null,"communityRating":7.21,"criticRating":89,"genres":["Thriller","Science Fiction"],"overview":"Four couples gather for dinner the night a mysterious and powerful comet passes overhead.","poster":"assets/movie-coherence-2014-poster.jpg","backdrop":"assets/movie-coherence-2014-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2017-08-12T23:49:00.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":220289,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":89,"rtCriticsLabel":"Certified Fresh","rtAudience":81,"rtAudienceLabel":"Upright","imdb":7.1,"imdbVotes":180354,"tmdb":7.208,"tmdbVotes":3702}},{"id":"movie-the-killing-of-a-sacred-deer-2017","title":"The Killing of a Sacred Deer","year":2017,"type":"movie","runtimeSeconds":7262,"seasonCount":null,"communityRating":7.003,"criticRating":79,"genres":["Drama","Thriller","Mystery"],"overview":"Dr. Steven Murphy is a renowned cardiovascular surgeon who presides over a spotless household with his wife and two children. Lurking at the margins of his idyllic suburban existence is Martin, a fatherless teen who\u2026","poster":"assets/movie-the-killing-of-a-sacred-deer-2017-poster.jpg","backdrop":"assets/movie-the-killing-of-a-sacred-deer-2017-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-22T21:49:26.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":399057,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":79,"rtCriticsLabel":"Certified Fresh","rtAudience":63,"rtAudienceLabel":"Upright","imdb":7,"imdbVotes":219488,"tmdb":7.001,"tmdbVotes":4640}},{"id":"movie-night-is-short-walk-on-girl-2017","title":"Night Is Short, Walk On Girl","year":2017,"type":"movie","runtimeSeconds":5548,"seasonCount":null,"communityRating":7.421,"criticRating":90,"genres":["Comedy","Romance","Animation"],"overview":"As a group of university students go out for a night on the town, a sophomore known only as \"The Girl with Black Hair\" experiences a series of surreal encounters with the local nightlife \u2013 all the while unaware of\u2026","poster":"assets/movie-night-is-short-walk-on-girl-2017-poster.jpg","backdrop":"assets/movie-night-is-short-walk-on-girl-2017-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T17:39:14.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":430214,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":90,"rtCriticsLabel":"Fresh","rtAudience":84,"rtAudienceLabel":"Upright","imdb":7.5,"imdbVotes":7640,"tmdb":7.4,"tmdbVotes":267}},{"id":"movie-thelma-louise-1991","title":"Thelma & Louise","year":1991,"type":"movie","runtimeSeconds":7786,"seasonCount":null,"communityRating":7.596,"criticRating":87,"genres":["Drama","Crime","Adventure"],"overview":"Taking a break from their dreary lives, close friends Thelma and Louise embark on a short weekend trip that ends in unforeseen incriminating circumstances. As fugitives, both women rediscover the strength of their\u2026","poster":"assets/movie-thelma-louise-1991-poster.jpg","backdrop":"assets/movie-thelma-louise-1991-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:24:40.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":1541,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":87,"rtCriticsLabel":"Certified Fresh","rtAudience":82,"rtAudienceLabel":"Upright","imdb":7.6,"imdbVotes":197947,"tmdb":7.594,"tmdbVotes":4063}},{"id":"movie-vicky-cristina-barcelona-2008","title":"Vicky Cristina Barcelona","year":2008,"type":"movie","runtimeSeconds":5804,"seasonCount":null,"communityRating":6.798,"criticRating":80,"genres":["Drama","Romance"],"overview":"Two girlfriends on a summer holiday in Spain become enamored with the same painter, unaware that his ex-wife, with whom he has a tempestuous relationship, is about to re-enter the picture.","poster":"assets/movie-vicky-cristina-barcelona-2008-poster.jpg","backdrop":"assets/movie-vicky-cristina-barcelona-2008-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:25:34.0000000Z","lastPlayedAt":"2026-08-11T20:12:57.3064089Z","availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":5038,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":80,"rtCriticsLabel":"Certified Fresh","rtAudience":74,"rtAudienceLabel":"Upright","imdb":7.1,"imdbVotes":283286,"tmdb":6.797,"tmdbVotes":4164}}],"shows":[{"id":"tv-all-creatures-great-small-2020","title":"All Creatures Great & Small","year":2020,"type":"tv","runtimeSeconds":3000,"seasonCount":7,"communityRating":8.2,"criticRating":null,"genres":["Drama","Comedy"],"overview":"The heartwarming and humorous adventures of a young country vet in the Yorkshire Dales in the 1930s. A remake of the 1978 series.","poster":"assets/tv-all-creatures-great-small-2020-poster.jpg","backdrop":"assets/tv-all-creatures-great-small-2020-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-11-04T20:13:03.4266156Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":108255,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":99,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.2,"tmdbVotes":168}},{"id":"tv-back-to-life-2019","title":"Back to Life","year":2019,"type":"tv","runtimeSeconds":1500,"seasonCount":2,"communityRating":7.367,"criticRating":null,"genres":["Comedy","Drama"],"overview":"When Miri Matteson returns home after eighteen years, can she integrate back into her old life? With a terrible event from her past hanging over her, it won\u2019t be easy.","poster":"assets/tv-back-to-life-2019-poster.jpg","backdrop":"assets/tv-back-to-life-2019-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0688758Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":88510,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.4,"tmdbVotes":65}},{"id":"tv-big-boys-2022","title":"Big Boys","year":2022,"type":"tv","runtimeSeconds":1440,"seasonCount":3,"communityRating":7.6,"criticRating":null,"genres":["Comedy","Drama"],"overview":"Two boys from very different ends of the 'spectrum of masculinity' become best friends at Brent University freshers' week; in their first year of uni, they explore, experiment and try to discover themselves, helping\u2026","poster":"assets/tv-big-boys-2022-poster.jpg","backdrop":"assets/tv-big-boys-2022-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-11-04T20:25:58.2156837Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":202851,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.6,"tmdbVotes":49}},{"id":"tv-call-the-midwife-2012","title":"Call the Midwife","year":2012,"type":"tv","runtimeSeconds":3120,"seasonCount":15,"communityRating":7.5,"criticRating":null,"genres":["Drama"],"overview":"Drama following the lives of a group of midwives working in the poverty-stricken East End of London during the 1950s, based on the best-selling memoirs of Jennifer Worth.","poster":"assets/tv-call-the-midwife-2012-poster.jpg","backdrop":"assets/tv-call-the-midwife-2012-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0377216Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":39793,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.577,"tmdbVotes":267}},{"id":"tv-derry-girls-2018","title":"Derry Girls","year":2018,"type":"tv","runtimeSeconds":1380,"seasonCount":3,"communityRating":8.144,"criticRating":null,"genres":["Comedy","Drama"],"overview":"Amidst the political conflict of Northern Ireland in the 1990s, five secondary school students square off with the universal challenges of being a teenager.","poster":"assets/tv-derry-girls-2018-poster.jpg","backdrop":"assets/tv-derry-girls-2018-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-02T20:01:55.8955537Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":76148,"artwork":{"posterKind":"center_crop","backdropKind":"backdrop"},"ratings":{"rtCritics":99,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.138,"tmdbVotes":454}},{"id":"tv-desperate-housewives-2004","title":"Desperate Housewives","year":2004,"type":"tv","runtimeSeconds":2520,"seasonCount":8,"communityRating":7.896,"criticRating":null,"genres":["Mystery","Drama","Comedy"],"overview":"Looking down on her friends and family isn't a way of life for Mary Alice Young... it's a way of death. One day, in her perfect house, in the loveliest of suburbs, Mary Alice ended it all. Now she's taking us into\u2026","poster":"assets/tv-desperate-housewives-2004-poster.jpg","backdrop":"assets/tv-desperate-housewives-2004-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-29T20:56:40.3505596Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":693,"artwork":{"posterKind":"poster","backdropKind":"center_crop"},"ratings":{"rtCritics":72,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.896,"tmdbVotes":2171}},{"id":"tv-the-diplomat-2023","title":"The Diplomat","year":2023,"type":"tv","runtimeSeconds":null,"seasonCount":4,"communityRating":7.569,"criticRating":null,"genres":["Drama","War & Politics"],"overview":"Amid an international crisis, a US diplomat contends with her high-profile job as ambassador to the UK and her strained marriage to a political star.","poster":"assets/tv-the-diplomat-2023-poster.jpg","backdrop":"assets/tv-the-diplomat-2023-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0640348Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":203857,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":93,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.652,"tmdbVotes":521}},{"id":"tv-the-durrells-2016","title":"The Durrells","year":2016,"type":"tv","runtimeSeconds":2760,"seasonCount":4,"communityRating":7.402,"criticRating":null,"genres":["Drama","Comedy","Family"],"overview":"In 1935, financially strapped widow Louisa Durrell, whose life has fallen apart, decides to move from England, with her four children (three sons, one daughter), to the island of Corfu, Greece. Once there, the family\u2026","poster":"assets/tv-the-durrells-2016-poster.jpg","backdrop":"assets/tv-the-durrells-2016-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0619436Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":66134,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":94,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.4,"tmdbVotes":127}},{"id":"tv-etoile-2025","title":"\u00c9toile","year":2025,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":7.197,"criticRating":null,"genres":["Comedy","Drama"],"overview":"In an ambitious gambit to save their storied institutions, two world-renowned ballet companies in New York City and Paris swap their most talented stars.","poster":"assets/tv-etoile-2025-poster.jpg","backdrop":"assets/tv-etoile-2025-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0601383Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":225383,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":86,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.3,"tmdbVotes":40}},{"id":"tv-gilmore-girls-2000","title":"Gilmore Girls","year":2000,"type":"tv","runtimeSeconds":2640,"seasonCount":7,"communityRating":7.893,"criticRating":null,"genres":["Comedy","Drama"],"overview":"Set in the charming town of Stars Hollow, Connecticut, the series follows the captivating lives of Lorelai and Rory Gilmore, a mother/daughter pair who have a relationship most people only dream of.","poster":"assets/tv-gilmore-girls-2000-poster.jpg","backdrop":"assets/tv-gilmore-girls-2000-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0631035Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":4586,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.9,"tmdbVotes":1339}},{"id":"tv-ginny-georgia-2021","title":"Ginny & Georgia","year":2021,"type":"tv","runtimeSeconds":null,"seasonCount":3,"communityRating":8.026,"criticRating":null,"genres":["Comedy","Drama"],"overview":"Free-spirited Georgia and her two kids, Ginny and Austin, move north in search of a fresh start but find that the road to new beginnings can be bumpy.","poster":"assets/tv-ginny-georgia-2021-poster.jpg","backdrop":"assets/tv-ginny-georgia-2021-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0694828Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":117581,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":68,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8,"tmdbVotes":1840}},{"id":"tv-hellcats-2010","title":"Hellcats","year":2010,"type":"tv","runtimeSeconds":2460,"seasonCount":1,"communityRating":7.5,"criticRating":null,"genres":["Drama"],"overview":"Pre-law student Marti Perkins' world is flipped upside down when she loses her scholarship, and realizes the only way she can stay in school is by reigniting her dormant teen gymnastic skills to win a place on Lancer\u2026","poster":"assets/tv-hellcats-2010-poster.jpg","backdrop":"assets/tv-hellcats-2010-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-22T20:39:02.7719318Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":32504,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":65,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.5,"tmdbVotes":116}},{"id":"tv-high-potential-2024","title":"High Potential","year":2024,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":8.201,"criticRating":null,"genres":["Drama","Crime","Mystery"],"overview":"Morgan is a single mom with an exceptional mind, whose unconventional knack for solving crimes leads to an unusual and unstoppable partnership with a by-the-book seasoned detective.","poster":"assets/tv-high-potential-2024-poster.jpg","backdrop":"assets/tv-high-potential-2024-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0686091Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":226637,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":98,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.3,"tmdbVotes":707}},{"id":"tv-how-to-get-to-heaven-from-belfast-2026","title":"How to Get to Heaven from Belfast","year":2026,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":7.027,"criticRating":null,"genres":["Mystery","Comedy","Drama"],"overview":"Three lifelong pals embark on a chaotic quest to solve the mystery of their old friend's suspicious death and keep their own dark secret under wraps.","poster":"assets/tv-how-to-get-to-heaven-from-belfast-2026-poster.jpg","backdrop":"assets/tv-how-to-get-to-heaven-from-belfast-2026-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0683192Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":233079,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":95,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.063,"tmdbVotes":95}},{"id":"tv-the-hunting-wives-2025","title":"The Hunting Wives","year":2025,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":6.932,"criticRating":null,"genres":["Drama","Mystery"],"overview":"Sophie trades New England for East Texas and falls into a wealthy socialite's magnetic orbit \u2014 where a clique of housewives hide deadly secrets.","poster":"assets/tv-the-hunting-wives-2025-poster.jpg","backdrop":"assets/tv-the-hunting-wives-2025-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-20T19:42:46.3227892Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":244447,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":81,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.964,"tmdbVotes":112}},{"id":"tv-the-lost-flowers-of-alice-hart-2023","title":"The Lost Flowers of Alice Hart","year":2023,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":7.634,"criticRating":null,"genres":["Drama","Mystery"],"overview":"After losing her parents in a mysterious fire, nine-year-old Alice Hart is raised by her grandmother June on a flower farm where she learns there are secrets within secrets. But years on, an unearthed betrayal sees\u2026","poster":"assets/tv-the-lost-flowers-of-alice-hart-2023-poster.jpg","backdrop":"assets/tv-the-lost-flowers-of-alice-hart-2023-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0607236Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":125816,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":82,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.64,"tmdbVotes":161}},{"id":"tv-love-is-blind-2020","title":"Love Is Blind","year":2020,"type":"tv","runtimeSeconds":null,"seasonCount":11,"communityRating":6.261,"criticRating":null,"genres":["Reality"],"overview":"Nick and Vanessa Lachey host this social experiment where single men and women look for love and get engaged, all before meeting in person.","poster":"assets/tv-love-is-blind-2020-poster.jpg","backdrop":"assets/tv-love-is-blind-2020-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-22T17:11:08.2447226Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":99353,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":66,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.233,"tmdbVotes":118}},{"id":"tv-maximum-pleasure-guaranteed-2026","title":"Maximum Pleasure Guaranteed","year":2026,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":6.676,"criticRating":null,"genres":["Comedy"],"overview":"A newly divorced mom falls down a dangerous rabbit hole of blackmail, murder, and youth soccer.","poster":"assets/tv-maximum-pleasure-guaranteed-2026-poster.jpg","backdrop":"assets/tv-maximum-pleasure-guaranteed-2026-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-07T21:04:02.8277793Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":285404,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":93,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.799,"tmdbVotes":92}},{"id":"tv-minx-2022","title":"Minx","year":2022,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":6.833,"criticRating":null,"genres":["Comedy","Drama"],"overview":"An earnest young feminist joins forces with a low-rent publisher to make the world's first erotic magazine for women.","poster":"assets/tv-minx-2022-poster.jpg","backdrop":"assets/tv-minx-2022-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0653613Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":118303,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":93,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.9,"tmdbVotes":123}},{"id":"tv-offspring-2010","title":"Offspring","year":2010,"type":"tv","runtimeSeconds":3600,"seasonCount":7,"communityRating":6.9,"criticRating":null,"genres":["Drama"],"overview":"An exuberant drama set in Melbourne's Fitzroy, centering on Nina Proudman and her struggle to deal with her fabulously messy family, her hunt for a decent love life and her tendency to overthink and fly off into fantasy.","poster":"assets/tv-offspring-2010-poster.jpg","backdrop":"assets/tv-offspring-2010-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0664581Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":33155,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.9,"tmdbVotes":27}},{"id":"tv-only-murders-in-the-building-2021","title":"Only Murders in the Building","year":2021,"type":"tv","runtimeSeconds":null,"seasonCount":5,"communityRating":8.398,"criticRating":null,"genres":["Comedy","Mystery","Crime"],"overview":"Three strangers share an obsession with true crime and suddenly find themselves wrapped up in one.","poster":"assets/tv-only-murders-in-the-building-2021-poster.jpg","backdrop":"assets/tv-only-murders-in-the-building-2021-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-11-04T20:25:58.2163301Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":107113,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":95,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.398,"tmdbVotes":2333}},{"id":"tv-outlander-blood-of-my-blood-2025","title":"Outlander: Blood of My Blood","year":2025,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":8.542,"criticRating":null,"genres":["Drama"],"overview":"From the battlefields of World War I to the rugged Highlands of 18th century Scotland, two fated couples must defy the forces that seek to tear them apart, unfolding in surprising and unforeseen ways in this romantic\u2026","poster":"assets/tv-outlander-blood-of-my-blood-2025-poster.jpg","backdrop":"assets/tv-outlander-blood-of-my-blood-2025-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0691373Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":207484,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":94,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.738,"tmdbVotes":124}},{"id":"tv-rivals-2024","title":"Rivals","year":2024,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":7.44,"criticRating":null,"genres":["Drama"],"overview":"It is 1986 and Britain is booming. \"Rivals\" dives headfirst into the cutthroat world of TV where hair-dos are big and ambitions are even bigger. Deals are brokered in boardrooms, as well as bedrooms. Nobody can be\u2026","poster":"assets/tv-rivals-2024-poster.jpg","backdrop":"assets/tv-rivals-2024-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0645815Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":208921,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":96,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.4,"tmdbVotes":93}},{"id":"tv-rooster-2026","title":"Rooster","year":2026,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":7.431,"criticRating":null,"genres":["Comedy"],"overview":"On a college campus, an author navigates a complicated relationship with his daughter.","poster":"assets/tv-rooster-2026-poster.jpg","backdrop":"assets/tv-rooster-2026-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.063389Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":254953,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":88,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.423,"tmdbVotes":144}},{"id":"tv-sex-and-the-city-1998","title":"Sex and the City","year":1998,"type":"tv","runtimeSeconds":null,"seasonCount":6,"communityRating":7.365,"criticRating":null,"genres":["Drama","Comedy"],"overview":"Based on the bestselling book by Candace Bushnell, Sex and the City tells the story of four best friends, all single and in their late thirties, as they pursue their careers and talk about their sex lives, all while\u2026","poster":"assets/tv-sex-and-the-city-1998-poster.jpg","backdrop":"assets/tv-sex-and-the-city-1998-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0679324Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":105,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":70,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.351,"tmdbVotes":2220}},{"id":"tv-skymed-2022","title":"SkyMed","year":2022,"type":"tv","runtimeSeconds":2640,"seasonCount":4,"communityRating":6.665,"criticRating":null,"genres":["Drama"],"overview":"Life, death and drama at 20,000 feet. The series weaves together intense character journeys and high-stakes medical rescues, as we follow the triumphs, heartbreaks and tribulations of budding nurses and pilots flying\u2026","poster":"assets/tv-skymed-2022-poster.jpg","backdrop":"assets/tv-skymed-2022-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-22T19:44:29.2431354Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":133908,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.699,"tmdbVotes":98}},{"id":"tv-so-you-think-you-can-dance-2008","title":"So You Think You Can Dance","year":2008,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":9.8,"criticRating":null,"genres":["Family","Reality"],"overview":"So You Think You Can Dance is a joint Belgian-Dutch dance competition show broadcast on RTL 5 and vtm television stations. The first season was broadcast only in the Netherlands, whereas starting with season 2, the\u2026","poster":"assets/tv-so-you-think-you-can-dance-2008-poster.jpg","backdrop":"assets/tv-so-you-think-you-can-dance-2008-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-23T11:11:35.4124418Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":40231,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":9.8,"tmdbVotes":4}},{"id":"tv-the-white-lotus-2021","title":"The White Lotus","year":2021,"type":"tv","runtimeSeconds":null,"seasonCount":3,"communityRating":7.597,"criticRating":null,"genres":["Comedy","Drama","Mystery"],"overview":"Follow the exploits of various guests and employees at an exclusive tropical resort over the span of a week as with each passing day, a darker complexity emerges in these picture-perfect travelers, the hotel\u2019s\u2026","poster":"assets/tv-the-white-lotus-2021-poster.jpg","backdrop":"assets/tv-the-white-lotus-2021-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-20T02:45:52.8742674Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":111803,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":90,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.599,"tmdbVotes":1604}},{"id":"tv-yellowjackets-2021","title":"Yellowjackets","year":2021,"type":"tv","runtimeSeconds":null,"seasonCount":3,"communityRating":7.431,"criticRating":null,"genres":["Drama","Mystery"],"overview":"This equal parts survival epic, psychological horror story and coming-of-age drama tells the saga of a team of wildly talented high school girls soccer players who become the (un)lucky survivors of a plane crash deep\u2026","poster":"assets/tv-yellowjackets-2021-poster.jpg","backdrop":"assets/tv-yellowjackets-2021-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-11-04T20:31:47.4592756Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":117488,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":92,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.431,"tmdbVotes":1070}}],"anime":[],"discover":[{"id":"movie-across-the-hall-2009","title":"Across the Hall","year":2009,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Thriller","Mystery"],"overview":"Convinced that his fiancee is cheating on him, a man follows her to a hotel and calls his best friend to help him avoid a calamity.","poster":"assets/movie-across-the-hall-2009-poster.jpg","backdrop":"assets/movie-across-the-hall-2009-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":21469,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":39,"rtAudienceLabel":"Spilled","imdb":5.8,"imdbVotes":5130,"tmdb":6,"tmdbVotes":129}},{"id":"movie-addicted-2014","title":"Addicted","year":2014,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Thriller"],"overview":"A gallerist risks her family and flourishing career when she enters into an affair with a talented painter and slowly loses control of her life.","poster":"assets/movie-addicted-2014-poster.jpg","backdrop":"assets/movie-addicted-2014-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":235271,"ratings":{"rtCritics":7,"rtCriticsLabel":"Rotten","rtAudience":51,"rtAudienceLabel":"Spilled","imdb":5,"imdbVotes":13131,"tmdb":5.928,"tmdbVotes":466}},{"id":"movie-adulterers-2016","title":"Adulterers","year":2016,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Thriller","Drama"],"overview":"On a steamy New Orleans afternoon, Sam Deuprey decides to surprise his beautiful wife, Ashley, for their anniversary and comes home early. But Ashley is not alone in the bedroom. She and her lover, Damien are about\u2026","poster":"assets/movie-adulterers-2016-poster.jpg","backdrop":"assets/movie-adulterers-2016-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":376004,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":37,"rtAudienceLabel":"Spilled","imdb":5.1,"imdbVotes":2144,"tmdb":6.2,"tmdbVotes":116}},{"id":"movie-alone-with-her-2006","title":"Alone With Her","year":2006,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Crime","Drama","Thriller"],"overview":"The harrowing story of a disturbed young man's attempts to win the affections of an unsuspecting young woman. When Doug first sees Amy, he instantly falls for her and begins to watch her every move, going so far as\u2026","poster":"assets/movie-alone-with-her-2006-poster.jpg","backdrop":"assets/movie-alone-with-her-2006-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":18206,"ratings":{"rtCritics":70,"rtCriticsLabel":"Fresh","rtAudience":46,"rtAudienceLabel":"Spilled","imdb":6,"imdbVotes":4359,"tmdb":5.9,"tmdbVotes":94}},{"id":"movie-awake-2007","title":"Awake","year":2007,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Thriller","Crime","Mystery"],"overview":"While undergoing heart surgery, a man experiences a phenomenon called \u2018anesthetic awareness\u2019, which leaves him awake but paralyzed throughout the operation. As various obstacles present themselves, his wife must make\u2026","poster":"assets/movie-awake-2007-poster.jpg","backdrop":"assets/movie-awake-2007-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":13483,"ratings":{"rtCritics":23,"rtCriticsLabel":"Rotten","rtAudience":55,"rtAudienceLabel":"Spilled","imdb":6.5,"imdbVotes":89389,"tmdb":6.586,"tmdbVotes":1649}},{"id":"movie-black-bear-2020","title":"Black Bear","year":2020,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Thriller"],"overview":"At a remote lake house in the Adirondack Mountains, a couple entertains an out-of-town guest looking for inspiration in her filmmaking. The group quickly falls into a calculated game of desire, manipulation, and\u2026","poster":"assets/movie-black-bear-2020-poster.jpg","backdrop":"assets/movie-black-bear-2020-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":624788,"ratings":{"rtCritics":89,"rtCriticsLabel":"Certified Fresh","rtAudience":64,"rtAudienceLabel":"Upright","imdb":6.5,"imdbVotes":18408,"tmdb":6.337,"tmdbVotes":315}},{"id":"movie-butterfly-on-a-wheel-2007","title":"Butterfly on a Wheel","year":2007,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Crime","Drama","Thriller"],"overview":"A sociopathic kidnapper methodically pushes a desperate pair of parents to their absolute breaking point.","poster":"assets/movie-butterfly-on-a-wheel-2007-poster.jpg","backdrop":"assets/movie-butterfly-on-a-wheel-2007-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":13250,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":61,"rtAudienceLabel":"Upright","imdb":6.6,"imdbVotes":35409,"tmdb":6.457,"tmdbVotes":595}},{"id":"movie-careful-what-you-wish-for-2015","title":"Careful What You Wish For","year":2015,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Thriller"],"overview":"A guy gets more than he bargained for after entering into an affair with the wife of an investment banker. Soon, a suspicious death and substantial life insurance policy embroil him in a scandal.","poster":"assets/movie-careful-what-you-wish-for-2015-poster.jpg","backdrop":"assets/movie-careful-what-you-wish-for-2015-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":317744,"ratings":{"rtCritics":17,"rtCriticsLabel":"Rotten","rtAudience":61,"rtAudienceLabel":"Upright","imdb":5.6,"imdbVotes":9452,"tmdb":6.129,"tmdbVotes":446}},{"id":"movie-crime-of-passion-1956","title":"Crime of Passion","year":1956,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Crime","Thriller"],"overview":"Kathy leaves the newspaper business to marry homicide detective Bill, but is frustrated by his lack of ambition and the banality of life in the suburbs. Her drive to advance Bill's career soon takes her down a\u2026","poster":"assets/movie-crime-of-passion-1956-poster.jpg","backdrop":"assets/movie-crime-of-passion-1956-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"center_crop","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1920,"ratings":{"rtCritics":80,"rtCriticsLabel":"Fresh","rtAudience":34,"rtAudienceLabel":"Spilled","imdb":6.4,"imdbVotes":3750,"tmdb":6.1,"tmdbVotes":57}},{"id":"movie-deep-water-2022","title":"Deep Water","year":2022,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Mystery","Thriller"],"overview":"A well-to-do husband who allows his wife to have affairs in order to avoid a divorce becomes a prime suspect in the disappearance of her lovers.","poster":"assets/movie-deep-water-2022-poster.jpg","backdrop":"assets/movie-deep-water-2022-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":619979,"ratings":{"rtCritics":35,"rtCriticsLabel":"Rotten","rtAudience":25,"rtAudienceLabel":"Spilled","imdb":5.5,"imdbVotes":74098,"tmdb":5.834,"tmdbVotes":1755}},{"id":"movie-derailed-2005","title":"Derailed","year":2005,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Thriller"],"overview":"When two married business executives having an affair are blackmailed by a violent criminal, they are forced to turn the tables on him to save their families.","poster":"assets/movie-derailed-2005-poster.jpg","backdrop":"assets/movie-derailed-2005-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":8999,"ratings":{"rtCritics":20,"rtCriticsLabel":"Rotten","rtAudience":58,"rtAudienceLabel":"Spilled","imdb":6.6,"imdbVotes":79563,"tmdb":6.405,"tmdbVotes":1193}},{"id":"movie-die-my-love-2025","title":"Die My Love","year":2025,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama"],"overview":"After inheriting a remote Montana house, Jackson moves there from New York with his partner Grace, and the couple soon welcome a child. As Jackson becomes increasingly absent and rural isolation sets in, Grace\u2026","poster":"assets/movie-die-my-love-2025-poster.jpg","backdrop":"assets/movie-die-my-love-2025-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1033148,"ratings":{"rtCritics":74,"rtCriticsLabel":"Certified Fresh","rtAudience":45,"rtAudienceLabel":"Spilled","imdb":6,"imdbVotes":50664,"tmdb":6.1,"tmdbVotes":683}},{"id":"movie-dream-house-2011","title":"Dream House","year":2011,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Mystery","Drama","Thriller"],"overview":"Publisher Will Atenton quits a lucrative job in New York to relocate his wife, Libby, and their daughters to a quaint town in New England. However, as they settle into their home the Atentons discover that a woman\u2026","poster":"assets/movie-dream-house-2011-poster.jpg","backdrop":"assets/movie-dream-house-2011-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":69668,"ratings":{"rtCritics":7,"rtCriticsLabel":"Rotten","rtAudience":36,"rtAudienceLabel":"Spilled","imdb":6,"imdbVotes":71386,"tmdb":6.212,"tmdbVotes":1480}},{"id":"movie-dream-lover-1994","title":"Dream Lover","year":1994,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Mystery","Thriller"],"overview":"Not long after they cross paths at an art gallery, architect Ray Reardon and hypnotically sensual Lena are married with children. But as strange incidents occur, Ray begins to realize he may not really know the woman\u2026","poster":"assets/movie-dream-lover-1994-poster.jpg","backdrop":"assets/movie-dream-lover-1994-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":18190,"ratings":{"rtCritics":57,"rtCriticsLabel":"Rotten","rtAudience":38,"rtAudienceLabel":"Spilled","imdb":6.2,"imdbVotes":7865,"tmdb":6.844,"tmdbVotes":167}},{"id":"movie-drop-2025","title":"Drop","year":2025,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Mystery","Thriller"],"overview":"Violet, a widowed mother on her first date in years, arrives at an upscale restaurant where she is relieved that her date, Henry, is more charming and handsome than she expected. But their chemistry begins to curdle\u2026","poster":"assets/movie-drop-2025-poster.jpg","backdrop":"assets/movie-drop-2025-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1249213,"ratings":{"rtCritics":83,"rtCriticsLabel":"Certified Fresh","rtAudience":79,"rtAudienceLabel":"Upright","imdb":6.1,"imdbVotes":61018,"tmdb":6.275,"tmdbVotes":1023}},{"id":"movie-eastern-promises-2007","title":"Eastern Promises","year":2007,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Thriller","Crime","Mystery"],"overview":"A Russian teenager living in London dies during childbirth but leaves clues in her diary that could tie her child to a rape involving a violent Russian mob family.","poster":"assets/movie-eastern-promises-2007-poster.jpg","backdrop":"assets/movie-eastern-promises-2007-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":2252,"ratings":{"rtCritics":89,"rtCriticsLabel":"Certified Fresh","rtAudience":83,"rtAudienceLabel":"Upright","imdb":7.6,"imdbVotes":281015,"tmdb":7.349,"tmdbVotes":3900}},{"id":"movie-faces-1968","title":"Faces","year":1968,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama"],"overview":"Middle-aged suburban husband Richard abruptly tells his wife, Maria, that he wants a divorce. As Richard takes up with a younger woman, Maria enjoys a night on the town with her friends and meets a younger man. As\u2026","poster":"assets/movie-faces-1968-poster.jpg","backdrop":"assets/movie-faces-1968-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"center_crop","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":753,"ratings":{"rtCritics":83,"rtCriticsLabel":"Fresh","rtAudience":86,"rtAudienceLabel":"Upright","imdb":7.4,"imdbVotes":12950,"tmdb":7.093,"tmdbVotes":227}},{"id":"movie-fatale-2020","title":"Fatale","year":2020,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Thriller"],"overview":"After a wild one-night stand, successful sports agent Derrick Tyler watches his perfect life slowly disappear when he discovers the sexy and mysterious woman he risked everything for is determined police detective\u2026","poster":"assets/movie-fatale-2020-poster.jpg","backdrop":"assets/movie-fatale-2020-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":549514,"ratings":{"rtCritics":46,"rtCriticsLabel":"Rotten","rtAudience":87,"rtAudienceLabel":"Upright","imdb":5.5,"imdbVotes":16392,"tmdb":6,"tmdbVotes":401}},{"id":"tv-56-days-2026","title":"56 Days","year":2026,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Crime","Mystery"],"overview":"When an unidentified body is found in a luxury apartment linked to Oliver Kennedy and his girlfriend Ciara Wyse, Detectives Lee Reardon and Karl Connolly reconstruct the couple's deadly romance across the past 56 days.","poster":"assets/tv-56-days-2026-poster.jpg","backdrop":"assets/tv-56-days-2026-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":241372,"ratings":{"rtCritics":60,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.388,"tmdbVotes":245}},{"id":"tv-90-day-fiance-before-the-90-days-2017","title":"90 Day Fianc\u00e9: Before the 90 Days","year":2017,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Reality"],"overview":"Follow couples who have an existing relationship online, but haven't met in person. We'll experience their journey as they travel to the other's foreign country for the first time in an attempt to establish an\u2026","poster":"assets/tv-90-day-fiance-before-the-90-days-2017-poster.jpg","backdrop":"assets/tv-90-day-fiance-before-the-90-days-2017-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":73319,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.5,"tmdbVotes":45}},{"id":"tv-90-day-fiance-the-other-way-2019","title":"90 Day Fianc\u00e9: The Other Way","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Reality"],"overview":"Americans move to a foreign country all in the name of love. Will uprooting their lives in the United States pay off, or will they be packing up and moving back to America brokenhearted?","poster":"assets/tv-90-day-fiance-the-other-way-2019-poster.jpg","backdrop":"assets/tv-90-day-fiance-the-other-way-2019-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":90046,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.8,"tmdbVotes":34}},{"id":"tv-absolutely-fabulous-1992","title":"Absolutely Fabulous","year":1992,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy"],"overview":"Set in the world of fashion and PR, immature fun-loving mother Edina Monsoon and her best friend Patsy drive Eddie's sensible daughter, Saffron, up the wall with their constant drug abuse and outrageous selfishness.\u2026","poster":"assets/tv-absolutely-fabulous-1992-poster.jpg","backdrop":"assets/tv-absolutely-fabulous-1992-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":4493,"ratings":{"rtCritics":96,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.6,"tmdbVotes":198}},{"id":"tv-the-afterparty-2022","title":"The Afterparty","year":2022,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Mystery","Comedy","Crime"],"overview":"Nothing is as it seems in this hilarious murder mystery where each suspect's story is told through a different film genre.","poster":"assets/tv-the-afterparty-2022-poster.jpg","backdrop":"assets/tv-the-afterparty-2022-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":106454,"ratings":{"rtCritics":92,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.071,"tmdbVotes":245}},{"id":"tv-agatha-christie-s-marple-2004","title":"Agatha Christie's Marple","year":2004,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Crime","Mystery"],"overview":"The adventures of Miss Jane Marple, an elderly spinster living in the quiet little village of St Mary Mead. During her many visits to friends and relatives in other villages, Miss Marple often stumbles upon\u2026","poster":"assets/tv-agatha-christie-s-marple-2004-poster.jpg","backdrop":"assets/tv-agatha-christie-s-marple-2004-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":6127,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.9,"tmdbVotes":152}},{"id":"tv-all-american-homecoming-2022","title":"All American: Homecoming","year":2022,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama"],"overview":"Follow the journeys of Simone Hicks, a tennis hopeful from Beverly Hills, and elite baseball player Damon Sims from Chicago, as they navigate life at the prestigious HBCU Bringston University.","poster":"assets/tv-all-american-homecoming-2022-poster.jpg","backdrop":"assets/tv-all-american-homecoming-2022-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":153723,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.3,"tmdbVotes":70}},{"id":"tv-and-just-like-that-2021","title":"And Just Like That\u2026","year":2021,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy","Drama"],"overview":"This new chapter of \u201cSex and the City\u201d follows Carrie, Miranda and Charlotte as they navigate the journey from the complicated reality of life and friendship in their 30s to the even more complicated reality of life\u2026","poster":"assets/tv-and-just-like-that-2021-poster.jpg","backdrop":"assets/tv-and-just-like-that-2021-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":116450,"ratings":{"rtCritics":52,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.211,"tmdbVotes":556}},{"id":"tv-anne-with-an-e-2017","title":"Anne with an E","year":2017,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Family"],"overview":"A coming-of-age story about an outsider who, against all odds and numerous challenges, fights for love and acceptance and for her place in the world. The series centers on a young orphaned girl in the late 1890s,\u2026","poster":"assets/tv-anne-with-an-e-2017-poster.jpg","backdrop":"assets/tv-anne-with-an-e-2017-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":70785,"ratings":{"rtCritics":63,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.7,"tmdbVotes":5019}},{"id":"tv-awkward-2011","title":"Awkward.","year":2011,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy","Drama"],"overview":"An irreverent look at the conflict, chaos and humor that defines teenage life through the eyes of 15-year-old Jenna Hamilton whose life begins to change when a simple accident becomes an epic misunderstanding and is\u2026","poster":"assets/tv-awkward-2011-poster.jpg","backdrop":"assets/tv-awkward-2011-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":39859,"ratings":{"rtCritics":78,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.4,"tmdbVotes":427}},{"id":"tv-the-baby-sitters-club-2020","title":"The Baby-Sitters Club","year":2020,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Kids","Drama"],"overview":"In this contemporary take on the beloved book series, five best friends launch a baby-sitting business that's big on fun and adventure.","poster":"assets/tv-the-baby-sitters-club-2020-poster.jpg","backdrop":"assets/tv-the-baby-sitters-club-2020-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":100412,"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.9,"tmdbVotes":506}},{"id":"tv-ballers-2015","title":"Ballers","year":2015,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Comedy"],"overview":"Looking at the lives of former and current football players, the show follows former superstar Spencer Strasmore as he gets his life on track in retirement while mentoring other current and former players through the\u2026","poster":"assets/tv-ballers-2015-poster.jpg","backdrop":"assets/tv-ballers-2015-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":62704,"ratings":{"rtCritics":72,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.809,"tmdbVotes":820}},{"id":"tv-baretta-1975","title":"Baretta","year":1975,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Crime","Drama","Mystery"],"overview":"Baretta is an American detective television series which ran on ABC from 1975 to 1978. The show was a milder version of a successful 1973\u201374 ABC series, Toma, starring Tony Musante as chameleon-like, real-life New\u2026","poster":"assets/tv-baretta-1975-poster.jpg","backdrop":"assets/tv-baretta-1975-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":3216,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.5,"tmdbVotes":43}},{"id":"tv-based-on-a-true-story-2023","title":"Based on a True Story","year":2023,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy","Drama"],"overview":"The lives of a realtor, a plumber and a former tennis star unexpectedly collide, exposing America\u2019s obsession with true crime, murder and the slow-close toilet seat.","poster":"assets/tv-based-on-a-true-story-2023-poster.jpg","backdrop":"assets/tv-based-on-a-true-story-2023-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":197373,"ratings":{"rtCritics":79,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7,"tmdbVotes":160}},{"id":"tv-the-beast-in-me-2025","title":"The Beast in Me","year":2025,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Mystery"],"overview":"A famous author is pulled into a twisted mind game with her rich, powerful new neighbor \u2014 who might be a murderer.","poster":"assets/tv-the-beast-in-me-2025-poster.jpg","backdrop":"assets/tv-the-beast-in-me-2025-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":250504,"ratings":{"rtCritics":85,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.072,"tmdbVotes":334}},{"id":"tv-big-city-greens-2018","title":"Big City Greens","year":2018,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Family","Animation","Comedy"],"overview":"The offbeat adventures of 10-year-old Cricket Green, a mischievous and optimistic country boy who moves to the big city with his wildly out of place family \u2013 older sister Tilly, father Bill and Gramma Alice.","poster":"assets/tv-big-city-greens-2018-poster.jpg","backdrop":"assets/tv-big-city-greens-2018-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":80587,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.555,"tmdbVotes":82}},{"id":"tv-the-bold-type-2017","title":"The Bold Type","year":2017,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Comedy"],"overview":"A glimpse into the outrageous lives of Jane, Kat and Sutton, who are working at the nation's top women's magazine, Scarlet, while navigating their careers, identities and individual voices.","poster":"assets/tv-the-bold-type-2017-poster.jpg","backdrop":"assets/tv-the-bold-type-2017-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":69630,"ratings":{"rtCritics":89,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.7,"tmdbVotes":204}},{"id":"tv-brassic-2019","title":"Brassic","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy","Drama","Crime"],"overview":"A group of working-class friends finding unconventional ways to win at life in suburban northern England. These lads have dealt, scammed, bribed and conned their way through adolescence, but now, their dealing and\u2026","poster":"assets/tv-brassic-2019-poster.jpg","backdrop":"assets/tv-brassic-2019-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":92621,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.336,"tmdbVotes":263}}]},{"key":"shared","movies":[{"id":"movie-american-gangster-2007","title":"American Gangster","year":2007,"type":"movie","runtimeSeconds":10546,"seasonCount":null,"communityRating":7.595,"criticRating":81,"genres":["Drama","Crime"],"overview":"Loosely based on the criminal career of Frank Lucas, a gangster from La Grange, North Carolina, who smuggled heroin into the United States on American service planes returning from the Vietnam War, before being\u2026","poster":"assets/movie-american-gangster-2007-poster.jpg","backdrop":"assets/movie-american-gangster-2007-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-08-23T10:22:36.0000000Z","lastPlayedAt":"2026-08-30T21:05:39.7952451Z","availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":4982,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":81,"rtCriticsLabel":"Certified Fresh","rtAudience":90,"rtAudienceLabel":"Upright","imdb":7.8,"imdbVotes":495656,"tmdb":7.599,"tmdbVotes":6350}},{"id":"movie-annie-hall-1977","title":"Annie Hall","year":1977,"type":"movie","runtimeSeconds":5604,"seasonCount":null,"communityRating":7.712,"criticRating":97,"genres":["Comedy","Drama","Romance"],"overview":"New York comedian Alvy Singer falls in love with the ditsy Annie Hall.","poster":"assets/movie-annie-hall-1977-poster.jpg","backdrop":"assets/movie-annie-hall-1977-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:24:23.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":703,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":97,"rtCriticsLabel":"Certified Fresh","rtAudience":92,"rtAudienceLabel":"Upright","imdb":7.9,"imdbVotes":293349,"tmdb":7.71,"tmdbVotes":4391}},{"id":"movie-apocalypse-now-1979","title":"Apocalypse Now","year":1979,"type":"movie","runtimeSeconds":8835,"seasonCount":null,"communityRating":8.261,"criticRating":91,"genres":["Drama","War"],"overview":"At the height of the Vietnam war, Captain Benjamin Willard is sent on a dangerous mission that, officially, \"does not exist, nor will it ever exist.\" His goal is to locate - and eliminate - a mysterious Green Beret\u2026","poster":"assets/movie-apocalypse-now-1979-poster.jpg","backdrop":"assets/movie-apocalypse-now-1979-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:22:25.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":28,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":91,"rtCriticsLabel":"Certified Fresh","rtAudience":94,"rtAudienceLabel":"Upright","imdb":8.4,"imdbVotes":781424,"tmdb":8.3,"tmdbVotes":9526}},{"id":"movie-arrival-2016","title":"Arrival","year":2016,"type":"movie","runtimeSeconds":6967,"seasonCount":null,"communityRating":7.636,"criticRating":94,"genres":["Drama","Science Fiction","Mystery"],"overview":"Taking place after alien crafts land around the world, an expert linguist is recruited by the military to determine whether they come in peace or are a threat.","poster":"assets/movie-arrival-2016-poster.jpg","backdrop":"assets/movie-arrival-2016-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-14T19:54:12.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":329865,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":94,"rtCriticsLabel":"Certified Fresh","rtAudience":83,"rtAudienceLabel":"Upright","imdb":7.9,"imdbVotes":883621,"tmdb":7.638,"tmdbVotes":20125}},{"id":"movie-avatar-aang-the-last-airbender-2026","title":"Avatar Aang: The Last Airbender","year":2026,"type":"movie","runtimeSeconds":5930,"seasonCount":null,"communityRating":9.147,"criticRating":90,"genres":["Animation","Adventure","Fantasy"],"overview":"Avatar Aang, the world's last Airbender, learns of an ancient power that could save his culture from extinction. With the help of his friends, he embarks on a global quest to find it before it falls into the wrong\u2026","poster":"assets/movie-avatar-aang-the-last-airbender-2026-poster.jpg","backdrop":"assets/movie-avatar-aang-the-last-airbender-2026-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-25T09:53:09.0000000Z","lastPlayedAt":"2026-08-02T19:22:33.6155383Z","availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":980431,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":90,"rtCriticsLabel":"Certified Fresh","rtAudience":99,"rtAudienceLabel":"Upright","imdb":7.7,"imdbVotes":30792,"tmdb":9,"tmdbVotes":1417}},{"id":"movie-bohemian-rhapsody-2018","title":"Bohemian Rhapsody","year":2018,"type":"movie","runtimeSeconds":8077,"seasonCount":null,"communityRating":7.95,"criticRating":60,"genres":["Music","Drama"],"overview":"Singer Freddie Mercury, guitarist Brian May, drummer Roger Taylor and bass guitarist John Deacon take the music world by storm when they form the rock 'n' roll band Queen in 1970. Hit songs become instant classics.\u2026","poster":"assets/movie-bohemian-rhapsody-2018-poster.jpg","backdrop":"assets/movie-bohemian-rhapsody-2018-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:28:20.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":424694,"artwork":{"posterKind":"center_crop","backdropKind":"backdrop"},"ratings":{"rtCritics":60,"rtCriticsLabel":"Fresh","rtAudience":85,"rtAudienceLabel":"Upright","imdb":7.9,"imdbVotes":655894,"tmdb":7.947,"tmdbVotes":18196}},{"id":"movie-the-boy-and-the-heron-2023","title":"The Boy and the Heron","year":2023,"type":"movie","runtimeSeconds":7437,"seasonCount":null,"communityRating":7.4,"criticRating":96,"genres":["Animation","Fantasy","Drama"],"overview":"While the Second World War rages, the teenage Mahito, haunted by his mother's tragic death, is relocated from Tokyo to the serene rural home of his new stepmother Natsuko, a woman who bears a striking resemblance to\u2026","poster":"assets/movie-the-boy-and-the-heron-2023-poster.jpg","backdrop":"assets/movie-the-boy-and-the-heron-2023-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:25:15.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":508883,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":96,"rtCriticsLabel":"Certified Fresh","rtAudience":88,"rtAudienceLabel":"Upright","imdb":7.3,"imdbVotes":152169,"tmdb":7.387,"tmdbVotes":2893}},{"id":"movie-braveheart-1995","title":"Braveheart","year":1995,"type":"movie","runtimeSeconds":10665,"seasonCount":null,"communityRating":7.945,"criticRating":74,"genres":["Drama","History","War"],"overview":"Enraged at the slaughter of Murron, his new bride and childhood love, Scottish warrior William Wallace slays a platoon of the local English lord's soldiers. This leads the village to revolt and, eventually, the\u2026","poster":"assets/movie-braveheart-1995-poster.jpg","backdrop":"assets/movie-braveheart-1995-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-10T21:24:28.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":197,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":74,"rtCriticsLabel":"Certified Fresh","rtAudience":85,"rtAudienceLabel":"Upright","imdb":8.3,"imdbVotes":1174990,"tmdb":7.947,"tmdbVotes":11584}},{"id":"movie-the-breakfast-club-1985","title":"The Breakfast Club","year":1985,"type":"movie","runtimeSeconds":5833,"seasonCount":null,"communityRating":7.7,"criticRating":87,"genres":["Comedy","Drama"],"overview":"Five high school students from different walks of life endure a Saturday detention under a power-hungry principal. The disparate group includes rebel John, princess Claire, outcast Allison, brainy Brian and Andrew,\u2026","poster":"assets/movie-the-breakfast-club-1985-poster.jpg","backdrop":"assets/movie-the-breakfast-club-1985-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:25:03.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":2108,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":87,"rtCriticsLabel":"Certified Fresh","rtAudience":92,"rtAudienceLabel":"Upright","imdb":7.8,"imdbVotes":478743,"tmdb":7.713,"tmdbVotes":8815}},{"id":"movie-castle-in-the-sky-1986","title":"Castle in the Sky","year":1986,"type":"movie","runtimeSeconds":7474,"seasonCount":null,"communityRating":8,"criticRating":97,"genres":["Adventure","Fantasy","Animation"],"overview":"A young boy and a girl with a magic crystal must race against pirates and foreign agents in a search for a legendary floating castle.","poster":"assets/movie-castle-in-the-sky-1986-poster.jpg","backdrop":"assets/movie-castle-in-the-sky-1986-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:23:09.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":10515,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":96,"rtCriticsLabel":"Fresh","rtAudience":91,"rtAudienceLabel":"Upright","imdb":8,"imdbVotes":201545,"tmdb":7.972,"tmdbVotes":4868}},{"id":"movie-citizen-kane-1941","title":"Citizen Kane","year":1941,"type":"movie","runtimeSeconds":7173,"seasonCount":null,"communityRating":7.966,"criticRating":99,"genres":["Mystery","Drama"],"overview":"Newspaper magnate Charles Foster Kane is taken from his mother as a boy and made the ward of a rich industrialist. As a result, every well-meaning, tyrannical or self-destructive move he makes for the rest of his\u2026","poster":"assets/movie-citizen-kane-1941-poster.jpg","backdrop":"assets/movie-citizen-kane-1941-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:22:16.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":15,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":99,"rtCriticsLabel":"Certified Fresh","rtAudience":98,"rtAudienceLabel":"Upright","imdb":8.2,"imdbVotes":498321,"tmdb":7.962,"tmdbVotes":6324}},{"id":"movie-conclave-2024","title":"Conclave","year":2024,"type":"movie","runtimeSeconds":7230,"seasonCount":null,"communityRating":7.19,"criticRating":93,"genres":["Drama","Thriller"],"overview":"After the unexpected death of the Pope, Cardinal Lawrence is tasked with managing the covert and ancient ritual of electing a new one. Sequestered in the Vatican with the Catholic Church\u2019s most powerful leaders until\u2026","poster":"assets/movie-conclave-2024-poster.jpg","backdrop":"assets/movie-conclave-2024-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:30:41.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":974576,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":93,"rtCriticsLabel":"Certified Fresh","rtAudience":86,"rtAudienceLabel":"Upright","imdb":7.4,"imdbVotes":290498,"tmdb":7.19,"tmdbVotes":3744}},{"id":"movie-the-dry-2021","title":"The Dry","year":2021,"type":"movie","runtimeSeconds":7037,"seasonCount":null,"communityRating":6.779,"criticRating":null,"genres":["Crime","Thriller","Mystery"],"overview":"Aaron Falk returns to his drought-stricken hometown to attend a tragic funeral. But his return opens a decades-old wound - the unsolved death of a teenage girl.","poster":"assets/movie-the-dry-2021-poster.jpg","backdrop":"assets/movie-the-dry-2021-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:29:20.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":567797,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":90,"rtCriticsLabel":"Certified Fresh","rtAudience":89,"rtAudienceLabel":"Upright","imdb":6.8,"imdbVotes":41935,"tmdb":6.8,"tmdbVotes":892}},{"id":"movie-easy-a-2010","title":"Easy A","year":2010,"type":"movie","runtimeSeconds":5545,"seasonCount":null,"communityRating":6.8,"criticRating":85,"genres":["Comedy"],"overview":"Olive, an average high school student, sees her below-the-radar existence turn around overnight once she decides to use the school's gossip grapevine to advance her social standing. Now her classmates are turning\u2026","poster":"assets/movie-easy-a-2010-poster.jpg","backdrop":"assets/movie-easy-a-2010-backdrop.jpg","played":true,"playCount":1,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-17T19:59:04.0000000Z","lastPlayedAt":"2026-10-17T20:02:51.1083337Z","availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":37735,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":85,"rtCriticsLabel":"Certified Fresh","rtAudience":77,"rtAudienceLabel":"Upright","imdb":7,"imdbVotes":448780,"tmdb":6.8,"tmdbVotes":7619}},{"id":"movie-el-camino-a-breaking-bad-movie-2019","title":"El Camino: A Breaking Bad Movie","year":2019,"type":"movie","runtimeSeconds":7362,"seasonCount":null,"communityRating":7.055,"criticRating":92,"genres":["Crime","Drama","Thriller"],"overview":"In the wake of his dramatic escape from captivity, Jesse Pinkman must come to terms with his past in order to forge some kind of future.","poster":"assets/movie-el-camino-a-breaking-bad-movie-2019-poster.jpg","backdrop":"assets/movie-el-camino-a-breaking-bad-movie-2019-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-21T23:31:11.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":559969,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":92,"rtCriticsLabel":"Certified Fresh","rtAudience":81,"rtAudienceLabel":"Upright","imdb":7.3,"imdbVotes":354488,"tmdb":7.056,"tmdbVotes":5950}},{"id":"movie-emancipation-2022","title":"Emancipation","year":2022,"type":"movie","runtimeSeconds":7949,"seasonCount":null,"communityRating":7.7,"criticRating":45,"genres":["Drama","War","History"],"overview":"Inspired by the gripping true story of a man who would do anything for his family\u2014and for freedom. When Peter, an enslaved man, risks his life to escape and return to his family, he embarks on a perilous journey of\u2026","poster":"assets/movie-emancipation-2022-poster.jpg","backdrop":"assets/movie-emancipation-2022-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-10T20:37:34.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":715931,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":45,"rtCriticsLabel":"Rotten","rtAudience":58,"rtAudienceLabel":"Spilled","imdb":6.3,"imdbVotes":32079,"tmdb":7.744,"tmdbVotes":1319}},{"id":"movie-fighting-with-my-family-2019","title":"Fighting with My Family","year":2019,"type":"movie","runtimeSeconds":6509,"seasonCount":null,"communityRating":6.84,"criticRating":93,"genres":["Comedy"],"overview":"Born into a tight-knit wrestling family, Paige and her brother Zak are ecstatic when they get the once-in-a-lifetime opportunity to try out for the WWE. But when only Paige earns a spot in the competitive training\u2026","poster":"assets/movie-fighting-with-my-family-2019-poster.jpg","backdrop":"assets/movie-fighting-with-my-family-2019-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-22T22:10:59.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":445629,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":93,"rtCriticsLabel":"Certified Fresh","rtAudience":86,"rtAudienceLabel":"Upright","imdb":7,"imdbVotes":94576,"tmdb":6.837,"tmdbVotes":1952}},{"id":"movie-force-of-nature-the-dry-2-2024","title":"Force of Nature: The Dry 2","year":2024,"type":"movie","runtimeSeconds":6753,"seasonCount":null,"communityRating":6.3,"criticRating":66,"genres":["Mystery","Thriller"],"overview":"When five women take part in a corporate hiking retreat and only four come out on the other side, Federal Agents Aaron Falk and Carmen Cooper head deep into the Victorian mountain ranges to investigate in the hopes\u2026","poster":"assets/movie-force-of-nature-the-dry-2-2024-poster.jpg","backdrop":"assets/movie-force-of-nature-the-dry-2-2024-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:29:49.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":832262,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":66,"rtCriticsLabel":"Fresh","rtAudience":43,"rtAudienceLabel":"Spilled","imdb":5.9,"imdbVotes":10343,"tmdb":6.269,"tmdbVotes":305}},{"id":"movie-free-state-of-jones-2016","title":"Free State of Jones","year":2016,"type":"movie","runtimeSeconds":8376,"seasonCount":null,"communityRating":6.79,"criticRating":48,"genres":["Action","Drama","History"],"overview":"In 1863, Mississippi farmer Newt Knight serves as a medic for the Confederate Army. Opposed to slavery, Knight would rather help the wounded than fight the Union. After his nephew dies in battle, Newt returns home to\u2026","poster":"assets/movie-free-state-of-jones-2016-poster.jpg","backdrop":"assets/movie-free-state-of-jones-2016-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-11T17:56:53.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":316152,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":48,"rtCriticsLabel":"Rotten","rtAudience":64,"rtAudienceLabel":"Upright","imdb":6.9,"imdbVotes":68931,"tmdb":6.788,"tmdbVotes":1730}},{"id":"movie-from-up-on-poppy-hill-2011","title":"From Up on Poppy Hill","year":2011,"type":"movie","runtimeSeconds":5482,"seasonCount":null,"communityRating":7.5,"criticRating":87,"genres":["Animation","Drama"],"overview":"Yokohama, 1963. Japan is picking itself up from the devastation of World War II and preparing to host the 1964 Olympics\u2014and the mood is one of both optimism and conflict as the young generation struggles to throw off\u2026","poster":"assets/movie-from-up-on-poppy-hill-2011-poster.jpg","backdrop":"assets/movie-from-up-on-poppy-hill-2011-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-07T14:41:03.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":83389,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":87,"rtCriticsLabel":"Certified Fresh","rtAudience":80,"rtAudienceLabel":"Upright","imdb":7.4,"imdbVotes":60769,"tmdb":7.509,"tmdbVotes":2026}},{"id":"movie-ghost-in-the-shell-1995","title":"Ghost in the Shell","year":1995,"type":"movie","runtimeSeconds":4959,"seasonCount":null,"communityRating":7.929,"criticRating":95,"genres":["Action","Animation","Science Fiction"],"overview":"In the year 2029, the barriers of our world have been broken down by the net and by cybernetics, but this brings new vulnerability to humans in the form of brain-hacking. When a highly-wanted hacker known as 'The\u2026","poster":"assets/movie-ghost-in-the-shell-1995-poster.jpg","backdrop":"assets/movie-ghost-in-the-shell-1995-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:22:57.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":9323,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":97,"rtCriticsLabel":"Certified Fresh","rtAudience":90,"rtAudienceLabel":"Upright","imdb":7.9,"imdbVotes":178061,"tmdb":7.928,"tmdbVotes":4130}},{"id":"movie-ghost-in-the-shell-2-innocence-2004","title":"Ghost in the Shell 2: Innocence","year":2004,"type":"movie","runtimeSeconds":5950,"seasonCount":null,"communityRating":7.352,"criticRating":65,"genres":["Animation","Drama","Science Fiction"],"overview":"Cyborg detective Batou is assigned to investigate a series of murders committed by gynoids\u2014doll-like cyborgs, which all malfunctioned, killed, then self-destructed afterwards. The brains of the gynoids initialize in\u2026","poster":"assets/movie-ghost-in-the-shell-2-innocence-2004-poster.jpg","backdrop":"assets/movie-ghost-in-the-shell-2-innocence-2004-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:23:38.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":12140,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":65,"rtCriticsLabel":"Fresh","rtAudience":80,"rtAudienceLabel":"Upright","imdb":7.4,"imdbVotes":43280,"tmdb":7.356,"tmdbVotes":1049}},{"id":"movie-the-godfather-1972","title":"The Godfather","year":1972,"type":"movie","runtimeSeconds":10603,"seasonCount":null,"communityRating":8.687,"criticRating":97,"genres":["Drama","Crime"],"overview":"Spanning the years 1945 to 1955, a chronicle of the fictional Italian-American Corleone crime family. When organized crime family patriarch, Vito Corleone barely survives an attempt on his life, his youngest son,\u2026","poster":"assets/movie-the-godfather-1972-poster.jpg","backdrop":"assets/movie-the-godfather-1972-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:24:12.0000000Z","lastPlayedAt":"2026-09-18T19:24:44.9855867Z","availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":238,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":97,"rtCriticsLabel":"Certified Fresh","rtAudience":98,"rtAudienceLabel":"Upright","imdb":9.2,"imdbVotes":2262024,"tmdb":8.688,"tmdbVotes":23907}},{"id":"movie-the-godfather-part-ii-1974","title":"The Godfather Part II","year":1974,"type":"movie","runtimeSeconds":12031,"seasonCount":null,"communityRating":8.573,"criticRating":96,"genres":["Drama","Crime"],"overview":"In the continuing saga of the Corleone crime family, a young Vito Corleone grows up in Sicily and in 1910s New York. In the 1950s, Michael Corleone attempts to expand the family business into Las Vegas, Hollywood and\u2026","poster":"assets/movie-the-godfather-part-ii-1974-poster.jpg","backdrop":"assets/movie-the-godfather-part-ii-1974-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:24:18.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":240,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":96,"rtCriticsLabel":"Certified Fresh","rtAudience":97,"rtAudienceLabel":"Upright","imdb":9,"imdbVotes":1521308,"tmdb":8.571,"tmdbVotes":14559}},{"id":"movie-the-godfather-part-iii-1990","title":"The Godfather Part III","year":1990,"type":"movie","runtimeSeconds":9476,"seasonCount":null,"communityRating":7.416,"criticRating":67,"genres":["Crime","Drama","Thriller"],"overview":"In the midst of trying to legitimize his business dealings in 1979 New York and Italy, aging mafia don, Michael Corleone seeks forgiveness for his sins while taking a young protege under his wing.","poster":"assets/movie-the-godfather-part-iii-1990-poster.jpg","backdrop":"assets/movie-the-godfather-part-iii-1990-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:26:29.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":242,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":68,"rtCriticsLabel":"Fresh","rtAudience":68,"rtAudienceLabel":"Upright","imdb":7.5,"imdbVotes":462448,"tmdb":7.413,"tmdbVotes":7159}},{"id":"movie-gosford-park-2001","title":"Gosford Park","year":2001,"type":"movie","runtimeSeconds":8247,"seasonCount":null,"communityRating":6.815,"criticRating":87,"genres":["Drama","Mystery","Thriller"],"overview":"In 1930s England, a group of pretentious rich and famous gather together for a weekend of relaxation at a hunting resort. But when a murder occurs, each one of these interesting characters becomes a suspect.","poster":"assets/movie-gosford-park-2001-poster.jpg","backdrop":"assets/movie-gosford-park-2001-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:25:49.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":5279,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":87,"rtCriticsLabel":"Certified Fresh","rtAudience":78,"rtAudienceLabel":"Upright","imdb":7.2,"imdbVotes":103883,"tmdb":6.822,"tmdbVotes":1317}},{"id":"movie-grave-of-the-fireflies-1988","title":"Grave of the Fireflies","year":1988,"type":"movie","runtimeSeconds":5313,"seasonCount":null,"communityRating":8.45,"criticRating":100,"genres":["Animation","Drama","War"],"overview":"In the final months of World War II, 14-year-old Seita and his sister Setsuko are orphaned when their mother is killed during an air raid in Kobe, Japan. After a falling out with their aunt, they move into an\u2026","poster":"assets/movie-grave-of-the-fireflies-1988-poster.jpg","backdrop":"assets/movie-grave-of-the-fireflies-1988-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:24:14.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":12477,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Certified Fresh","rtAudience":95,"rtAudienceLabel":"Upright","imdb":8.5,"imdbVotes":399802,"tmdb":8.45,"tmdbVotes":6938}},{"id":"movie-the-great-gatsby-2013","title":"The Great Gatsby","year":2013,"type":"movie","runtimeSeconds":8525,"seasonCount":null,"communityRating":7.346,"criticRating":49,"genres":["Drama","Romance"],"overview":"Nick Carraway arrives in New York in 1922, an era of loose morals, glittering jazz and bootleg kings. Chasing his own American Dream, Nick encounters the mysterious millionaire Gatsby and his bewitching cousin Daisy.\u2026","poster":"assets/movie-the-great-gatsby-2013-poster.jpg","backdrop":"assets/movie-the-great-gatsby-2013-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:26:50.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":64682,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":48,"rtCriticsLabel":"Rotten","rtAudience":67,"rtAudienceLabel":"Upright","imdb":7.2,"imdbVotes":651882,"tmdb":7.346,"tmdbVotes":13290}},{"id":"movie-the-hours-2002","title":"The Hours","year":2002,"type":"movie","runtimeSeconds":6887,"seasonCount":null,"communityRating":7.25,"criticRating":79,"genres":["Drama"],"overview":"The story of three women searching for more potent, meaningful lives. Each is alive at a different time and place, all are linked by their yearnings and their fears. Their stories intertwine, and finally come\u2026","poster":"assets/movie-the-hours-2002-poster.jpg","backdrop":"assets/movie-the-hours-2002-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:23:27.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":590,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":79,"rtCriticsLabel":"Certified Fresh","rtAudience":84,"rtAudienceLabel":"Upright","imdb":7.5,"imdbVotes":148367,"tmdb":7.249,"tmdbVotes":1931}},{"id":"movie-howl-s-moving-castle-2004","title":"Howl's Moving Castle","year":2004,"type":"movie","runtimeSeconds":7149,"seasonCount":null,"communityRating":8.4,"criticRating":88,"genres":["Fantasy","Animation","Adventure"],"overview":"Sophie, a young milliner, is turned into an elderly woman by a witch who enters her shop and curses her. She encounters a wizard named Howl and gets caught up in his resistance to fighting for the king.","poster":"assets/movie-howl-s-moving-castle-2004-poster.jpg","backdrop":"assets/movie-howl-s-moving-castle-2004-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:22:47.0000000Z","lastPlayedAt":"2026-05-21T18:46:08.0000000Z","availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":4935,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":87,"rtCriticsLabel":"Certified Fresh","rtAudience":93,"rtAudienceLabel":"Upright","imdb":8.2,"imdbVotes":524520,"tmdb":8.391,"tmdbVotes":11642}},{"id":"movie-in-the-heights-2021","title":"In the Heights","year":2021,"type":"movie","runtimeSeconds":8579,"seasonCount":null,"communityRating":7.111,"criticRating":null,"genres":["Drama","Romance"],"overview":"The story of Usnavi, a bodega owner who has mixed feelings about closing his store and retiring to the Dominican Republic or staying in Washington Heights.","poster":"assets/movie-in-the-heights-2021-poster.jpg","backdrop":"assets/movie-in-the-heights-2021-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:29:11.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":467909,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":94,"rtCriticsLabel":"Certified Fresh","rtAudience":94,"rtAudienceLabel":"Upright","imdb":7.2,"imdbVotes":56513,"tmdb":7.104,"tmdbVotes":826}},{"id":"movie-jennifer-s-body-2009","title":"Jennifer's Body","year":2009,"type":"movie","runtimeSeconds":6450,"seasonCount":null,"communityRating":6.012,"criticRating":47,"genres":["Horror","Comedy"],"overview":"Jennifer, a gorgeous, seductive cheerleader takes evil to a whole new level after she's possessed by a sinister demon. Now it's up to her best friend to stop Jennifer's reign of terror before it's too late.","poster":"assets/movie-jennifer-s-body-2009-poster.jpg","backdrop":"assets/movie-jennifer-s-body-2009-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-30T03:37:04.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":19994,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":47,"rtCriticsLabel":"Rotten","rtAudience":36,"rtAudienceLabel":"Spilled","imdb":5.6,"imdbVotes":179710,"tmdb":6.013,"tmdbVotes":4481}},{"id":"movie-kiki-s-delivery-service-1989","title":"Kiki's Delivery Service","year":1989,"type":"movie","runtimeSeconds":6183,"seasonCount":null,"communityRating":7.839,"criticRating":null,"genres":["Animation","Family","Fantasy"],"overview":"A young witch, on her mandatory year of independent life, finds fitting into a new community difficult while she supports herself by running an air courier service.","poster":"assets/movie-kiki-s-delivery-service-1989-poster.jpg","backdrop":"assets/movie-kiki-s-delivery-service-1989-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:24:20.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":16859,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":98,"rtCriticsLabel":"Certified Fresh","rtAudience":89,"rtAudienceLabel":"Upright","imdb":7.8,"imdbVotes":192477,"tmdb":7.839,"tmdbVotes":4811}},{"id":"movie-the-last-of-the-mohicans-1992","title":"The Last of the Mohicans","year":1992,"type":"movie","runtimeSeconds":6874,"seasonCount":null,"communityRating":7.388,"criticRating":88,"genres":["History","War","Drama"],"overview":"In war-torn colonial America, in the midst of a bloody battle between British, the French and Native American allies, the aristocratic daughter of a British Colonel and her party are captured by a group of Huron\u2026","poster":"assets/movie-the-last-of-the-mohicans-1992-poster.jpg","backdrop":"assets/movie-the-last-of-the-mohicans-1992-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-10T20:59:22.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":9361,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":88,"rtCriticsLabel":"Certified Fresh","rtAudience":88,"rtAudienceLabel":"Upright","imdb":7.6,"imdbVotes":210791,"tmdb":7.39,"tmdbVotes":3593}},{"id":"movie-the-last-samurai-2003","title":"The Last Samurai","year":2003,"type":"movie","runtimeSeconds":9251,"seasonCount":null,"communityRating":7.61,"criticRating":65,"genres":["Drama","Action","War"],"overview":"Nathan Algren is an American hired to instruct the Japanese army in the ways of modern warfare, which finds him learning to respect the samurai and the honorable principles that rule them. Pressed to destroy the\u2026","poster":"assets/movie-the-last-samurai-2003-poster.jpg","backdrop":"assets/movie-the-last-samurai-2003-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-26T05:25:10.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":616,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":66,"rtCriticsLabel":"Fresh","rtAudience":83,"rtAudienceLabel":"Upright","imdb":7.8,"imdbVotes":512982,"tmdb":7.614,"tmdbVotes":7887}},{"id":"movie-lemony-snicket-s-a-series-of-unfortunate-events-2004","title":"Lemony Snicket's A Series of Unfortunate Events","year":2004,"type":"movie","runtimeSeconds":6479,"seasonCount":null,"communityRating":6.8,"criticRating":72,"genres":["Adventure","Comedy","Family"],"overview":"Three wealthy children's parents are killed in a fire. When they are sent to a distant relative, they find out that he is plotting to kill them and seize their fortune.","poster":"assets/movie-lemony-snicket-s-a-series-of-unfortunate-events-2004-poster.jpg","backdrop":"assets/movie-lemony-snicket-s-a-series-of-unfortunate-events-2004-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:26:09.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":11774,"artwork":{"posterKind":"center_crop","backdropKind":"backdrop"},"ratings":{"rtCritics":72,"rtCriticsLabel":"Fresh","rtAudience":63,"rtAudienceLabel":"Upright","imdb":6.8,"imdbVotes":233636,"tmdb":6.82,"tmdbVotes":5447}},{"id":"movie-the-lighthouse-2019","title":"The Lighthouse","year":2019,"type":"movie","runtimeSeconds":6549,"seasonCount":null,"communityRating":7.463,"criticRating":90,"genres":["Drama","Fantasy","Thriller"],"overview":"Two lighthouse keepers try to maintain their sanity while living on a remote and mysterious New England island in the 1890s.","poster":"assets/movie-the-lighthouse-2019-poster.jpg","backdrop":"assets/movie-the-lighthouse-2019-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:29:01.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":503919,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":90,"rtCriticsLabel":"Certified Fresh","rtAudience":72,"rtAudienceLabel":"Upright","imdb":7.3,"imdbVotes":312344,"tmdb":7.46,"tmdbVotes":5895}},{"id":"movie-locke-2014","title":"Locke","year":2014,"type":"movie","runtimeSeconds":5090,"seasonCount":null,"communityRating":6.888,"criticRating":91,"genres":["Drama","Thriller"],"overview":"Ivan Locke has worked hard to craft a good life for himself. Tonight, that life will collapse around him. On the eve of the biggest challenge of his career, Ivan receives a phone call that sets in motion a series of\u2026","poster":"assets/movie-locke-2014-poster.jpg","backdrop":"assets/movie-locke-2014-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T17:38:48.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":210479,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":90,"rtCriticsLabel":"Certified Fresh","rtAudience":72,"rtAudienceLabel":"Upright","imdb":7.1,"imdbVotes":171265,"tmdb":6.889,"tmdbVotes":3088}},{"id":"movie-the-matrix-1999","title":"The Matrix","year":1999,"type":"movie","runtimeSeconds":8179,"seasonCount":null,"communityRating":8.259,"criticRating":83,"genres":["Action","Science Fiction"],"overview":"Set in the 22nd century, The Matrix tells the story of a computer hacker who joins a group of underground insurgents fighting the vast and powerful computers who now rule the earth.","poster":"assets/movie-the-matrix-1999-poster.jpg","backdrop":"assets/movie-the-matrix-1999-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:18:12.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":603,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":83,"rtCriticsLabel":"Certified Fresh","rtAudience":85,"rtAudienceLabel":"Upright","imdb":8.7,"imdbVotes":2289808,"tmdb":8.262,"tmdbVotes":29153}},{"id":"movie-the-matrix-reloaded-2003","title":"The Matrix Reloaded","year":2003,"type":"movie","runtimeSeconds":8298,"seasonCount":null,"communityRating":7.085,"criticRating":74,"genres":["Adventure","Action","Thriller"],"overview":"The Resistance builds in numbers as humans are freed from the Matrix and brought to the city of Zion. Neo discovers his superpowers, including the ability to see the code inside the Matrix. With machine sentinels\u2026","poster":"assets/movie-the-matrix-reloaded-2003-poster.jpg","backdrop":"assets/movie-the-matrix-reloaded-2003-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:24:03.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":604,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":73,"rtCriticsLabel":"Certified Fresh","rtAudience":72,"rtAudienceLabel":"Upright","imdb":7.2,"imdbVotes":678013,"tmdb":7.087,"tmdbVotes":12504}},{"id":"movie-the-matrix-resurrections-2021","title":"The Matrix Resurrections","year":2021,"type":"movie","runtimeSeconds":8875,"seasonCount":null,"communityRating":6.303,"criticRating":63,"genres":["Science Fiction","Action","Adventure"],"overview":"Plagued by strange memories, Neo's life takes an unexpected turn when he finds himself back inside the Matrix.","poster":"assets/movie-the-matrix-resurrections-2021-poster.jpg","backdrop":"assets/movie-the-matrix-resurrections-2021-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:31:22.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":624860,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":63,"rtCriticsLabel":"Fresh","rtAudience":63,"rtAudienceLabel":"Upright","imdb":5.6,"imdbVotes":307780,"tmdb":6.294,"tmdbVotes":6842}},{"id":"movie-the-matrix-revolutions-2003","title":"The Matrix Revolutions","year":2003,"type":"movie","runtimeSeconds":7756,"seasonCount":null,"communityRating":6.758,"criticRating":33,"genres":["Adventure","Action","Thriller"],"overview":"The human city of Zion defends itself against the massive invasion of the machines as Neo fights to end the war at another front while also opposing the rogue Agent Smith.","poster":"assets/movie-the-matrix-revolutions-2003-poster.jpg","backdrop":"assets/movie-the-matrix-revolutions-2003-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:25:47.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":605,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":34,"rtCriticsLabel":"Rotten","rtAudience":60,"rtAudienceLabel":"Upright","imdb":6.8,"imdbVotes":581553,"tmdb":6.762,"tmdbVotes":11292}},{"id":"movie-mercy-2026","title":"Mercy","year":2026,"type":"movie","runtimeSeconds":5968,"seasonCount":null,"communityRating":7.077,"criticRating":null,"genres":["Science Fiction","Thriller","Crime"],"overview":"In the near future, a detective stands on trial accused of murdering his wife. He has ninety minutes to prove his innocence to the advanced AI Judge he once championed, before it determines his fate.","poster":"assets/movie-mercy-2026-poster.jpg","backdrop":"assets/movie-mercy-2026-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:31:40.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":1236153,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":24,"rtCriticsLabel":"Rotten","rtAudience":81,"rtAudienceLabel":"Upright","imdb":6.2,"imdbVotes":83878,"tmdb":7.054,"tmdbVotes":1812}},{"id":"movie-normal-2026","title":"Normal","year":2026,"type":"movie","runtimeSeconds":5514,"seasonCount":null,"communityRating":7.267,"criticRating":77,"genres":["Action","Crime","Thriller"],"overview":"An unassuming substitute sheriff with a troubled past responds to a bank robbery in a small, sleepy town and unknowingly uncovers something far more explosive.","poster":"assets/movie-normal-2026-poster.jpg","backdrop":"assets/movie-normal-2026-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-08-21T08:33:18.0000000Z","lastPlayedAt":"2026-09-24T23:07:52.1161581Z","availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":1242332,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":78,"rtCriticsLabel":"Certified Fresh","rtAudience":75,"rtAudienceLabel":"Upright","imdb":6.3,"imdbVotes":37501,"tmdb":7.241,"tmdbVotes":786}},{"id":"movie-outlaw-king-2018","title":"Outlaw King","year":2018,"type":"movie","runtimeSeconds":7297,"seasonCount":null,"communityRating":6.829,"criticRating":63,"genres":["Action","History","War"],"overview":"Forced into exile by the English after being crowned King of Scotland, legendary warrior Robert the Bruce fights to reclaim the throne.","poster":"assets/movie-outlaw-king-2018-poster.jpg","backdrop":"assets/movie-outlaw-king-2018-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:28:32.0000000Z","lastPlayedAt":"2026-07-26T22:35:35.0000000Z","availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":454227,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":63,"rtCriticsLabel":"Fresh","rtAudience":69,"rtAudienceLabel":"Upright","imdb":6.9,"imdbVotes":89876,"tmdb":6.844,"tmdbVotes":1780}},{"id":"movie-panic-room-2002","title":"Panic Room","year":2002,"type":"movie","runtimeSeconds":6717,"seasonCount":null,"communityRating":6.794,"criticRating":76,"genres":["Crime","Drama","Thriller"],"overview":"Trapped in their New York brownstone's panic room, a hidden chamber built as a sanctuary in the event of break-ins, newly divorced Meg Altman and her young daughter Sarah play a deadly game of cat-and-mouse with\u2026","poster":"assets/movie-panic-room-2002-poster.jpg","backdrop":"assets/movie-panic-room-2002-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-19T20:50:01.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":4547,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":76,"rtCriticsLabel":"Certified Fresh","rtAudience":64,"rtAudienceLabel":"Upright","imdb":6.8,"imdbVotes":317468,"tmdb":6.796,"tmdbVotes":5653}},{"id":"movie-the-patriot-2000","title":"The Patriot","year":2000,"type":"movie","runtimeSeconds":9887,"seasonCount":null,"communityRating":7.214,"criticRating":61,"genres":["Drama","History","War"],"overview":"After proving himself on the field of battle in the French and Indian War, Benjamin Martin wants nothing more to do with such things, preferring the simple life of a farmer. But when his son Gabriel enlists in the\u2026","poster":"assets/movie-the-patriot-2000-poster.jpg","backdrop":"assets/movie-the-patriot-2000-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-10T20:50:00.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":2024,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":61,"rtCriticsLabel":"Fresh","rtAudience":81,"rtAudienceLabel":"Upright","imdb":7.2,"imdbVotes":317639,"tmdb":7.215,"tmdbVotes":4535}},{"id":"movie-peaky-blinders-the-immortal-man-2026","title":"Peaky Blinders: The Immortal Man","year":2026,"type":"movie","runtimeSeconds":6844,"seasonCount":null,"communityRating":7.187,"criticRating":90,"genres":["Crime","Drama"],"overview":"After his estranged son gets embroiled in a Nazi plot, self-exiled gangster Tommy Shelby must return to Birmingham to save his family \u2014 and his nation.","poster":"assets/movie-peaky-blinders-the-immortal-man-2026-poster.jpg","backdrop":"assets/movie-peaky-blinders-the-immortal-man-2026-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:30:01.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":875828,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":90,"rtCriticsLabel":"Certified Fresh","rtAudience":87,"rtAudienceLabel":"Upright","imdb":6.5,"imdbVotes":92130,"tmdb":7.189,"tmdbVotes":1304}},{"id":"movie-ponyo-2008","title":"Ponyo","year":2008,"type":"movie","runtimeSeconds":6530,"seasonCount":null,"communityRating":7.763,"criticRating":91,"genres":["Animation","Fantasy","Family"],"overview":"When Sosuke, a young boy who lives on a clifftop overlooking the sea, rescues a stranded goldfish named Ponyo, he discovers more than he bargained for. Ponyo is a curious, energetic young creature who yearns to be\u2026","poster":"assets/movie-ponyo-2008-poster.jpg","backdrop":"assets/movie-ponyo-2008-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:23:53.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":12429,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":91,"rtCriticsLabel":"Certified Fresh","rtAudience":84,"rtAudienceLabel":"Upright","imdb":7.6,"imdbVotes":190294,"tmdb":7.759,"tmdbVotes":5050}},{"id":"movie-porco-rosso-1992","title":"Porco Rosso","year":1992,"type":"movie","runtimeSeconds":5600,"seasonCount":null,"communityRating":7.794,"criticRating":96,"genres":["Animation","Adventure","Fantasy"],"overview":"In Italy in the 1930s, sky pirates in biplanes terrorize wealthy cruise ships as they sail the Adriatic Sea. The only pilot brave enough to stop the scourge is the mysterious Porco Rosso, a former World War I flying\u2026","poster":"assets/movie-porco-rosso-1992-poster.jpg","backdrop":"assets/movie-porco-rosso-1992-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:23:22.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":11621,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":96,"rtCriticsLabel":"Fresh","rtAudience":87,"rtAudienceLabel":"Upright","imdb":7.7,"imdbVotes":119396,"tmdb":7.789,"tmdbVotes":3879}},{"id":"movie-princess-mononoke-1997","title":"Princess Mononoke","year":1997,"type":"movie","runtimeSeconds":8003,"seasonCount":null,"communityRating":8.321,"criticRating":93,"genres":["Adventure","Fantasy","Animation"],"overview":"Ashitaka, a prince of the disappearing Emishi people, is cursed by a demonized boar god and must journey to the west to find a cure. Along the way, he encounters San, a young human woman fighting to protect the\u2026","poster":"assets/movie-princess-mononoke-1997-poster.jpg","backdrop":"assets/movie-princess-mononoke-1997-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:22:28.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":128,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":94,"rtCriticsLabel":"Certified Fresh","rtAudience":99,"rtAudienceLabel":"Upright","imdb":8.3,"imdbVotes":493735,"tmdb":8.321,"tmdbVotes":9438}},{"id":"movie-prisoners-2013","title":"Prisoners","year":2013,"type":"movie","runtimeSeconds":9192,"seasonCount":null,"communityRating":8.106,"criticRating":81,"genres":["Drama","Thriller","Crime"],"overview":"After his six-year-old daughter is abducted, a desperate father takes justice into his own hands when he loses faith in the detective leading the investigation, setting both men on a collision course as the search\u2026","poster":"assets/movie-prisoners-2013-poster.jpg","backdrop":"assets/movie-prisoners-2013-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:27:33.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":146233,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":82,"rtCriticsLabel":"Certified Fresh","rtAudience":87,"rtAudienceLabel":"Upright","imdb":8.2,"imdbVotes":963062,"tmdb":8.105,"tmdbVotes":13722}},{"id":"movie-racing-stripes-2005","title":"Racing Stripes","year":2005,"type":"movie","runtimeSeconds":6117,"seasonCount":null,"communityRating":5.945,"criticRating":35,"genres":["Comedy","Family"],"overview":"Shattered illusions are hard to repair -- especially for a good-hearted zebra named Stripes who's spent his life on a Kentucky farm amidst the sorely mistaken notion that he's a debonair thoroughbred. Once he faces\u2026","poster":"assets/movie-racing-stripes-2005-poster.jpg","backdrop":"assets/movie-racing-stripes-2005-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:26:02.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":6439,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":35,"rtCriticsLabel":"Rotten","rtAudience":42,"rtAudienceLabel":"Spilled","imdb":5.3,"imdbVotes":19569,"tmdb":5.962,"tmdbVotes":705}},{"id":"movie-requiem-for-a-dream-2000","title":"Requiem for a Dream","year":2000,"type":"movie","runtimeSeconds":6086,"seasonCount":null,"communityRating":8.005,"criticRating":80,"genres":["Crime","Drama"],"overview":"The drug-induced utopias of four Coney Island residents are shattered when their addictions run deep.","poster":"assets/movie-requiem-for-a-dream-2000-poster.jpg","backdrop":"assets/movie-requiem-for-a-dream-2000-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:24:15.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":641,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":81,"rtCriticsLabel":"Certified Fresh","rtAudience":93,"rtAudienceLabel":"Upright","imdb":8.3,"imdbVotes":989090,"tmdb":8,"tmdbVotes":11454}},{"id":"movie-rogue-one-a-star-wars-story-2016","title":"Rogue One: A Star Wars Story","year":2016,"type":"movie","runtimeSeconds":8038,"seasonCount":null,"communityRating":7.51,"criticRating":84,"genres":["Action","Adventure","Science Fiction"],"overview":"A rogue band of resistance fighters unite for a mission to steal the Death Star plans and bring a new hope to the galaxy.","poster":"assets/movie-rogue-one-a-star-wars-story-2016-poster.jpg","backdrop":"assets/movie-rogue-one-a-star-wars-story-2016-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:28:00.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":330459,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":84,"rtCriticsLabel":"Certified Fresh","rtAudience":87,"rtAudienceLabel":"Upright","imdb":7.8,"imdbVotes":768365,"tmdb":7.512,"tmdbVotes":16937}},{"id":"movie-secondhand-lions-2003","title":"Secondhand Lions","year":2003,"type":"movie","runtimeSeconds":6547,"seasonCount":null,"communityRating":7.237,"criticRating":60,"genres":["Family","Comedy","Drama"],"overview":"The comedic adventures of an introverted boy left on the doorstep of a pair of reluctant, eccentric great-uncles, whose exotic remembrances stir the boy's spirit and re-ignite the men's lives.","poster":"assets/movie-secondhand-lions-2003-poster.jpg","backdrop":"assets/movie-secondhand-lions-2003-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-12T07:16:13.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":13156,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":59,"rtCriticsLabel":"Rotten","rtAudience":84,"rtAudienceLabel":"Upright","imdb":7.5,"imdbVotes":66911,"tmdb":7.242,"tmdbVotes":872}},{"id":"movie-the-secret-life-of-pets-2-2019","title":"The Secret Life of Pets 2","year":2019,"type":"movie","runtimeSeconds":5164,"seasonCount":null,"communityRating":6.95,"criticRating":60,"genres":["Animation","Comedy","Family"],"overview":"Max the terrier must cope with some major life changes when his owner gets married and has a baby. When the family takes a trip to the countryside, nervous Max has numerous run-ins with canine-intolerant cows,\u2026","poster":"assets/movie-the-secret-life-of-pets-2-2019-poster.jpg","backdrop":"assets/movie-the-secret-life-of-pets-2-2019-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-05T07:00:53.0000000Z","lastPlayedAt":"2026-09-17T18:07:00.7024231Z","availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":412117,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":60,"rtCriticsLabel":"Fresh","rtAudience":90,"rtAudienceLabel":"Upright","imdb":6.4,"imdbVotes":80464,"tmdb":6.948,"tmdbVotes":3450}},{"id":"movie-self-reliance-2024","title":"Self Reliance","year":2024,"type":"movie","runtimeSeconds":5461,"seasonCount":null,"communityRating":5.888,"criticRating":73,"genres":["Comedy","Thriller"],"overview":"When a man is offered a million dollars to play a game in which hunters try to kill him, he thinks he has found the perfect loophole: they can only attack when he\u2019s alone. His only problem is that none of his friends\u2026","poster":"assets/movie-self-reliance-2024-poster.jpg","backdrop":"assets/movie-self-reliance-2024-backdrop.jpg","played":false,"playCount":1,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:31:00.0000000Z","lastPlayedAt":"2026-10-02T19:59:16.9286868Z","availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":1072876,"artwork":{"posterKind":"center_crop","backdropKind":"backdrop"},"ratings":{"rtCritics":73,"rtCriticsLabel":"Certified Fresh","rtAudience":56,"rtAudienceLabel":"Spilled","imdb":6,"imdbVotes":23771,"tmdb":5.866,"tmdbVotes":346}},{"id":"movie-serpico-1973","title":"Serpico","year":1973,"type":"movie","runtimeSeconds":7805,"seasonCount":null,"communityRating":7.5,"criticRating":93,"genres":["Crime","Drama","History"],"overview":"New York cop Frank Serpico blows the whistle on the rampant corruption in the force only to have his comrades turn against him.","poster":"assets/movie-serpico-1973-poster.jpg","backdrop":"assets/movie-serpico-1973-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-10T21:45:02.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":9040,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":93,"rtCriticsLabel":"Certified Fresh","rtAudience":88,"rtAudienceLabel":"Upright","imdb":7.7,"imdbVotes":149750,"tmdb":7.525,"tmdbVotes":2323}},{"id":"movie-shaft-2000","title":"Shaft","year":2000,"type":"movie","runtimeSeconds":5960,"seasonCount":null,"communityRating":6.026,"criticRating":67,"genres":["Action","Adventure","Crime"],"overview":"New York police detective John Shaft arrests Walter Wade Jr. for a racially motivated slaying. But the only eyewitness disappears, and Wade jumps bail for Switzerland. Two years later Wade returns to face trial,\u2026","poster":"assets/movie-shaft-2000-poster.jpg","backdrop":"assets/movie-shaft-2000-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-10T21:30:40.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":479,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":68,"rtCriticsLabel":"Fresh","rtAudience":40,"rtAudienceLabel":"Spilled","imdb":6,"imdbVotes":86257,"tmdb":6.024,"tmdbVotes":1531}},{"id":"movie-a-silent-voice-the-movie-2016","title":"A Silent Voice: The Movie","year":2016,"type":"movie","runtimeSeconds":7804,"seasonCount":null,"communityRating":8.398,"criticRating":null,"genres":["Animation","Drama","Romance"],"overview":"Shouya Ishida starts bullying the new girl in class, Shouko Nishimiya, because she is deaf. But as the teasing continues, the rest of the class starts to turn on Shouya for his lack of compassion. When they leave\u2026","poster":"assets/movie-a-silent-voice-the-movie-2016-poster.jpg","backdrop":"assets/movie-a-silent-voice-the-movie-2016-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T17:39:46.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":378064,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":95,"rtCriticsLabel":"Fresh","rtAudience":94,"rtAudienceLabel":"Upright","imdb":8.2,"imdbVotes":151926,"tmdb":8.396,"tmdbVotes":4764}},{"id":"movie-sinbad-legend-of-the-seven-seas-2003","title":"Sinbad: Legend of the Seven Seas","year":2003,"type":"movie","runtimeSeconds":5143,"seasonCount":null,"communityRating":7.067,"criticRating":44,"genres":["Action","Adventure","Animation"],"overview":"The sailor of legend is framed by the goddess Eris for the theft of the Book of Peace, and must travel to her realm at the end of the world to retrieve it and save the life of his childhood friend Prince Proteus.","poster":"assets/movie-sinbad-legend-of-the-seven-seas-2003-poster.jpg","backdrop":"assets/movie-sinbad-legend-of-the-seven-seas-2003-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:26:25.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":14411,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":46,"rtCriticsLabel":"Rotten","rtAudience":57,"rtAudienceLabel":"Spilled","imdb":6.8,"imdbVotes":65298,"tmdb":7.071,"tmdbVotes":2323}},{"id":"movie-sleeping-with-other-people-2015","title":"Sleeping with Other People","year":2015,"type":"movie","runtimeSeconds":6076,"seasonCount":null,"communityRating":6.274,"criticRating":64,"genres":["Comedy","Romance"],"overview":"Can two serial cheaters get a second chance at love? After a one-night stand in college, New Yorkers Lainey and Jake meet by chance twelve years later and discover they each have the same problem: because of their\u2026","poster":"assets/movie-sleeping-with-other-people-2015-poster.jpg","backdrop":"assets/movie-sleeping-with-other-people-2015-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:27:42.0000000Z","lastPlayedAt":"2026-07-17T17:50:44.0000000Z","availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":288036,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":64,"rtCriticsLabel":"Fresh","rtAudience":56,"rtAudienceLabel":"Spilled","imdb":6.5,"imdbVotes":52275,"tmdb":6.275,"tmdbVotes":1020}},{"id":"movie-snowpiercer-2013","title":"Snowpiercer","year":2013,"type":"movie","runtimeSeconds":7573,"seasonCount":null,"communityRating":6.909,"criticRating":94,"genres":["Action","Science Fiction","Drama"],"overview":"In a future where a failed global-warming experiment kills off most life on the planet, a class system evolves aboard the Snowpiercer; a train that travels around the globe via a perpetual-motion engine.","poster":"assets/movie-snowpiercer-2013-poster.jpg","backdrop":"assets/movie-snowpiercer-2013-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:27:07.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":110415,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":94,"rtCriticsLabel":"Certified Fresh","rtAudience":72,"rtAudienceLabel":"Upright","imdb":7.1,"imdbVotes":426976,"tmdb":6.9,"tmdbVotes":10807}},{"id":"movie-spider-man-brand-new-day-2026","title":"Spider-Man: Brand New Day","year":2026,"type":"movie","runtimeSeconds":8701,"seasonCount":null,"communityRating":8.374,"criticRating":90,"genres":["Science Fiction","Action","Adventure"],"overview":"Fighting crime full-time as Spider-Man in a world that doesn't remember him\u2014and the pressure of seeing his old friends move on without him\u2014sparks a change in Peter Parker he may not have the power to control. But\u2026","poster":"assets/movie-spider-man-brand-new-day-2026-poster.jpg","backdrop":"assets/movie-spider-man-brand-new-day-2026-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-10T14:14:27.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":969681,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":90,"rtCriticsLabel":"Certified Fresh","rtAudience":97,"rtAudienceLabel":"Upright","imdb":7.9,"imdbVotes":366886,"tmdb":8.5,"tmdbVotes":6537}},{"id":"movie-spider-man-far-from-home-2019","title":"Spider-Man: Far From Home","year":2019,"type":"movie","runtimeSeconds":7762,"seasonCount":null,"communityRating":7.389,"criticRating":91,"genres":["Action","Adventure","Science Fiction"],"overview":"Peter Parker and his friends go on a summer trip to Europe. However, they will hardly be able to rest - Peter will have to agree to help Nick Fury uncover the mystery of creatures that cause natural disasters and\u2026","poster":"assets/movie-spider-man-far-from-home-2019-poster.jpg","backdrop":"assets/movie-spider-man-far-from-home-2019-backdrop.jpg","played":true,"playCount":1,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-10T14:25:47.0000000Z","lastPlayedAt":"2026-10-10T17:50:35.6193119Z","availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":429617,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":91,"rtCriticsLabel":"Certified Fresh","rtAudience":95,"rtAudienceLabel":"Upright","imdb":7.3,"imdbVotes":682887,"tmdb":7.387,"tmdbVotes":17847}},{"id":"movie-spider-man-homecoming-2017","title":"Spider-Man: Homecoming","year":2017,"type":"movie","runtimeSeconds":8008,"seasonCount":null,"communityRating":7.333,"criticRating":92,"genres":["Action","Adventure","Science Fiction"],"overview":"Following the events of Captain America: Civil War, Peter Parker, with the help of his mentor Tony Stark, tries to balance his life as an ordinary high school student in Queens, New York City, with fighting crime as\u2026","poster":"assets/movie-spider-man-homecoming-2017-poster.jpg","backdrop":"assets/movie-spider-man-homecoming-2017-backdrop.jpg","played":true,"playCount":1,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-10T14:33:13.0000000Z","lastPlayedAt":"2026-10-10T20:31:23.4444213Z","availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":315635,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":92,"rtCriticsLabel":"Certified Fresh","rtAudience":87,"rtAudienceLabel":"Upright","imdb":7.4,"imdbVotes":840974,"tmdb":7.332,"tmdbVotes":24183}},{"id":"movie-spider-man-no-way-home-2021","title":"Spider-Man: No Way Home","year":2021,"type":"movie","runtimeSeconds":8890,"seasonCount":null,"communityRating":7.947,"criticRating":93,"genres":["Action","Adventure","Science Fiction"],"overview":"Peter Parker is unmasked and no longer able to separate his normal life from the high-stakes of being a super-hero. When he asks for help from Doctor Strange the stakes become even more dangerous, forcing him to\u2026","poster":"assets/movie-spider-man-no-way-home-2021-poster.jpg","backdrop":"assets/movie-spider-man-no-way-home-2021-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-10T14:21:05.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":634649,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":93,"rtCriticsLabel":"Certified Fresh","rtAudience":97,"rtAudienceLabel":"Upright","imdb":8.1,"imdbVotes":1082660,"tmdb":7.947,"tmdbVotes":23505}},{"id":"movie-spirited-away-2001","title":"Spirited Away","year":2001,"type":"movie","runtimeSeconds":7472,"seasonCount":null,"communityRating":8.535,"criticRating":96,"genres":["Animation","Family","Fantasy"],"overview":"A young girl, Chihiro, becomes trapped in a strange new world of spirits. When her parents undergo a mysterious transformation, she must call upon the courage she never knew she had to free her family.","poster":"assets/movie-spirited-away-2001-poster.jpg","backdrop":"assets/movie-spirited-away-2001-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:22:42.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":129,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":96,"rtCriticsLabel":"Certified Fresh","rtAudience":99,"rtAudienceLabel":"Upright","imdb":8.6,"imdbVotes":987658,"tmdb":8.536,"tmdbVotes":19176}},{"id":"movie-the-substance-2024","title":"The Substance","year":2024,"type":"movie","runtimeSeconds":8531,"seasonCount":null,"communityRating":7.135,"criticRating":89,"genres":["Horror","Science Fiction"],"overview":"A fading celebrity decides to use a black market drug, a cell-replicating substance that temporarily creates a younger, better version of herself.","poster":"assets/movie-the-substance-2024-poster.jpg","backdrop":"assets/movie-the-substance-2024-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:30:22.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":933260,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":89,"rtCriticsLabel":"Certified Fresh","rtAudience":76,"rtAudienceLabel":"Upright","imdb":7.2,"imdbVotes":466542,"tmdb":7.13,"tmdbVotes":6746}},{"id":"movie-the-tale-of-the-princess-kaguya-2013","title":"The Tale of The Princess Kaguya","year":2013,"type":"movie","runtimeSeconds":8218,"seasonCount":null,"communityRating":8.1,"criticRating":100,"genres":["Animation","Drama","Fantasy"],"overview":"Found inside a shining stalk of bamboo by an old bamboo cutter and his wife, a tiny girl grows rapidly into an exquisite young lady. The mysterious young princess enthrals all who encounter her. But, ultimately, she\u2026","poster":"assets/movie-the-tale-of-the-princess-kaguya-2013-poster.jpg","backdrop":"assets/movie-the-tale-of-the-princess-kaguya-2013-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-07T13:40:15.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":149871,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Certified Fresh","rtAudience":90,"rtAudienceLabel":"Upright","imdb":8,"imdbVotes":63574,"tmdb":8.083,"tmdbVotes":2079}},{"id":"movie-taxi-driver-1976","title":"Taxi Driver","year":1976,"type":"movie","runtimeSeconds":6831,"seasonCount":null,"communityRating":8.121,"criticRating":89,"genres":["Crime","Drama"],"overview":"Suffering from insomnia, disturbed loner Travis Bickle takes a job as a New York City cabbie, haunting the streets nightly, growing increasingly detached from reality as he dreams of cleaning up the filthy city.","poster":"assets/movie-taxi-driver-1976-poster.jpg","backdrop":"assets/movie-taxi-driver-1976-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:23:04.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":103,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":89,"rtCriticsLabel":"Certified Fresh","rtAudience":93,"rtAudienceLabel":"Upright","imdb":8.2,"imdbVotes":1046700,"tmdb":8.116,"tmdbVotes":13973}},{"id":"movie-triangle-of-sadness-2022","title":"Triangle of Sadness","year":2022,"type":"movie","runtimeSeconds":8833,"seasonCount":null,"communityRating":7.005,"criticRating":71,"genres":["Comedy","Drama"],"overview":"A celebrity model couple are invited on a luxury cruise for the uber-rich, helmed by an unhinged, alcoholic captain. What first appears Instagrammable ends catastrophically, leaving the survivors stranded on a desert\u2026","poster":"assets/movie-triangle-of-sadness-2022-poster.jpg","backdrop":"assets/movie-triangle-of-sadness-2022-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:29:00.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":497828,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":72,"rtCriticsLabel":"Fresh","rtAudience":80,"rtAudienceLabel":"Upright","imdb":7.2,"imdbVotes":221069,"tmdb":7,"tmdbVotes":3104}},{"id":"movie-tsotsi-2005","title":"Tsotsi","year":2005,"type":"movie","runtimeSeconds":5663,"seasonCount":null,"communityRating":6.937,"criticRating":82,"genres":["Crime","Drama"],"overview":"A young South African boy from the Johannesburg ghetto named Tsotsi, meaning Gangster, leaves home as a child to get away from his helpless parents. Now a teenage thug, Tsotsi finds a baby in the back seat of a car\u2026","poster":"assets/movie-tsotsi-2005-poster.jpg","backdrop":"assets/movie-tsotsi-2005-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:24:58.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":868,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":82,"rtCriticsLabel":"Certified Fresh","rtAudience":86,"rtAudienceLabel":"Upright","imdb":7.2,"imdbVotes":32526,"tmdb":6.941,"tmdbVotes":372}},{"id":"movie-unknown-number-the-high-school-catfish-2025","title":"Unknown Number: The High School Catfish","year":2025,"type":"movie","runtimeSeconds":5691,"seasonCount":null,"communityRating":6.746,"criticRating":85,"genres":["Documentary"],"overview":"Vulgar, taunting texts blow up the phones of a teen and her boyfriend. Who's sending them \u2014 and why? This twisty documentary reveals the shocking answer.","poster":"assets/movie-unknown-number-the-high-school-catfish-2025-poster.jpg","backdrop":"assets/movie-unknown-number-the-high-school-catfish-2025-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:32:10.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":1517772,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":85,"rtCriticsLabel":"Fresh","rtAudience":69,"rtAudienceLabel":"Upright","imdb":6.7,"imdbVotes":23039,"tmdb":6.737,"tmdbVotes":257}},{"id":"movie-the-uprising-2026","title":"The Uprising","year":2026,"type":"movie","runtimeSeconds":7684,"seasonCount":null,"communityRating":7.846,"criticRating":55,"genres":["Action","Drama","History"],"overview":"As war and plague devastate 14th-century England, a humble peasant ignites a rebellion, uniting an army of commoners to defy the King\u2019s might in a desperate fight for justice and survival.","poster":"assets/movie-the-uprising-2026-poster.jpg","backdrop":"assets/movie-the-uprising-2026-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-11-02T16:37:03.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":977942,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":57,"rtCriticsLabel":"Rotten","rtAudience":65,"rtAudienceLabel":"Upright","imdb":6.2,"imdbVotes":6622,"tmdb":7.8,"tmdbVotes":404}},{"id":"movie-vice-2018","title":"Vice","year":2018,"type":"movie","runtimeSeconds":7948,"seasonCount":null,"communityRating":7.013,"criticRating":64,"genres":["Drama","Comedy","History"],"overview":"George W. Bush picks Dick Cheney, the CEO of Halliburton Co., to be his Republican running mate in the 2000 presidential election. No stranger to politics, Cheney's impressive r\u00e9sum\u00e9 includes stints as White House\u2026","poster":"assets/movie-vice-2018-poster.jpg","backdrop":"assets/movie-vice-2018-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:28:30.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":429197,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":64,"rtCriticsLabel":"Fresh","rtAudience":61,"rtAudienceLabel":"Upright","imdb":7.2,"imdbVotes":177299,"tmdb":7.014,"tmdbVotes":3723}},{"id":"movie-warriors-of-the-wind-1984","title":"Warriors of the Wind","year":1984,"type":"movie","runtimeSeconds":7022,"seasonCount":null,"communityRating":7.941,"criticRating":87,"genres":["Adventure","Animation","Fantasy"],"overview":"After a global war, the seaside kingdom known as the Valley of the Wind remains one of the last strongholds on Earth untouched by a poisonous jungle and the powerful insects that guard it. Led by the courageous\u2026","poster":"assets/movie-warriors-of-the-wind-1984-poster.jpg","backdrop":"assets/movie-warriors-of-the-wind-1984-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:22:20.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":81,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":87,"rtCriticsLabel":"Fresh","rtAudience":91,"rtAudienceLabel":"Upright","imdb":8,"imdbVotes":200154,"tmdb":7.94,"tmdbVotes":4260}},{"id":"movie-we-bury-the-dead-2026","title":"We Bury the Dead","year":2026,"type":"movie","runtimeSeconds":5693,"seasonCount":null,"communityRating":6.153,"criticRating":87,"genres":["Horror","Thriller"],"overview":"After a catastrophic military disaster reanimates the dead, Ava searches for her missing husband amidst an increasingly hostile world.","poster":"assets/movie-we-bury-the-dead-2026-poster.jpg","backdrop":"assets/movie-we-bury-the-dead-2026-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-08-26T05:36:00.4272328Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":1198984,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":87,"rtCriticsLabel":"Certified Fresh","rtAudience":45,"rtAudienceLabel":"Spilled","imdb":5.6,"imdbVotes":20693,"tmdb":6.137,"tmdbVotes":433}},{"id":"movie-white-hot-the-rise-fall-of-abercrombie-fitch-2022","title":"White Hot: The Rise & Fall of Abercrombie & Fitch","year":2022,"type":"movie","runtimeSeconds":5187,"seasonCount":null,"communityRating":5.663,"criticRating":66,"genres":["Documentary"],"overview":"All the cool kids were wearing it. This documentary explores A&F's pop culture reign in the late '90s and early 2000s and how it thrived on exclusion.","poster":"assets/movie-white-hot-the-rise-fall-of-abercrombie-fitch-2022-poster.jpg","backdrop":"assets/movie-white-hot-the-rise-fall-of-abercrombie-fitch-2022-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:30:34.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":953371,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":66,"rtCriticsLabel":"Fresh","rtAudience":29,"rtAudienceLabel":"Spilled","imdb":5.8,"imdbVotes":5655,"tmdb":5.7,"tmdbVotes":102}},{"id":"movie-the-wild-robot-2024","title":"The Wild Robot","year":2024,"type":"movie","runtimeSeconds":6101,"seasonCount":null,"communityRating":8.308,"criticRating":97,"genres":["Family","Animation","Science Fiction"],"overview":"After a shipwreck, an intelligent robot called Roz is stranded on an uninhabited island. To survive the harsh environment, Roz bonds with the island's animals and cares for an orphaned baby goose.","poster":"assets/movie-the-wild-robot-2024-poster.jpg","backdrop":"assets/movie-the-wild-robot-2024-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:31:49.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":1184918,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":97,"rtCriticsLabel":"Certified Fresh","rtAudience":98,"rtAudienceLabel":"Upright","imdb":8.1,"imdbVotes":241134,"tmdb":8.309,"tmdbVotes":6819}},{"id":"movie-the-wind-rises-2013","title":"The Wind Rises","year":2013,"type":"movie","runtimeSeconds":8031,"seasonCount":null,"communityRating":7.784,"criticRating":88,"genres":["Animation","Drama","History"],"overview":"A lifelong love of flight inspires Japanese aviation engineer Jiro Horikoshi, whose storied career includes the creation of the A-6M World War II fighter plane.","poster":"assets/movie-the-wind-rises-2013-poster.jpg","backdrop":"assets/movie-the-wind-rises-2013-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T10:24:38.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":149870,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":89,"rtCriticsLabel":"Certified Fresh","rtAudience":85,"rtAudienceLabel":"Upright","imdb":7.8,"imdbVotes":115756,"tmdb":7.783,"tmdbVotes":3536}},{"id":"movie-the-witcher-nightmare-of-the-wolf-2021","title":"The Witcher: Nightmare of the Wolf","year":2021,"type":"movie","runtimeSeconds":5015,"seasonCount":null,"communityRating":7.422,"criticRating":100,"genres":["Animation","Action","Fantasy"],"overview":"Escaping from poverty to become a witcher, Vesemir slays monsters for coin and glory, but when a new menace rises, he must face the demons of his past.","poster":"assets/movie-the-witcher-nightmare-of-the-wolf-2021-poster.jpg","backdrop":"assets/movie-the-witcher-nightmare-of-the-wolf-2021-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-26T04:42:03.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":666243,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":83,"rtAudienceLabel":"Upright","imdb":7.2,"imdbVotes":55759,"tmdb":7.407,"tmdbVotes":1159}},{"id":"movie-the-witcher-sirens-of-the-deep-2025","title":"The Witcher: Sirens of the Deep","year":2025,"type":"movie","runtimeSeconds":5517,"seasonCount":null,"communityRating":6.8,"criticRating":60,"genres":["Animation","Fantasy","Action"],"overview":"When human sailors are attacked by mysterious creatures of the deep, only one person can stop the war between land and sea: the Witcher, Geralt of Rivia.","poster":"assets/movie-the-witcher-sirens-of-the-deep-2025-poster.jpg","backdrop":"assets/movie-the-witcher-sirens-of-the-deep-2025-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-26T05:03:26.0000000Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":1203329,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":60,"rtCriticsLabel":"Fresh","rtAudience":37,"rtAudienceLabel":"Spilled","imdb":6.1,"imdbVotes":11799,"tmdb":6.741,"tmdbVotes":303}}],"shows":[{"id":"tv-adults-2025","title":"Adults","year":2025,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":6.495,"criticRating":null,"genres":["Comedy"],"overview":"A group of twenty-somethings in New York trying to be good people, despite being neither \"good\" nor \"people\" yet.","poster":"assets/tv-adults-2025-poster.jpg","backdrop":"assets/tv-adults-2025-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-23T21:01:41.1814765Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":260458,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":88,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.5,"tmdbVotes":102}},{"id":"tv-american-crime-story-2016","title":"American Crime Story","year":2016,"type":"tv","runtimeSeconds":null,"seasonCount":3,"communityRating":7.573,"criticRating":null,"genres":["Crime","Drama"],"overview":"An anthology series centered around some of history's most famous criminal investigations.","poster":"assets/tv-american-crime-story-2016-poster.jpg","backdrop":"assets/tv-american-crime-story-2016-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0490488Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":64513,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":84,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.585,"tmdbVotes":1094}},{"id":"tv-american-primeval-2025","title":"American Primeval","year":2025,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":7.691,"criticRating":null,"genres":["Western","Drama","Action & Adventure"],"overview":"A mother and son fleeing from their past form a found family while confronting a harsh landscape of freedom and cruelty in the American West.","poster":"assets/tv-american-primeval-2025-poster.jpg","backdrop":"assets/tv-american-primeval-2025-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0573221Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":215866,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":71,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.741,"tmdbVotes":538}},{"id":"tv-arrested-development-2003","title":"Arrested Development","year":2003,"type":"tv","runtimeSeconds":null,"seasonCount":5,"communityRating":7.925,"criticRating":null,"genres":["Comedy"],"overview":"The story of a wealthy family that lost everything, and the one son who had no choice but to keep them all together.","poster":"assets/tv-arrested-development-2003-poster.jpg","backdrop":"assets/tv-arrested-development-2003-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0513048Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":4589,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":75,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.906,"tmdbVotes":1793}},{"id":"tv-avatar-the-last-airbender-2005","title":"Avatar: The Last Airbender","year":2005,"type":"tv","runtimeSeconds":1440,"seasonCount":3,"communityRating":8.78,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"In a war-torn world of elemental magic, a young boy reawakens to undertake a dangerous mystic quest to fulfill his destiny as the Avatar, and bring peace to the world.","poster":"assets/tv-avatar-the-last-airbender-2005-poster.jpg","backdrop":"assets/tv-avatar-the-last-airbender-2005-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0504536Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":246,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.787,"tmdbVotes":5215}},{"id":"tv-b-b-vol-liefde-2021","title":"B&B Vol Liefde","year":2021,"type":"tv","runtimeSeconds":3720,"seasonCount":1,"communityRating":7.2,"criticRating":null,"genres":["Reality"],"overview":"B&B Vol Liefde is a heartwarming adventure, full of romance, excitement, and unforgettable moments. Adventurous Dutch B&B owners abroad throw their doors wide open and let their hearts speak, determined to find that\u2026","poster":"assets/tv-b-b-vol-liefde-2021-poster.jpg","backdrop":"assets/tv-b-b-vol-liefde-2021-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-31T22:30:11.129657Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":124428,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.2,"tmdbVotes":10}},{"id":"tv-the-bear-2022","title":"The Bear","year":2022,"type":"tv","runtimeSeconds":null,"seasonCount":5,"communityRating":8.139,"criticRating":null,"genres":["Drama","Comedy"],"overview":"Carmy, a young fine-dining chef, comes home to Chicago to run his family sandwich shop. As he fights to transform the shop and himself, he works alongside a rough-around-the-edges crew that ultimately reveal\u2026","poster":"assets/tv-the-bear-2022-poster.jpg","backdrop":"assets/tv-the-bear-2022-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0467371Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":136315,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":93,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.158,"tmdbVotes":2025}},{"id":"tv-blue-planet-ii-2017","title":"Blue Planet II","year":2017,"type":"tv","runtimeSeconds":3600,"seasonCount":1,"communityRating":8.64,"criticRating":null,"genres":["Documentary","Family"],"overview":"There is nowhere more powerful and unforgiving yet more beautiful and compelling than the ocean. Join us and explore the greatest yet least known parts of our planet.","poster":"assets/tv-blue-planet-ii-2017-poster.jpg","backdrop":"assets/tv-blue-planet-ii-2017-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0634849Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":74313,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":97,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.6,"tmdbVotes":380}},{"id":"tv-breeders-2020","title":"Breeders","year":2020,"type":"tv","runtimeSeconds":1500,"seasonCount":4,"communityRating":6.8,"criticRating":null,"genres":["Comedy"],"overview":"Exposing the parental-paradox that it is possible, in the very same moment, to love your child to the horizon of the universe, while being apoplectically angry enough to want to send them there.","poster":"assets/tv-breeders-2020-poster.jpg","backdrop":"assets/tv-breeders-2020-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-28T18:54:21.8885435Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":93290,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":92,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.8,"tmdbVotes":104}},{"id":"tv-chernobyl-2019","title":"Chernobyl","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":8.718,"criticRating":null,"genres":["Drama"],"overview":"The true story of one of the worst man-made catastrophes in history: the catastrophic nuclear accident at Chernobyl. A tale of the brave men and women who sacrificed to save Europe from unimaginable disaster.","poster":"assets/tv-chernobyl-2019-poster.jpg","backdrop":"assets/tv-chernobyl-2019-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0469903Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":87108,"artwork":{"posterKind":"poster","backdropKind":"center_crop"},"ratings":{"rtCritics":95,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.731,"tmdbVotes":8496}},{"id":"tv-community-2009","title":"Community","year":2009,"type":"tv","runtimeSeconds":null,"seasonCount":6,"communityRating":7.997,"criticRating":null,"genres":["Comedy"],"overview":"Follow the lives of a group of students at what is possibly the world\u2019s worst community college in the fictional locale of Greendale, Colorado.","poster":"assets/tv-community-2009-poster.jpg","backdrop":"assets/tv-community-2009-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0531416Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":18347,"artwork":{"posterKind":"center_crop","backdropKind":"backdrop"},"ratings":{"rtCritics":88,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.994,"tmdbVotes":2226}},{"id":"tv-dead-end-job-2026","title":"Dead-End Job","year":2026,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":7.7,"criticRating":null,"genres":["Mystery"],"overview":"Drowning in debt, a young man takes lucrative part-time jobs from a mysterious agency \u2014 only to find his hustle for more money turning nightmarish.","poster":"assets/tv-dead-end-job-2026-poster.jpg","backdrop":"assets/tv-dead-end-job-2026-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-11-04T18:58:01.8352857Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":289517,"artwork":{"posterKind":"center_crop","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.7,"tmdbVotes":38}},{"id":"tv-dopesick-2021","title":"Dopesick","year":2021,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":8.015,"criticRating":null,"genres":["Crime","Drama"],"overview":"The story of how one company triggered the worst drug epidemic in American history. Look into the epicenter of America's struggle with opioid addiction, from a distressed Virginia mining community, to the hallways of\u2026","poster":"assets/tv-dopesick-2021-poster.jpg","backdrop":"assets/tv-dopesick-2021-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0580168Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":110695,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":89,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.035,"tmdbVotes":565}},{"id":"tv-dune-prophecy-2024","title":"Dune: Prophecy","year":2024,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":7.213,"criticRating":null,"genres":["Sci-Fi & Fantasy","Drama","Action & Adventure"],"overview":"Ten thousand years before the ascension of Paul Atreides, sisters Valya and Tula Harkonnen establish the fabled sect and female order that would become known as the Bene Gesserit to control the future of humankind.","poster":"assets/tv-dune-prophecy-2024-poster.jpg","backdrop":"assets/tv-dune-prophecy-2024-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-11-04T18:23:01.2908568Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":90228,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":64,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.213,"tmdbVotes":677}},{"id":"tv-east-of-eden-2026","title":"East of Eden","year":2026,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":7.931,"criticRating":null,"genres":["Drama","Crime"],"overview":"In the early 1900s, a fiercely independent woman drives a rift between two brothers, igniting a saga that unfolds across two generations.","poster":"assets/tv-east-of-eden-2026-poster.jpg","backdrop":"assets/tv-east-of-eden-2026-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-23T18:07:11.3965096Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":258165,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":88,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.982,"tmdbVotes":139}},{"id":"tv-fallout-2024","title":"Fallout","year":2024,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":8.124,"criticRating":null,"genres":["Action & Adventure","Sci-Fi & Fantasy","Drama"],"overview":"The story of haves and have-nots in a world in which there's almost nothing left to have. 200 years after the apocalypse, the gentle denizens of luxury fallout shelters are forced to return to the irradiated\u2026","poster":"assets/tv-fallout-2024-poster.jpg","backdrop":"assets/tv-fallout-2024-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0669262Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":106379,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":94,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.106,"tmdbVotes":3233}},{"id":"tv-fawlty-towers-1975","title":"Fawlty Towers","year":1975,"type":"tv","runtimeSeconds":1800,"seasonCount":2,"communityRating":8.295,"criticRating":null,"genres":["Comedy"],"overview":"Owner Basil Fawlty, his wife Sybil, a chambermaid Polly, and Spanish waiter Manuel attempt to run their hotel amidst farcical situations and an array of demanding guests.","poster":"assets/tv-fawlty-towers-1975-poster.jpg","backdrop":"assets/tv-fawlty-towers-1975-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-19T23:26:39.7658344Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":2207,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.296,"tmdbVotes":867}},{"id":"tv-the-final-problem-2026","title":"The Final Problem","year":2026,"type":"tv","runtimeSeconds":3420,"seasonCount":1,"communityRating":7.041,"criticRating":null,"genres":["Crime","Mystery"],"overview":"In the spring of 1959, a retired actor, who previously played Sherlock Holmes, must investigate a murder at a small hotel on a tiny island near Mallorca.","poster":"assets/tv-the-final-problem-2026-poster.jpg","backdrop":"assets/tv-the-final-problem-2026-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-11-04T19:16:12.4822791Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":290720,"artwork":{"posterKind":"center_crop","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.041,"tmdbVotes":49}},{"id":"tv-the-four-seasons-2025","title":"The Four Seasons","year":2025,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":6.879,"criticRating":null,"genres":["Comedy"],"overview":"The decades-long friendship between three married couples is tested when one divorces, complicating their tradition of quarterly weekend getaways.","poster":"assets/tv-the-four-seasons-2025-poster.jpg","backdrop":"assets/tv-the-four-seasons-2025-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-28T18:36:42.5326384Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":243316,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":81,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.892,"tmdbVotes":204}},{"id":"tv-the-get-down-2016","title":"The Get Down","year":2016,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":7.3,"criticRating":null,"genres":["Drama"],"overview":"In 1977 New York City, the talented and soulful youth of the South Bronx chase dreams and breakneck beats to transform music history.","poster":"assets/tv-the-get-down-2016-poster.jpg","backdrop":"assets/tv-the-get-down-2016-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0497737Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":65345,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":81,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.3,"tmdbVotes":196}},{"id":"tv-how-to-change-your-mind-2022","title":"How to Change Your Mind","year":2022,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":7.76,"criticRating":null,"genres":["Documentary","Mystery"],"overview":"Author Michael Pollan leads the way in this docuseries exploring the history and uses of psychedelics, including LSD, psilocybin, MDMA and mescaline.","poster":"assets/tv-how-to-change-your-mind-2022-poster.jpg","backdrop":"assets/tv-how-to-change-your-mind-2022-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0601399Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":204304,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.8,"tmdbVotes":53}},{"id":"tv-interrogation-2020","title":"Interrogation","year":2020,"type":"tv","runtimeSeconds":2700,"seasonCount":1,"communityRating":6.788,"criticRating":null,"genres":["Drama","Crime"],"overview":"Based on a true story that spanned more than 30 years in which a young man was charged and convicted of brutally murdering his mother. Each episode is structured around an interrogation taken directly from the real\u2026","poster":"assets/tv-interrogation-2020-poster.jpg","backdrop":"assets/tv-interrogation-2020-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-26T05:52:06.1068207Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":96488,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":57,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.9,"tmdbVotes":54}},{"id":"tv-it-s-always-sunny-in-philadelphia-2005","title":"It's Always Sunny in Philadelphia","year":2005,"type":"tv","runtimeSeconds":null,"seasonCount":18,"communityRating":8.2,"criticRating":null,"genres":["Comedy"],"overview":"Four egocentric friends run a neighborhood Irish pub in Philadelphia and try to find their way through the adult world of work and relationships. Unfortunately, their warped views and precarious judgments often lead\u2026","poster":"assets/tv-it-s-always-sunny-in-philadelphia-2005-poster.jpg","backdrop":"assets/tv-it-s-always-sunny-in-philadelphia-2005-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0485774Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":2710,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":94,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.253,"tmdbVotes":1457}},{"id":"tv-a-knight-of-the-seven-kingdoms-2026","title":"A Knight of the Seven Kingdoms","year":2026,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":8.431,"criticRating":null,"genres":["Drama","Sci-Fi & Fantasy","Action & Adventure"],"overview":"A century before the events of Game of Thrones, two unlikely heroes wandered Westeros: a young, naive but courageous knight, Ser Duncan the Tall, and his diminutive squire, Egg. Set in an age when the Targaryen line\u2026","poster":"assets/tv-a-knight-of-the-seven-kingdoms-2026-poster.jpg","backdrop":"assets/tv-a-knight-of-the-seven-kingdoms-2026-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0493344Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":224372,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":94,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.4,"tmdbVotes":1266}},{"id":"tv-landman-2024","title":"Landman","year":2024,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":8.194,"criticRating":null,"genres":["Drama"],"overview":"Set in the proverbial boomtowns of West-Texas and a modern-day tale of fortune-seeking in the world of oil rigs, the series is an upstairs/downstairs story of roughnecks and wildcat billionaires that are fueling a\u2026","poster":"assets/tv-landman-2024-poster.jpg","backdrop":"assets/tv-landman-2024-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-10-22T21:38:18.0973875Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":157741,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":80,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.209,"tmdbVotes":668}},{"id":"tv-the-last-of-us-2023","title":"The Last of Us","year":2023,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":8.419,"criticRating":null,"genres":["Drama"],"overview":"Twenty years after modern civilization has been destroyed, Joel, a hardened survivor, is hired to smuggle Ellie, a 14-year-old girl, out of an oppressive quarantine zone. What starts as a small job soon becomes a\u2026","poster":"assets/tv-the-last-of-us-2023-poster.jpg","backdrop":"assets/tv-the-last-of-us-2023-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0640955Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":100088,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":94,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.4,"tmdbVotes":7485}},{"id":"tv-last-samurai-standing-2025","title":"Last Samurai Standing","year":2025,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":7.805,"criticRating":null,"genres":["Action & Adventure","Drama"],"overview":"In the early Meiji era, Shujiro, once known as an undefeated samurai, decides to participate in a deadly survival game to save his family and villagers.","poster":"assets/tv-last-samurai-standing-2025-poster.jpg","backdrop":"assets/tv-last-samurai-standing-2025-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0622526Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":252193,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.812,"tmdbVotes":271}},{"id":"tv-lord-of-the-flies-2026","title":"Lord of the Flies","year":2026,"type":"tv","runtimeSeconds":3480,"seasonCount":1,"communityRating":7.571,"criticRating":null,"genres":["Drama","Action & Adventure"],"overview":"After a plane crash, a group of schoolboys find themselves stranded on a tropical island without adults. Ralph is elected leader and, with the help of the intelligent Piggy, strives to maintain order and\u2026","poster":"assets/tv-lord-of-the-flies-2026-poster.jpg","backdrop":"assets/tv-lord-of-the-flies-2026-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0645648Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":270572,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":91,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.58,"tmdbVotes":138}},{"id":"tv-the-lord-of-the-rings-the-rings-of-power-2022","title":"The Lord of the Rings: The Rings of Power","year":2022,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":7.233,"criticRating":null,"genres":["Action & Adventure","Sci-Fi & Fantasy","Drama"],"overview":"Beginning in a time of relative peace, we follow an ensemble cast of characters as they confront the re-emergence of evil to Middle-earth. From the darkest depths of the Misty Mountains, to the majestic forests of\u2026","poster":"assets/tv-the-lord-of-the-rings-the-rings-of-power-2022-poster.jpg","backdrop":"assets/tv-the-lord-of-the-rings-the-rings-of-power-2022-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0618904Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":84773,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":84,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.211,"tmdbVotes":4003}},{"id":"tv-love-death-robots-2019","title":"Love, Death & Robots","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":4,"communityRating":8.21,"criticRating":null,"genres":["Animation","Sci-Fi & Fantasy"],"overview":"Terrifying creatures, wicked surprises and dark comedy converge in this NSFW anthology of animated stories presented by Tim Miller and David Fincher.","poster":"assets/tv-love-death-robots-2019-poster.jpg","backdrop":"assets/tv-love-death-robots-2019-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0460964Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":86831,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":89,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.203,"tmdbVotes":4238}},{"id":"tv-maniac-2018","title":"Maniac","year":2018,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":7.338,"criticRating":null,"genres":["Comedy","Drama","Sci-Fi & Fantasy"],"overview":"Two strangers are drawn to a mysterious pharmaceutical trial that will, they're assured, with no complications or side-effects whatsoever, solve all of their problems, permanently. Things do not go as planned.","poster":"assets/tv-maniac-2018-poster.jpg","backdrop":"assets/tv-maniac-2018-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-20T19:42:30.955548Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":73411,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":84,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.323,"tmdbVotes":1073}},{"id":"tv-mussolini-son-of-the-century-2024","title":"Mussolini: Son of the Century","year":2024,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":8.135,"criticRating":null,"genres":["Drama","War & Politics"],"overview":"The rise of Benito Mussolini and the birth of fascism in Italy, chronicling a country\u2019s surrender to dictatorship and the relentless ascent of a man who rose from his ashes time and again.","poster":"assets/tv-mussolini-son-of-the-century-2024-poster.jpg","backdrop":"assets/tv-mussolini-son-of-the-century-2024-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0586588Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":212333,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":96,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.1,"tmdbVotes":179}},{"id":"tv-the-night-manager-2016","title":"The Night Manager","year":2016,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":7.74,"criticRating":null,"genres":["Drama","Mystery","Crime"],"overview":"Former British soldier Jonathan Pine navigates the shadowy recesses of Whitehall and Washington where an unholy alliance operates between the intelligence community and the secret arms trade. To infiltrate the inner\u2026","poster":"assets/tv-the-night-manager-2016-poster.jpg","backdrop":"assets/tv-the-night-manager-2016-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0663672Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":61859,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":88,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.7,"tmdbVotes":1422}},{"id":"tv-one-piece-2023","title":"ONE PIECE","year":2023,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":8.118,"criticRating":null,"genres":["Action & Adventure","Sci-Fi & Fantasy"],"overview":"With his straw hat and ragtag crew, young pirate Monkey D. Luffy goes on an epic voyage for treasure.","poster":"assets/tv-one-piece-2023-poster.jpg","backdrop":"assets/tv-one-piece-2023-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0439378Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":111110,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":93,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.104,"tmdbVotes":1988}},{"id":"tv-only-murders-in-the-building-2021","title":"Only Murders in the Building","year":2021,"type":"tv","runtimeSeconds":null,"seasonCount":5,"communityRating":8.438,"criticRating":null,"genres":["Comedy","Mystery","Crime"],"overview":"Three strangers share an obsession with true crime and suddenly find themselves wrapped up in one.","poster":"assets/tv-only-murders-in-the-building-2021-poster.jpg","backdrop":"assets/tv-only-murders-in-the-building-2021-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0594614Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":107113,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":95,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.398,"tmdbVotes":2333}},{"id":"tv-over-the-garden-wall-2014","title":"Over the Garden Wall","year":2014,"type":"tv","runtimeSeconds":720,"seasonCount":1,"communityRating":8.6,"criticRating":null,"genres":["Mystery","Sci-Fi & Fantasy","Animation"],"overview":"Two brothers, Wirt and Greg, find themselves lost in the Unknown; a strange forest adrift in time. With the help of a wise old Woodsman and a foul-tempered bluebird named Beatrice, Wirt and Greg must travel across\u2026","poster":"assets/tv-over-the-garden-wall-2014-poster.jpg","backdrop":"assets/tv-over-the-garden-wall-2014-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0455757Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":61617,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.6,"tmdbVotes":1854}},{"id":"tv-peaky-blinders-2013","title":"Peaky Blinders","year":2013,"type":"tv","runtimeSeconds":null,"seasonCount":6,"communityRating":8.5,"criticRating":null,"genres":["Drama","Crime"],"overview":"A gangster family epic set in 1919 Birmingham, England and centered on a gang who sew razor blades in the peaks of their caps, and their fierce boss Tommy Shelby, who means to move up in the world.","poster":"assets/tv-peaky-blinders-2013-poster.jpg","backdrop":"assets/tv-peaky-blinders-2013-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0539185Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":60574,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":93,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.5,"tmdbVotes":11506}},{"id":"tv-the-pitt-2025","title":"The Pitt","year":2025,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":8.729,"criticRating":null,"genres":["Drama"],"overview":"The staff of Pittsburgh's Trauma Medical Center work around the clock to save lives in an overcrowded and underfunded emergency department.","poster":"assets/tv-the-pitt-2025-poster.jpg","backdrop":"assets/tv-the-pitt-2025-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0582942Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":250307,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":96,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.731,"tmdbVotes":1046}},{"id":"tv-pluribus-2025","title":"Pluribus","year":2025,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":7.936,"criticRating":null,"genres":["Drama","Sci-Fi & Fantasy"],"overview":"The most miserable person on Earth must save the world from happiness.","poster":"assets/tv-pluribus-2025-poster.jpg","backdrop":"assets/tv-pluribus-2025-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0674462Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":225171,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":99,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.921,"tmdbVotes":1191}},{"id":"tv-ripley-2024","title":"RIPLEY","year":2024,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":7.911,"criticRating":null,"genres":["Drama"],"overview":"A grifter in 1960s New York is hired to convince a wealthy man's son to return home from Italy and begins a life of deceit, fraud and murder.","poster":"assets/tv-ripley-2024-poster.jpg","backdrop":"assets/tv-ripley-2024-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0658942Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":94028,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":86,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.909,"tmdbVotes":453}},{"id":"tv-say-nothing-2024","title":"Say Nothing","year":2024,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":7.462,"criticRating":null,"genres":["Drama","Crime"],"overview":"Through the eyes of various Irish Republican Army (IRA) members, explore the extremes some people will go to in the name of their beliefs, the way a deeply divided society can suddenly tip over into armed conflict,\u2026","poster":"assets/tv-say-nothing-2024-poster.jpg","backdrop":"assets/tv-say-nothing-2024-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0499752Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":245256,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":94,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.475,"tmdbVotes":122}},{"id":"tv-severance-2022","title":"Severance","year":2022,"type":"tv","runtimeSeconds":null,"seasonCount":2,"communityRating":8.396,"criticRating":null,"genres":["Drama","Mystery","Sci-Fi & Fantasy"],"overview":"Mark leads a team of office workers whose memories have been surgically divided between their work and personal lives. When a mysterious colleague appears outside of work, it begins a journey to discover the truth\u2026","poster":"assets/tv-severance-2022-poster.jpg","backdrop":"assets/tv-severance-2022-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0598478Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":95396,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":95,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.389,"tmdbVotes":3095}},{"id":"tv-six-feet-under-2001","title":"Six Feet Under","year":2001,"type":"tv","runtimeSeconds":null,"seasonCount":5,"communityRating":8.115,"criticRating":null,"genres":["Drama"],"overview":"When death is your business, what is your life? For the Fisher family, the world outside of their family-owned funeral home continues to be at least as challenging as\u2014and far less predictable than\u2014the one inside.","poster":"assets/tv-six-feet-under-2001-poster.jpg","backdrop":"assets/tv-six-feet-under-2001-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-09-26T04:04:05.108787Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":1274,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":81,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.1,"tmdbVotes":1192}},{"id":"tv-undercover-2019","title":"Undercover","year":2019,"type":"tv","runtimeSeconds":3000,"seasonCount":3,"communityRating":7.5,"criticRating":null,"genres":["Crime","Drama"],"overview":"Undercover agents infiltrate a drug kingpin's operation by posing as a couple at the campground where he spends his weekends. Inspired by real events.","poster":"assets/tv-undercover-2019-poster.jpg","backdrop":"assets/tv-undercover-2019-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0570153Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":86942,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.5,"tmdbVotes":186}},{"id":"tv-upload-2020","title":"Upload","year":2020,"type":"tv","runtimeSeconds":null,"seasonCount":4,"communityRating":7.781,"criticRating":null,"genres":["Comedy","Sci-Fi & Fantasy","Drama"],"overview":"In 2033, people who are near death can be \u201cuploaded\u201d into virtual reality hotels run by 6 tech firms. Cash-strapped Nora lives in Brooklyn and works customer service for the luxurious \u201cLakeview\u201d digital afterlife.\u2026","poster":"assets/tv-upload-2020-poster.jpg","backdrop":"assets/tv-upload-2020-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0566967Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":86248,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":87,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.757,"tmdbVotes":1511}},{"id":"tv-the-walk-in-2022","title":"The Walk-In","year":2022,"type":"tv","runtimeSeconds":2760,"seasonCount":1,"communityRating":6.9,"criticRating":null,"genres":["Drama","Crime"],"overview":"Forced to flee the UK and go into hiding in the 1990s, when he became a mole from within the BNP, Matthew Collins returned to Britain to make a new life for himself, working with young white men in the fight against\u2026","poster":"assets/tv-the-walk-in-2022-poster.jpg","backdrop":"assets/tv-the-walk-in-2022-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0654569Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":210664,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":80,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7,"tmdbVotes":50}},{"id":"tv-the-white-lotus-2021","title":"The White Lotus","year":2021,"type":"tv","runtimeSeconds":null,"seasonCount":3,"communityRating":7.596,"criticRating":null,"genres":["Comedy","Drama","Mystery"],"overview":"Follow the exploits of various guests and employees at an exclusive tropical resort over the span of a week as with each passing day, a darker complexity emerges in these picture-perfect travelers, the hotel\u2019s\u2026","poster":"assets/tv-the-white-lotus-2021-poster.jpg","backdrop":"assets/tv-the-white-lotus-2021-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0546438Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":111803,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":90,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.599,"tmdbVotes":1604}},{"id":"tv-widow-s-bay-2026","title":"Widow's Bay","year":2026,"type":"tv","runtimeSeconds":null,"seasonCount":1,"communityRating":8.172,"criticRating":null,"genres":["Drama","Comedy","Mystery"],"overview":"The mayor of a New England town resolves to turn it into the next tourist hot spot, despite local warnings that it's cursed.","poster":"assets/tv-widow-s-bay-2026-poster.jpg","backdrop":"assets/tv-widow-s-bay-2026-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-20T10:27:12.7003979Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":270476,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":98,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8,"tmdbVotes":585}},{"id":"tv-the-witcher-2019","title":"The Witcher","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":4,"communityRating":7.905,"criticRating":null,"genres":["Drama","Action & Adventure"],"overview":"Geralt of Rivia, a mutated monster-hunter for hire, journeys toward his destiny in a turbulent world where people often prove more wicked than beasts.","poster":"assets/tv-the-witcher-2019-poster.jpg","backdrop":"assets/tv-the-witcher-2019-backdrop.jpg","played":true,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0552369Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":71912,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":75,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.88,"tmdbVotes":6997}},{"id":"tv-yellowjackets-2021","title":"Yellowjackets","year":2021,"type":"tv","runtimeSeconds":null,"seasonCount":3,"communityRating":7.449,"criticRating":null,"genres":["Drama","Mystery"],"overview":"This equal parts survival epic, psychological horror story and coming-of-age drama tells the saga of a team of wildly talented high school girls soccer players who become the (un)lucky survivors of a plane crash deep\u2026","poster":"assets/tv-yellowjackets-2021-poster.jpg","backdrop":"assets/tv-yellowjackets-2021-backdrop.jpg","played":false,"playCount":0,"resumeSeconds":0.0,"progress":0,"addedAt":"2026-07-17T15:45:22.0577612Z","lastPlayedAt":null,"availability":"in_library","availabilityEvidence":"viewer_scoped_jellyfin_library","source":"jellyfin_library","tmdbId":117488,"artwork":{"posterKind":"poster","backdropKind":"backdrop"},"ratings":{"rtCritics":92,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.431,"tmdbVotes":1070}}],"anime":[],"discover":[{"id":"movie-12-years-a-slave-2013","title":"12 Years a Slave","year":2013,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","History"],"overview":"In the pre-Civil War United States, Solomon Northup, a free black man from upstate New York, is abducted and sold into slavery. Facing cruelty as well as unexpected kindnesses Solomon struggles not only to stay\u2026","poster":"assets/movie-12-years-a-slave-2013-poster.jpg","backdrop":"assets/movie-12-years-a-slave-2013-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":76203,"ratings":{"rtCritics":95,"rtCriticsLabel":"Certified Fresh","rtAudience":90,"rtAudienceLabel":"Upright","imdb":8.1,"imdbVotes":796313,"tmdb":7.927,"tmdbVotes":12335}},{"id":"movie-101-dalmatians-ii-patch-s-london-adventure-2003","title":"101 Dalmatians II: Patch's London Adventure","year":2003,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Family","Animation","Adventure"],"overview":"Being one of 101 takes its toll on Patch, who doesn't feel unique. When he's accidentally left behind on moving day, he meets his idol, Thunderbolt, who enlists him on a publicity campaign.","poster":"assets/movie-101-dalmatians-ii-patch-s-london-adventure-2003-poster.jpg","backdrop":"assets/movie-101-dalmatians-ii-patch-s-london-adventure-2003-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":13654,"ratings":{"rtCritics":67,"rtCriticsLabel":"Fresh","rtAudience":41,"rtAudienceLabel":"Spilled","imdb":5.7,"imdbVotes":12343,"tmdb":6.025,"tmdbVotes":1274}},{"id":"movie-absolution-2024","title":"Absolution","year":2024,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Crime","Thriller"],"overview":"An aging ex-boxer gangster working as muscle for a Boston crime boss receives an upsetting diagnosis. Despite a faltering memory, he attempts to rectify the sins of his past and reconnect with his estranged\u2026","poster":"assets/movie-absolution-2024-poster.jpg","backdrop":"assets/movie-absolution-2024-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":974453,"ratings":{"rtCritics":56,"rtCriticsLabel":"Rotten","rtAudience":32,"rtAudienceLabel":"Spilled","imdb":5.2,"imdbVotes":11413,"tmdb":5.906,"tmdbVotes":564}},{"id":"movie-addicted-2014","title":"Addicted","year":2014,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Thriller"],"overview":"A gallerist risks her family and flourishing career when she enters into an affair with a talented painter and slowly loses control of her life.","poster":"assets/movie-addicted-2014-poster.jpg","backdrop":"assets/movie-addicted-2014-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":235271,"ratings":{"rtCritics":7,"rtCriticsLabel":"Rotten","rtAudience":51,"rtAudienceLabel":"Spilled","imdb":5,"imdbVotes":13131,"tmdb":5.928,"tmdbVotes":466}},{"id":"movie-all-the-money-in-the-world-2017","title":"All the Money in the World","year":2017,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Crime","History","Thriller"],"overview":"The story of the kidnapping of 16-year-old John Paul Getty III and the desperate attempt by his devoted mother to convince his billionaire grandfather Jean Paul Getty to pay the ransom.","poster":"assets/movie-all-the-money-in-the-world-2017-poster.jpg","backdrop":"assets/movie-all-the-money-in-the-world-2017-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":446791,"ratings":{"rtCritics":79,"rtCriticsLabel":"Certified Fresh","rtAudience":66,"rtAudienceLabel":"Upright","imdb":6.8,"imdbVotes":97448,"tmdb":6.493,"tmdbVotes":2493}},{"id":"movie-the-alto-knights-2025","title":"The Alto Knights","year":2025,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Crime","Drama"],"overview":"Two of New York's most notorious organized crime bosses, Frank Costello and Vito Genovese, vie for control of the city's streets. Once the best of friends, petty jealousies and a series of betrayals place them on a\u2026","poster":"assets/movie-the-alto-knights-2025-poster.jpg","backdrop":"assets/movie-the-alto-knights-2025-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1013601,"ratings":{"rtCritics":39,"rtCriticsLabel":"Rotten","rtAudience":71,"rtAudienceLabel":"Upright","imdb":5.9,"imdbVotes":23017,"tmdb":6.223,"tmdbVotes":485}},{"id":"movie-the-amazing-spider-man-2-2014","title":"The Amazing Spider-Man 2","year":2014,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"For Peter Parker, life is busy. Between taking out the bad guys as Spider-Man and spending time with the person he loves, Gwen Stacy, high school graduation cannot come quickly enough. Peter has not forgotten about\u2026","poster":"assets/movie-the-amazing-spider-man-2-2014-poster.jpg","backdrop":"assets/movie-the-amazing-spider-man-2-2014-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":102382,"ratings":{"rtCritics":51,"rtCriticsLabel":"Rotten","rtAudience":64,"rtAudienceLabel":"Upright","imdb":6.6,"imdbVotes":611981,"tmdb":6.567,"tmdbVotes":14919}},{"id":"movie-ant-man-and-the-wasp-quantumania-2023","title":"Ant-Man and the Wasp: Quantumania","year":2023,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"Super-Hero partners Scott Lang and Hope van Dyne, along with with Hope's parents Janet van Dyne and Hank Pym, and Scott's daughter Cassie Lang, find themselves exploring the Quantum Realm, interacting with strange\u2026","poster":"assets/movie-ant-man-and-the-wasp-quantumania-2023-poster.jpg","backdrop":"assets/movie-ant-man-and-the-wasp-quantumania-2023-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":640146,"ratings":{"rtCritics":46,"rtCriticsLabel":"Rotten","rtAudience":81,"rtAudienceLabel":"Upright","imdb":6,"imdbVotes":281738,"tmdb":6.197,"tmdbVotes":6236}},{"id":"movie-arctic-dogs-2019","title":"Arctic Dogs","year":2019,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Adventure","Comedy"],"overview":"Animals band together to save the day when the evil Otto Von Walrus hatches a sinister scheme to accelerate global warming and melt the Arctic Circle.","poster":"assets/movie-arctic-dogs-2019-poster.jpg","backdrop":"assets/movie-arctic-dogs-2019-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":416153,"ratings":{"rtCritics":13,"rtCriticsLabel":"Rotten","rtAudience":60,"rtAudienceLabel":"Upright","imdb":4.9,"imdbVotes":2580,"tmdb":5.9,"tmdbVotes":148}},{"id":"movie-the-avengers-2012","title":"The Avengers","year":2012,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Science Fiction","Action","Adventure"],"overview":"When an unexpected enemy emerges and threatens global safety and security, Nick Fury, director of the international peacekeeping agency known as S.H.I.E.L.D., finds himself in need of a team to pull the world back\u2026","poster":"assets/movie-the-avengers-2012-poster.jpg","backdrop":"assets/movie-the-avengers-2012-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":24428,"ratings":{"rtCritics":91,"rtCriticsLabel":"Certified Fresh","rtAudience":91,"rtAudienceLabel":"Upright","imdb":8,"imdbVotes":1590693,"tmdb":8.084,"tmdbVotes":40262}},{"id":"movie-black-bear-2020","title":"Black Bear","year":2020,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Thriller"],"overview":"At a remote lake house in the Adirondack Mountains, a couple entertains an out-of-town guest looking for inspiration in her filmmaking. The group quickly falls into a calculated game of desire, manipulation, and\u2026","poster":"assets/movie-black-bear-2020-poster.jpg","backdrop":"assets/movie-black-bear-2020-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":624788,"ratings":{"rtCritics":89,"rtCriticsLabel":"Certified Fresh","rtAudience":64,"rtAudienceLabel":"Upright","imdb":6.5,"imdbVotes":18408,"tmdb":6.337,"tmdbVotes":315}},{"id":"movie-black-panther-2018","title":"Black Panther","year":2018,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"King T'Challa returns home to the reclusive, technologically advanced African nation of Wakanda to serve as his country's new leader. However, T'Challa soon finds that he is challenged for the throne by factions\u2026","poster":"assets/movie-black-panther-2018-poster.jpg","backdrop":"assets/movie-black-panther-2018-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":284054,"ratings":{"rtCritics":96,"rtCriticsLabel":"Certified Fresh","rtAudience":null,"rtAudienceLabel":"Spilled","imdb":7.3,"imdbVotes":931120,"tmdb":7.36,"tmdbVotes":24190}},{"id":"movie-a-bronx-tale-1993","title":"A Bronx Tale","year":1993,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Crime"],"overview":"Set in the Bronx during the tumultuous 1960s, an adolescent boy is torn between his honest, working-class father and a violent yet charismatic crime boss. Complicating matters is the youngster's growing attraction -\u2026","poster":"assets/movie-a-bronx-tale-1993-poster.jpg","backdrop":"assets/movie-a-bronx-tale-1993-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1607,"ratings":{"rtCritics":97,"rtCriticsLabel":"Fresh","rtAudience":92,"rtAudienceLabel":"Upright","imdb":7.8,"imdbVotes":191930,"tmdb":7.913,"tmdbVotes":3075}},{"id":"movie-by-any-means-2026","title":"By Any Means","year":2026,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Thriller","History","Crime"],"overview":"In 1960s Mississippi, a young Black FBI agent is forced to partner with a notorious mafia hitman to investigate a wave of brutal civil rights murders.","poster":"assets/movie-by-any-means-2026-poster.jpg","backdrop":"assets/movie-by-any-means-2026-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1380417,"ratings":{"rtCritics":49,"rtCriticsLabel":"Rotten","rtAudience":88,"rtAudienceLabel":"Upright","imdb":6.8,"imdbVotes":3534,"tmdb":6.6,"tmdbVotes":92}},{"id":"movie-captain-america-civil-war-2016","title":"Captain America: Civil War","year":2016,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Adventure","Action","Science Fiction"],"overview":"Following the events of Age of Ultron, the collective governments of the world pass an act designed to regulate all superhuman activity. This polarizes opinion amongst the Avengers, causing two factions to side with\u2026","poster":"assets/movie-captain-america-civil-war-2016-poster.jpg","backdrop":"assets/movie-captain-america-civil-war-2016-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":271110,"ratings":{"rtCritics":90,"rtCriticsLabel":"Certified Fresh","rtAudience":89,"rtAudienceLabel":"Upright","imdb":7.8,"imdbVotes":954943,"tmdb":7.455,"tmdbVotes":24808}},{"id":"movie-captain-america-the-first-avenger-2011","title":"Captain America: The First Avenger","year":2011,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"During World War II, Steve Rogers is a sickly man from Brooklyn who's transformed into super-soldier Captain America to aid in the war effort. Rogers must stop the Red Skull \u2013 Adolf Hitler's ruthless head of\u2026","poster":"assets/movie-captain-america-the-first-avenger-2011-poster.jpg","backdrop":"assets/movie-captain-america-the-first-avenger-2011-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1771,"ratings":{"rtCritics":80,"rtCriticsLabel":"Certified Fresh","rtAudience":75,"rtAudienceLabel":"Upright","imdb":6.9,"imdbVotes":993453,"tmdb":7.012,"tmdbVotes":23473}},{"id":"movie-captain-america-the-winter-soldier-2014","title":"Captain America: The Winter Soldier","year":2014,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"After the cataclysmic events in New York with The Avengers, Steve Rogers, aka Captain America is living quietly in Washington, D.C. and trying to adjust to the modern world. But when a S.H.I.E.L.D. colleague comes\u2026","poster":"assets/movie-captain-america-the-winter-soldier-2014-poster.jpg","backdrop":"assets/movie-captain-america-the-winter-soldier-2014-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":100402,"ratings":{"rtCritics":90,"rtCriticsLabel":"Certified Fresh","rtAudience":92,"rtAudienceLabel":"Upright","imdb":7.7,"imdbVotes":995514,"tmdb":7.654,"tmdbVotes":20688}},{"id":"movie-careful-what-you-wish-for-2015","title":"Careful What You Wish For","year":2015,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Thriller"],"overview":"A guy gets more than he bargained for after entering into an affair with the wife of an investment banker. Soon, a suspicious death and substantial life insurance policy embroil him in a scandal.","poster":"assets/movie-careful-what-you-wish-for-2015-poster.jpg","backdrop":"assets/movie-careful-what-you-wish-for-2015-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":317744,"ratings":{"rtCritics":17,"rtCriticsLabel":"Rotten","rtAudience":61,"rtAudienceLabel":"Upright","imdb":5.6,"imdbVotes":9452,"tmdb":6.129,"tmdbVotes":446}},{"id":"tv-12-monkeys-2015","title":"12 Monkeys","year":2015,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Sci-Fi & Fantasy","Drama"],"overview":"The provocative story of Cole, a time traveler from a decimated future in a high-stakes race against the clock. Utilizing a dangerous and untested method of time travel, he journeys from 2043 to the present day on a\u2026","poster":"assets/tv-12-monkeys-2015-poster.jpg","backdrop":"assets/tv-12-monkeys-2015-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":60948,"ratings":{"rtCritics":88,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.441,"tmdbVotes":1245}},{"id":"tv-90-day-fiance-before-the-90-days-2017","title":"90 Day Fianc\u00e9: Before the 90 Days","year":2017,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Reality"],"overview":"Follow couples who have an existing relationship online, but haven't met in person. We'll experience their journey as they travel to the other's foreign country for the first time in an attempt to establish an\u2026","poster":"assets/tv-90-day-fiance-before-the-90-days-2017-poster.jpg","backdrop":"assets/tv-90-day-fiance-before-the-90-days-2017-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":73319,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.5,"tmdbVotes":45}},{"id":"tv-90-day-fiance-the-other-way-2019","title":"90 Day Fianc\u00e9: The Other Way","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Reality"],"overview":"Americans move to a foreign country all in the name of love. Will uprooting their lives in the United States pay off, or will they be packing up and moving back to America brokenhearted?","poster":"assets/tv-90-day-fiance-the-other-way-2019-poster.jpg","backdrop":"assets/tv-90-day-fiance-the-other-way-2019-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":90046,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.8,"tmdbVotes":34}},{"id":"tv-the-100-2014","title":"The 100","year":2014,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Sci-Fi & Fantasy","Action & Adventure","Drama"],"overview":"100 years in the future, when the Earth has been abandoned due to radioactivity, the last surviving humans live on an ark orbiting the planet \u2014 but the ark won't last forever. So the repressive regime picks 100\u2026","poster":"assets/tv-the-100-2014-poster.jpg","backdrop":"assets/tv-the-100-2014-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":48866,"ratings":{"rtCritics":93,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.878,"tmdbVotes":8855}},{"id":"tv-accused-2023","title":"Accused","year":2023,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Crime","Drama"],"overview":"In this crime anthology series, viewers discover how an ordinary person got caught up in an extraordinary situation, ultimately revealing how one wrong turn leads to another, until it\u2019s too late to turn back. Told\u2026","poster":"assets/tv-accused-2023-poster.jpg","backdrop":"assets/tv-accused-2023-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":202097,"ratings":{"rtCritics":61,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.851,"tmdbVotes":87}},{"id":"tv-after-life-2019","title":"After Life","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy","Drama"],"overview":"Tony had a perfect life. But after his wife Lisa suddenly dies, Tony changes. After contemplating taking his own life, he decides instead to live long enough to punish the world by saying and doing whatever he likes\u2026","poster":"assets/tv-after-life-2019-poster.jpg","backdrop":"assets/tv-after-life-2019-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":79410,"ratings":{"rtCritics":72,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.902,"tmdbVotes":1169}},{"id":"tv-all-creatures-great-and-small-1978","title":"All Creatures Great and Small","year":1978,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy","Drama"],"overview":"The trials and misadventures of the staff at a country veterinary office in Yorkshire. James Herriot, a young animal surgeon, moves to a small Yorkshire town to begin his first job.","poster":"assets/tv-all-creatures-great-and-small-1978-poster.jpg","backdrop":"assets/tv-all-creatures-great-and-small-1978-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"center_crop","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":7406,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.8,"tmdbVotes":50}},{"id":"tv-american-housewife-2016","title":"American Housewife","year":2016,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy"],"overview":"A family comedy narrated by Katie, a strong-willed mother, raising her flawed family in a wealthy town filled with perfect wives and their perfect offspring.","poster":"assets/tv-american-housewife-2016-poster.jpg","backdrop":"assets/tv-american-housewife-2016-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":67117,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.7,"tmdbVotes":187}},{"id":"tv-atlantis-2013","title":"Atlantis","year":2013,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action & Adventure","Sci-Fi & Fantasy"],"overview":"A fantasy drama set in a world of legendary heroes and mythical creatures. Far from home and desperate for answers, Jason washes up on the shores of an ancient land. A mysterious place; a world of bull leaping, of\u2026","poster":"assets/tv-atlantis-2013-poster.jpg","backdrop":"assets/tv-atlantis-2013-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":47054,"ratings":{"rtCritics":62,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.4,"tmdbVotes":155}},{"id":"tv-avatar-the-last-airbender-2024","title":"Avatar: The Last Airbender","year":2024,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action & Adventure","Sci-Fi & Fantasy","Drama"],"overview":"A young boy known as the Avatar must master the four elemental powers to save a world at war \u2014 and fight a ruthless enemy bent on stopping him.","poster":"assets/tv-avatar-the-last-airbender-2024-poster.jpg","backdrop":"assets/tv-avatar-the-last-airbender-2024-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":82452,"ratings":{"rtCritics":66,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.8,"tmdbVotes":1406}},{"id":"tv-avatar-seven-havens-2026","title":"Avatar: Seven Havens","year":2026,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"In a world shattered by a devastating cataclysm, a young Earthbender discovers she's the new Avatar after Korra. But in this dangerous era, that title marks her as humanity's destroyer, not its savior. Hunted by both\u2026","poster":"assets/tv-avatar-seven-havens-2026-poster.jpg","backdrop":"assets/tv-avatar-seven-havens-2026-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":284833,"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.9,"tmdbVotes":183}},{"id":"tv-batman-the-brave-and-the-bold-2008","title":"Batman: The Brave and the Bold","year":2008,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"The Caped Crusader is teamed up with Blue Beetle, Green Arrow, Aquaman and countless others in his quest to uphold justice.","poster":"assets/tv-batman-the-brave-and-the-bold-2008-poster.jpg","backdrop":"assets/tv-batman-the-brave-and-the-bold-2008-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":15804,"ratings":{"rtCritics":96,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.6,"tmdbVotes":295}},{"id":"tv-beat-bobby-flay-2013","title":"Beat Bobby Flay","year":2013,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Reality"],"overview":"Two talented chefs go head-to-head for the chance to Beat Bobby Flay. To get to Bobby the chefs must first face off against each other, creating a spectacular dish with a secret ingredient of Bobby's choice. Judges\u2026","poster":"assets/tv-beat-bobby-flay-2013-poster.jpg","backdrop":"assets/tv-beat-bobby-flay-2013-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":62481,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.5,"tmdbVotes":31}},{"id":"tv-benson-1979","title":"Benson","year":1979,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy"],"overview":"A butler deals with life at the governor's mansion.","poster":"assets/tv-benson-1979-poster.jpg","backdrop":"assets/tv-benson-1979-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1849,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7,"tmdbVotes":46}},{"id":"tv-black-rabbit-2025","title":"Black Rabbit","year":2025,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Crime"],"overview":"A rising-star restaurateur is forced into New York's criminal underworld when his chaotic brother returns to town with loan sharks on his trail.","poster":"assets/tv-black-rabbit-2025-poster.jpg","backdrop":"assets/tv-black-rabbit-2025-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":249039,"ratings":{"rtCritics":66,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.983,"tmdbVotes":240}},{"id":"tv-black-ish-2014","title":"black-ish","year":2014,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy"],"overview":"A family man struggles to gain a sense of cultural identity while raising his kids in a predominantly white, upper-middle-class neighborhood.","poster":"assets/tv-black-ish-2014-poster.jpg","backdrop":"assets/tv-black-ish-2014-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":61381,"ratings":{"rtCritics":92,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.1,"tmdbVotes":352}},{"id":"tv-breaking-bad-2008","title":"Breaking Bad","year":2008,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Crime"],"overview":"Walter White, a New Mexico chemistry teacher, is diagnosed with Stage III cancer and given a prognosis of only two years left to live. He becomes filled with a sense of fearlessness and an unrelenting desire to\u2026","poster":"assets/tv-breaking-bad-2008-poster.jpg","backdrop":"assets/tv-breaking-bad-2008-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"center_crop","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1396,"ratings":{"rtCritics":96,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.959,"tmdbVotes":19030}},{"id":"tv-the-capture-2019","title":"The Capture","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Crime","Drama","Mystery"],"overview":"When soldier Shaun Emery's conviction for a murder in Afghanistan is overturned due to flawed video evidence, he returns to life as a free man with his young daughter. But when damning CCTV footage from a night out\u2026","poster":"assets/tv-the-capture-2019-poster.jpg","backdrop":"assets/tv-the-capture-2019-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":93166,"ratings":{"rtCritics":97,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.634,"tmdbVotes":361}}]}],"seeAll":{"trending":[{"id":"tv-american-gods-2017","title":"American Gods","year":2017,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Mystery","Sci-Fi & Fantasy"],"overview":"An ex-con becomes the traveling partner of a conman who turns out to be one of the older gods trying to recruit troops to battle the upstart deities. Based on Neil Gaiman's fantasy novel.","poster":"assets/tv-american-gods-2017-poster.jpg","backdrop":"assets/tv-american-gods-2017-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":46639,"ratings":{"rtCritics":75,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.1,"tmdbVotes":1852}},{"id":"tv-avatar-seven-havens-2026","title":"Avatar: Seven Havens","year":2026,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"In a world shattered by a devastating cataclysm, a young Earthbender discovers she's the new Avatar after Korra. But in this dangerous era, that title marks her as humanity's destroyer, not its savior. Hunted by both\u2026","poster":"assets/tv-avatar-seven-havens-2026-poster.jpg","backdrop":"assets/tv-avatar-seven-havens-2026-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":284833,"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.9,"tmdbVotes":183}},{"id":"tv-batman-the-brave-and-the-bold-2008","title":"Batman: The Brave and the Bold","year":2008,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"The Caped Crusader is teamed up with Blue Beetle, Green Arrow, Aquaman and countless others in his quest to uphold justice.","poster":"assets/tv-batman-the-brave-and-the-bold-2008-poster.jpg","backdrop":"assets/tv-batman-the-brave-and-the-bold-2008-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":15804,"ratings":{"rtCritics":96,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.6,"tmdbVotes":295}},{"id":"tv-batwoman-2019","title":"Batwoman","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Sci-Fi & Fantasy","Action & Adventure"],"overview":"Kate Kane, armed with a passion for social justice and a flair for speaking her mind, soars onto the streets of Gotham as Batwoman, an out lesbian and highly trained street fighter primed to snuff out the failing\u2026","poster":"assets/tv-batwoman-2019-poster.jpg","backdrop":"assets/tv-batwoman-2019-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":89247,"ratings":{"rtCritics":83,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.8,"tmdbVotes":1619}},{"id":"tv-big-mouth-2017","title":"Big Mouth","year":2017,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy","Animation"],"overview":"Teenage friends find their lives upended by the wonders and horrors of puberty in this edgy comedy from real-life pals Nick Kroll and Andrew Goldberg.","poster":"assets/tv-big-mouth-2017-poster.jpg","backdrop":"assets/tv-big-mouth-2017-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":74204,"ratings":{"rtCritics":95,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.591,"tmdbVotes":1274}},{"id":"tv-black-lightning-2018","title":"Black Lightning","year":2018,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action & Adventure","Sci-Fi & Fantasy","Drama"],"overview":"Jefferson Pierce is a man wrestling with a secret. As the father of two daughters and principal of a charter high school that also serves as a safe haven for young people in a New Orleans neighborhood overrun by gang\u2026","poster":"assets/tv-black-lightning-2018-poster.jpg","backdrop":"assets/tv-black-lightning-2018-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":71663,"ratings":{"rtCritics":92,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.907,"tmdbVotes":991}},{"id":"movie-across-the-hall-2009","title":"Across the Hall","year":2009,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Thriller","Mystery"],"overview":"Convinced that his fiancee is cheating on him, a man follows her to a hotel and calls his best friend to help him avoid a calamity.","poster":"assets/movie-across-the-hall-2009-poster.jpg","backdrop":"assets/movie-across-the-hall-2009-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":21469,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":39,"rtAudienceLabel":"Spilled","imdb":5.8,"imdbVotes":5130,"tmdb":6,"tmdbVotes":129}},{"id":"movie-addicted-2014","title":"Addicted","year":2014,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Thriller"],"overview":"A gallerist risks her family and flourishing career when she enters into an affair with a talented painter and slowly loses control of her life.","poster":"assets/movie-addicted-2014-poster.jpg","backdrop":"assets/movie-addicted-2014-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":235271,"ratings":{"rtCritics":7,"rtCriticsLabel":"Rotten","rtAudience":51,"rtAudienceLabel":"Spilled","imdb":5,"imdbVotes":13131,"tmdb":5.928,"tmdbVotes":466}},{"id":"movie-adulterers-2016","title":"Adulterers","year":2016,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Thriller","Drama"],"overview":"On a steamy New Orleans afternoon, Sam Deuprey decides to surprise his beautiful wife, Ashley, for their anniversary and comes home early. But Ashley is not alone in the bedroom. She and her lover, Damien are about\u2026","poster":"assets/movie-adulterers-2016-poster.jpg","backdrop":"assets/movie-adulterers-2016-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":376004,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":37,"rtAudienceLabel":"Spilled","imdb":5.1,"imdbVotes":2144,"tmdb":6.2,"tmdbVotes":116}},{"id":"movie-alone-with-her-2006","title":"Alone With Her","year":2006,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Crime","Drama","Thriller"],"overview":"The harrowing story of a disturbed young man's attempts to win the affections of an unsuspecting young woman. When Doug first sees Amy, he instantly falls for her and begins to watch her every move, going so far as\u2026","poster":"assets/movie-alone-with-her-2006-poster.jpg","backdrop":"assets/movie-alone-with-her-2006-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":18206,"ratings":{"rtCritics":70,"rtCriticsLabel":"Fresh","rtAudience":46,"rtAudienceLabel":"Spilled","imdb":6,"imdbVotes":4359,"tmdb":5.9,"tmdbVotes":94}},{"id":"movie-awake-2007","title":"Awake","year":2007,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Thriller","Crime","Mystery"],"overview":"While undergoing heart surgery, a man experiences a phenomenon called \u2018anesthetic awareness\u2019, which leaves him awake but paralyzed throughout the operation. As various obstacles present themselves, his wife must make\u2026","poster":"assets/movie-awake-2007-poster.jpg","backdrop":"assets/movie-awake-2007-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":13483,"ratings":{"rtCritics":23,"rtCriticsLabel":"Rotten","rtAudience":55,"rtAudienceLabel":"Spilled","imdb":6.5,"imdbVotes":89389,"tmdb":6.586,"tmdbVotes":1649}},{"id":"movie-black-bear-2020","title":"Black Bear","year":2020,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Thriller"],"overview":"At a remote lake house in the Adirondack Mountains, a couple entertains an out-of-town guest looking for inspiration in her filmmaking. The group quickly falls into a calculated game of desire, manipulation, and\u2026","poster":"assets/movie-black-bear-2020-poster.jpg","backdrop":"assets/movie-black-bear-2020-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":624788,"ratings":{"rtCritics":89,"rtCriticsLabel":"Certified Fresh","rtAudience":64,"rtAudienceLabel":"Upright","imdb":6.5,"imdbVotes":18408,"tmdb":6.337,"tmdbVotes":315}},{"id":"movie-butterfly-on-a-wheel-2007","title":"Butterfly on a Wheel","year":2007,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Crime","Drama","Thriller"],"overview":"A sociopathic kidnapper methodically pushes a desperate pair of parents to their absolute breaking point.","poster":"assets/movie-butterfly-on-a-wheel-2007-poster.jpg","backdrop":"assets/movie-butterfly-on-a-wheel-2007-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":13250,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":61,"rtAudienceLabel":"Upright","imdb":6.6,"imdbVotes":35409,"tmdb":6.457,"tmdbVotes":595}},{"id":"movie-careful-what-you-wish-for-2015","title":"Careful What You Wish For","year":2015,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Thriller"],"overview":"A guy gets more than he bargained for after entering into an affair with the wife of an investment banker. Soon, a suspicious death and substantial life insurance policy embroil him in a scandal.","poster":"assets/movie-careful-what-you-wish-for-2015-poster.jpg","backdrop":"assets/movie-careful-what-you-wish-for-2015-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":317744,"ratings":{"rtCritics":17,"rtCriticsLabel":"Rotten","rtAudience":61,"rtAudienceLabel":"Upright","imdb":5.6,"imdbVotes":9452,"tmdb":6.129,"tmdbVotes":446}},{"id":"movie-crime-of-passion-1956","title":"Crime of Passion","year":1956,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Crime","Thriller"],"overview":"Kathy leaves the newspaper business to marry homicide detective Bill, but is frustrated by his lack of ambition and the banality of life in the suburbs. Her drive to advance Bill's career soon takes her down a\u2026","poster":"assets/movie-crime-of-passion-1956-poster.jpg","backdrop":"assets/movie-crime-of-passion-1956-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"center_crop","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1920,"ratings":{"rtCritics":80,"rtCriticsLabel":"Fresh","rtAudience":34,"rtAudienceLabel":"Spilled","imdb":6.4,"imdbVotes":3750,"tmdb":6.1,"tmdbVotes":57}},{"id":"movie-deep-water-2022","title":"Deep Water","year":2022,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Mystery","Thriller"],"overview":"A well-to-do husband who allows his wife to have affairs in order to avoid a divorce becomes a prime suspect in the disappearance of her lovers.","poster":"assets/movie-deep-water-2022-poster.jpg","backdrop":"assets/movie-deep-water-2022-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":619979,"ratings":{"rtCritics":35,"rtCriticsLabel":"Rotten","rtAudience":25,"rtAudienceLabel":"Spilled","imdb":5.5,"imdbVotes":74098,"tmdb":5.834,"tmdbVotes":1755}},{"id":"movie-derailed-2005","title":"Derailed","year":2005,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Thriller"],"overview":"When two married business executives having an affair are blackmailed by a violent criminal, they are forced to turn the tables on him to save their families.","poster":"assets/movie-derailed-2005-poster.jpg","backdrop":"assets/movie-derailed-2005-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":8999,"ratings":{"rtCritics":20,"rtCriticsLabel":"Rotten","rtAudience":58,"rtAudienceLabel":"Spilled","imdb":6.6,"imdbVotes":79563,"tmdb":6.405,"tmdbVotes":1193}},{"id":"movie-die-my-love-2025","title":"Die My Love","year":2025,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama"],"overview":"After inheriting a remote Montana house, Jackson moves there from New York with his partner Grace, and the couple soon welcome a child. As Jackson becomes increasingly absent and rural isolation sets in, Grace\u2026","poster":"assets/movie-die-my-love-2025-poster.jpg","backdrop":"assets/movie-die-my-love-2025-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1033148,"ratings":{"rtCritics":74,"rtCriticsLabel":"Certified Fresh","rtAudience":45,"rtAudienceLabel":"Spilled","imdb":6,"imdbVotes":50664,"tmdb":6.1,"tmdbVotes":683}},{"id":"movie-dream-house-2011","title":"Dream House","year":2011,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Mystery","Drama","Thriller"],"overview":"Publisher Will Atenton quits a lucrative job in New York to relocate his wife, Libby, and their daughters to a quaint town in New England. However, as they settle into their home the Atentons discover that a woman\u2026","poster":"assets/movie-dream-house-2011-poster.jpg","backdrop":"assets/movie-dream-house-2011-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":69668,"ratings":{"rtCritics":7,"rtCriticsLabel":"Rotten","rtAudience":36,"rtAudienceLabel":"Spilled","imdb":6,"imdbVotes":71386,"tmdb":6.212,"tmdbVotes":1480}},{"id":"movie-dream-lover-1994","title":"Dream Lover","year":1994,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Mystery","Thriller"],"overview":"Not long after they cross paths at an art gallery, architect Ray Reardon and hypnotically sensual Lena are married with children. But as strange incidents occur, Ray begins to realize he may not really know the woman\u2026","poster":"assets/movie-dream-lover-1994-poster.jpg","backdrop":"assets/movie-dream-lover-1994-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":18190,"ratings":{"rtCritics":57,"rtCriticsLabel":"Rotten","rtAudience":38,"rtAudienceLabel":"Spilled","imdb":6.2,"imdbVotes":7865,"tmdb":6.844,"tmdbVotes":167}},{"id":"movie-drop-2025","title":"Drop","year":2025,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Mystery","Thriller"],"overview":"Violet, a widowed mother on her first date in years, arrives at an upscale restaurant where she is relieved that her date, Henry, is more charming and handsome than she expected. But their chemistry begins to curdle\u2026","poster":"assets/movie-drop-2025-poster.jpg","backdrop":"assets/movie-drop-2025-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1249213,"ratings":{"rtCritics":83,"rtCriticsLabel":"Certified Fresh","rtAudience":79,"rtAudienceLabel":"Upright","imdb":6.1,"imdbVotes":61018,"tmdb":6.275,"tmdbVotes":1023}},{"id":"movie-eastern-promises-2007","title":"Eastern Promises","year":2007,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Thriller","Crime","Mystery"],"overview":"A Russian teenager living in London dies during childbirth but leaves clues in her diary that could tie her child to a rape involving a violent Russian mob family.","poster":"assets/movie-eastern-promises-2007-poster.jpg","backdrop":"assets/movie-eastern-promises-2007-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":2252,"ratings":{"rtCritics":89,"rtCriticsLabel":"Certified Fresh","rtAudience":83,"rtAudienceLabel":"Upright","imdb":7.6,"imdbVotes":281015,"tmdb":7.349,"tmdbVotes":3900}},{"id":"movie-faces-1968","title":"Faces","year":1968,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama"],"overview":"Middle-aged suburban husband Richard abruptly tells his wife, Maria, that he wants a divorce. As Richard takes up with a younger woman, Maria enjoys a night on the town with her friends and meets a younger man. As\u2026","poster":"assets/movie-faces-1968-poster.jpg","backdrop":"assets/movie-faces-1968-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"center_crop","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":753,"ratings":{"rtCritics":83,"rtCriticsLabel":"Fresh","rtAudience":86,"rtAudienceLabel":"Upright","imdb":7.4,"imdbVotes":12950,"tmdb":7.093,"tmdbVotes":227}},{"id":"movie-fatale-2020","title":"Fatale","year":2020,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Thriller"],"overview":"After a wild one-night stand, successful sports agent Derrick Tyler watches his perfect life slowly disappear when he discovers the sexy and mysterious woman he risked everything for is determined police detective\u2026","poster":"assets/movie-fatale-2020-poster.jpg","backdrop":"assets/movie-fatale-2020-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":549514,"ratings":{"rtCritics":46,"rtCriticsLabel":"Rotten","rtAudience":87,"rtAudienceLabel":"Upright","imdb":5.5,"imdbVotes":16392,"tmdb":6,"tmdbVotes":401}},{"id":"tv-56-days-2026","title":"56 Days","year":2026,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Crime","Mystery"],"overview":"When an unidentified body is found in a luxury apartment linked to Oliver Kennedy and his girlfriend Ciara Wyse, Detectives Lee Reardon and Karl Connolly reconstruct the couple's deadly romance across the past 56 days.","poster":"assets/tv-56-days-2026-poster.jpg","backdrop":"assets/tv-56-days-2026-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":241372,"ratings":{"rtCritics":60,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.388,"tmdbVotes":245}},{"id":"tv-absolutely-fabulous-1992","title":"Absolutely Fabulous","year":1992,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy"],"overview":"Set in the world of fashion and PR, immature fun-loving mother Edina Monsoon and her best friend Patsy drive Eddie's sensible daughter, Saffron, up the wall with their constant drug abuse and outrageous selfishness.\u2026","poster":"assets/tv-absolutely-fabulous-1992-poster.jpg","backdrop":"assets/tv-absolutely-fabulous-1992-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":4493,"ratings":{"rtCritics":96,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.6,"tmdbVotes":198}},{"id":"tv-the-afterparty-2022","title":"The Afterparty","year":2022,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Mystery","Comedy","Crime"],"overview":"Nothing is as it seems in this hilarious murder mystery where each suspect's story is told through a different film genre.","poster":"assets/tv-the-afterparty-2022-poster.jpg","backdrop":"assets/tv-the-afterparty-2022-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":106454,"ratings":{"rtCritics":92,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.071,"tmdbVotes":245}},{"id":"tv-agatha-christie-s-marple-2004","title":"Agatha Christie's Marple","year":2004,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Crime","Mystery"],"overview":"The adventures of Miss Jane Marple, an elderly spinster living in the quiet little village of St Mary Mead. During her many visits to friends and relatives in other villages, Miss Marple often stumbles upon\u2026","poster":"assets/tv-agatha-christie-s-marple-2004-poster.jpg","backdrop":"assets/tv-agatha-christie-s-marple-2004-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":6127,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.9,"tmdbVotes":152}},{"id":"tv-all-american-homecoming-2022","title":"All American: Homecoming","year":2022,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama"],"overview":"Follow the journeys of Simone Hicks, a tennis hopeful from Beverly Hills, and elite baseball player Damon Sims from Chicago, as they navigate life at the prestigious HBCU Bringston University.","poster":"assets/tv-all-american-homecoming-2022-poster.jpg","backdrop":"assets/tv-all-american-homecoming-2022-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":153723,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.3,"tmdbVotes":70}},{"id":"tv-and-just-like-that-2021","title":"And Just Like That\u2026","year":2021,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy","Drama"],"overview":"This new chapter of \u201cSex and the City\u201d follows Carrie, Miranda and Charlotte as they navigate the journey from the complicated reality of life and friendship in their 30s to the even more complicated reality of life\u2026","poster":"assets/tv-and-just-like-that-2021-poster.jpg","backdrop":"assets/tv-and-just-like-that-2021-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":116450,"ratings":{"rtCritics":52,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.211,"tmdbVotes":556}},{"id":"tv-anne-with-an-e-2017","title":"Anne with an E","year":2017,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Family"],"overview":"A coming-of-age story about an outsider who, against all odds and numerous challenges, fights for love and acceptance and for her place in the world. The series centers on a young orphaned girl in the late 1890s,\u2026","poster":"assets/tv-anne-with-an-e-2017-poster.jpg","backdrop":"assets/tv-anne-with-an-e-2017-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":70785,"ratings":{"rtCritics":63,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.7,"tmdbVotes":5019}},{"id":"tv-awkward-2011","title":"Awkward.","year":2011,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy","Drama"],"overview":"An irreverent look at the conflict, chaos and humor that defines teenage life through the eyes of 15-year-old Jenna Hamilton whose life begins to change when a simple accident becomes an epic misunderstanding and is\u2026","poster":"assets/tv-awkward-2011-poster.jpg","backdrop":"assets/tv-awkward-2011-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":39859,"ratings":{"rtCritics":78,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.4,"tmdbVotes":427}},{"id":"tv-the-baby-sitters-club-2020","title":"The Baby-Sitters Club","year":2020,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Kids","Drama"],"overview":"In this contemporary take on the beloved book series, five best friends launch a baby-sitting business that's big on fun and adventure.","poster":"assets/tv-the-baby-sitters-club-2020-poster.jpg","backdrop":"assets/tv-the-baby-sitters-club-2020-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":100412,"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.9,"tmdbVotes":506}},{"id":"tv-ballers-2015","title":"Ballers","year":2015,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Comedy"],"overview":"Looking at the lives of former and current football players, the show follows former superstar Spencer Strasmore as he gets his life on track in retirement while mentoring other current and former players through the\u2026","poster":"assets/tv-ballers-2015-poster.jpg","backdrop":"assets/tv-ballers-2015-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":62704,"ratings":{"rtCritics":72,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.809,"tmdbVotes":820}},{"id":"tv-baretta-1975","title":"Baretta","year":1975,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Crime","Drama","Mystery"],"overview":"Baretta is an American detective television series which ran on ABC from 1975 to 1978. The show was a milder version of a successful 1973\u201374 ABC series, Toma, starring Tony Musante as chameleon-like, real-life New\u2026","poster":"assets/tv-baretta-1975-poster.jpg","backdrop":"assets/tv-baretta-1975-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":3216,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.5,"tmdbVotes":43}},{"id":"tv-based-on-a-true-story-2023","title":"Based on a True Story","year":2023,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy","Drama"],"overview":"The lives of a realtor, a plumber and a former tennis star unexpectedly collide, exposing America\u2019s obsession with true crime, murder and the slow-close toilet seat.","poster":"assets/tv-based-on-a-true-story-2023-poster.jpg","backdrop":"assets/tv-based-on-a-true-story-2023-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":197373,"ratings":{"rtCritics":79,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7,"tmdbVotes":160}},{"id":"tv-the-beast-in-me-2025","title":"The Beast in Me","year":2025,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Mystery"],"overview":"A famous author is pulled into a twisted mind game with her rich, powerful new neighbor \u2014 who might be a murderer.","poster":"assets/tv-the-beast-in-me-2025-poster.jpg","backdrop":"assets/tv-the-beast-in-me-2025-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":250504,"ratings":{"rtCritics":85,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.072,"tmdbVotes":334}},{"id":"tv-big-city-greens-2018","title":"Big City Greens","year":2018,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Family","Animation","Comedy"],"overview":"The offbeat adventures of 10-year-old Cricket Green, a mischievous and optimistic country boy who moves to the big city with his wildly out of place family \u2013 older sister Tilly, father Bill and Gramma Alice.","poster":"assets/tv-big-city-greens-2018-poster.jpg","backdrop":"assets/tv-big-city-greens-2018-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":80587,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.555,"tmdbVotes":82}},{"id":"tv-the-bold-type-2017","title":"The Bold Type","year":2017,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Comedy"],"overview":"A glimpse into the outrageous lives of Jane, Kat and Sutton, who are working at the nation's top women's magazine, Scarlet, while navigating their careers, identities and individual voices.","poster":"assets/tv-the-bold-type-2017-poster.jpg","backdrop":"assets/tv-the-bold-type-2017-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":69630,"ratings":{"rtCritics":89,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.7,"tmdbVotes":204}},{"id":"tv-brassic-2019","title":"Brassic","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy","Drama","Crime"],"overview":"A group of working-class friends finding unconventional ways to win at life in suburban northern England. These lads have dealt, scammed, bribed and conned their way through adolescence, but now, their dealing and\u2026","poster":"assets/tv-brassic-2019-poster.jpg","backdrop":"assets/tv-brassic-2019-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":92621,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.336,"tmdbVotes":263}},{"id":"movie-12-years-a-slave-2013","title":"12 Years a Slave","year":2013,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","History"],"overview":"In the pre-Civil War United States, Solomon Northup, a free black man from upstate New York, is abducted and sold into slavery. Facing cruelty as well as unexpected kindnesses Solomon struggles not only to stay\u2026","poster":"assets/movie-12-years-a-slave-2013-poster.jpg","backdrop":"assets/movie-12-years-a-slave-2013-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":76203,"ratings":{"rtCritics":95,"rtCriticsLabel":"Certified Fresh","rtAudience":90,"rtAudienceLabel":"Upright","imdb":8.1,"imdbVotes":796313,"tmdb":7.927,"tmdbVotes":12335}},{"id":"movie-101-dalmatians-ii-patch-s-london-adventure-2003","title":"101 Dalmatians II: Patch's London Adventure","year":2003,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Family","Animation","Adventure"],"overview":"Being one of 101 takes its toll on Patch, who doesn't feel unique. When he's accidentally left behind on moving day, he meets his idol, Thunderbolt, who enlists him on a publicity campaign.","poster":"assets/movie-101-dalmatians-ii-patch-s-london-adventure-2003-poster.jpg","backdrop":"assets/movie-101-dalmatians-ii-patch-s-london-adventure-2003-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":13654,"ratings":{"rtCritics":67,"rtCriticsLabel":"Fresh","rtAudience":41,"rtAudienceLabel":"Spilled","imdb":5.7,"imdbVotes":12343,"tmdb":6.025,"tmdbVotes":1274}},{"id":"movie-absolution-2024","title":"Absolution","year":2024,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Crime","Thriller"],"overview":"An aging ex-boxer gangster working as muscle for a Boston crime boss receives an upsetting diagnosis. Despite a faltering memory, he attempts to rectify the sins of his past and reconnect with his estranged\u2026","poster":"assets/movie-absolution-2024-poster.jpg","backdrop":"assets/movie-absolution-2024-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":974453,"ratings":{"rtCritics":56,"rtCriticsLabel":"Rotten","rtAudience":32,"rtAudienceLabel":"Spilled","imdb":5.2,"imdbVotes":11413,"tmdb":5.906,"tmdbVotes":564}},{"id":"movie-all-the-money-in-the-world-2017","title":"All the Money in the World","year":2017,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Crime","History","Thriller"],"overview":"The story of the kidnapping of 16-year-old John Paul Getty III and the desperate attempt by his devoted mother to convince his billionaire grandfather Jean Paul Getty to pay the ransom.","poster":"assets/movie-all-the-money-in-the-world-2017-poster.jpg","backdrop":"assets/movie-all-the-money-in-the-world-2017-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":446791,"ratings":{"rtCritics":79,"rtCriticsLabel":"Certified Fresh","rtAudience":66,"rtAudienceLabel":"Upright","imdb":6.8,"imdbVotes":97448,"tmdb":6.493,"tmdbVotes":2493}},{"id":"movie-the-alto-knights-2025","title":"The Alto Knights","year":2025,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Crime","Drama"],"overview":"Two of New York's most notorious organized crime bosses, Frank Costello and Vito Genovese, vie for control of the city's streets. Once the best of friends, petty jealousies and a series of betrayals place them on a\u2026","poster":"assets/movie-the-alto-knights-2025-poster.jpg","backdrop":"assets/movie-the-alto-knights-2025-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1013601,"ratings":{"rtCritics":39,"rtCriticsLabel":"Rotten","rtAudience":71,"rtAudienceLabel":"Upright","imdb":5.9,"imdbVotes":23017,"tmdb":6.223,"tmdbVotes":485}},{"id":"movie-arctic-dogs-2019","title":"Arctic Dogs","year":2019,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Adventure","Comedy"],"overview":"Animals band together to save the day when the evil Otto Von Walrus hatches a sinister scheme to accelerate global warming and melt the Arctic Circle.","poster":"assets/movie-arctic-dogs-2019-poster.jpg","backdrop":"assets/movie-arctic-dogs-2019-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":416153,"ratings":{"rtCritics":13,"rtCriticsLabel":"Rotten","rtAudience":60,"rtAudienceLabel":"Upright","imdb":4.9,"imdbVotes":2580,"tmdb":5.9,"tmdbVotes":148}},{"id":"movie-a-bronx-tale-1993","title":"A Bronx Tale","year":1993,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Crime"],"overview":"Set in the Bronx during the tumultuous 1960s, an adolescent boy is torn between his honest, working-class father and a violent yet charismatic crime boss. Complicating matters is the youngster's growing attraction -\u2026","poster":"assets/movie-a-bronx-tale-1993-poster.jpg","backdrop":"assets/movie-a-bronx-tale-1993-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1607,"ratings":{"rtCritics":97,"rtCriticsLabel":"Fresh","rtAudience":92,"rtAudienceLabel":"Upright","imdb":7.8,"imdbVotes":191930,"tmdb":7.913,"tmdbVotes":3075}},{"id":"movie-by-any-means-2026","title":"By Any Means","year":2026,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Thriller","History","Crime"],"overview":"In 1960s Mississippi, a young Black FBI agent is forced to partner with a notorious mafia hitman to investigate a wave of brutal civil rights murders.","poster":"assets/movie-by-any-means-2026-poster.jpg","backdrop":"assets/movie-by-any-means-2026-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1380417,"ratings":{"rtCritics":49,"rtCriticsLabel":"Rotten","rtAudience":88,"rtAudienceLabel":"Upright","imdb":6.8,"imdbVotes":3534,"tmdb":6.6,"tmdbVotes":92}},{"id":"movie-captain-america-civil-war-2016","title":"Captain America: Civil War","year":2016,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Adventure","Action","Science Fiction"],"overview":"Following the events of Age of Ultron, the collective governments of the world pass an act designed to regulate all superhuman activity. This polarizes opinion amongst the Avengers, causing two factions to side with\u2026","poster":"assets/movie-captain-america-civil-war-2016-poster.jpg","backdrop":"assets/movie-captain-america-civil-war-2016-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":271110,"ratings":{"rtCritics":90,"rtCriticsLabel":"Certified Fresh","rtAudience":89,"rtAudienceLabel":"Upright","imdb":7.8,"imdbVotes":954943,"tmdb":7.455,"tmdbVotes":24808}},{"id":"movie-captain-america-the-first-avenger-2011","title":"Captain America: The First Avenger","year":2011,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"During World War II, Steve Rogers is a sickly man from Brooklyn who's transformed into super-soldier Captain America to aid in the war effort. Rogers must stop the Red Skull \u2013 Adolf Hitler's ruthless head of\u2026","poster":"assets/movie-captain-america-the-first-avenger-2011-poster.jpg","backdrop":"assets/movie-captain-america-the-first-avenger-2011-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1771,"ratings":{"rtCritics":80,"rtCriticsLabel":"Certified Fresh","rtAudience":75,"rtAudienceLabel":"Upright","imdb":6.9,"imdbVotes":993453,"tmdb":7.012,"tmdbVotes":23473}},{"id":"movie-captain-america-the-winter-soldier-2014","title":"Captain America: The Winter Soldier","year":2014,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"After the cataclysmic events in New York with The Avengers, Steve Rogers, aka Captain America is living quietly in Washington, D.C. and trying to adjust to the modern world. But when a S.H.I.E.L.D. colleague comes\u2026","poster":"assets/movie-captain-america-the-winter-soldier-2014-poster.jpg","backdrop":"assets/movie-captain-america-the-winter-soldier-2014-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":100402,"ratings":{"rtCritics":90,"rtCriticsLabel":"Certified Fresh","rtAudience":92,"rtAudienceLabel":"Upright","imdb":7.7,"imdbVotes":995514,"tmdb":7.654,"tmdbVotes":20688}},{"id":"tv-12-monkeys-2015","title":"12 Monkeys","year":2015,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Sci-Fi & Fantasy","Drama"],"overview":"The provocative story of Cole, a time traveler from a decimated future in a high-stakes race against the clock. Utilizing a dangerous and untested method of time travel, he journeys from 2043 to the present day on a\u2026","poster":"assets/tv-12-monkeys-2015-poster.jpg","backdrop":"assets/tv-12-monkeys-2015-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":60948,"ratings":{"rtCritics":88,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.441,"tmdbVotes":1245}},{"id":"tv-accused-2023","title":"Accused","year":2023,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Crime","Drama"],"overview":"In this crime anthology series, viewers discover how an ordinary person got caught up in an extraordinary situation, ultimately revealing how one wrong turn leads to another, until it\u2019s too late to turn back. Told\u2026","poster":"assets/tv-accused-2023-poster.jpg","backdrop":"assets/tv-accused-2023-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":202097,"ratings":{"rtCritics":61,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.851,"tmdbVotes":87}},{"id":"tv-after-life-2019","title":"After Life","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy","Drama"],"overview":"Tony had a perfect life. But after his wife Lisa suddenly dies, Tony changes. After contemplating taking his own life, he decides instead to live long enough to punish the world by saying and doing whatever he likes\u2026","poster":"assets/tv-after-life-2019-poster.jpg","backdrop":"assets/tv-after-life-2019-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":79410,"ratings":{"rtCritics":72,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.902,"tmdbVotes":1169}},{"id":"tv-all-creatures-great-and-small-1978","title":"All Creatures Great and Small","year":1978,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy","Drama"],"overview":"The trials and misadventures of the staff at a country veterinary office in Yorkshire. James Herriot, a young animal surgeon, moves to a small Yorkshire town to begin his first job.","poster":"assets/tv-all-creatures-great-and-small-1978-poster.jpg","backdrop":"assets/tv-all-creatures-great-and-small-1978-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"center_crop","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":7406,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.8,"tmdbVotes":50}},{"id":"tv-american-housewife-2016","title":"American Housewife","year":2016,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy"],"overview":"A family comedy narrated by Katie, a strong-willed mother, raising her flawed family in a wealthy town filled with perfect wives and their perfect offspring.","poster":"assets/tv-american-housewife-2016-poster.jpg","backdrop":"assets/tv-american-housewife-2016-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":67117,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.7,"tmdbVotes":187}},{"id":"tv-atlantis-2013","title":"Atlantis","year":2013,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action & Adventure","Sci-Fi & Fantasy"],"overview":"A fantasy drama set in a world of legendary heroes and mythical creatures. Far from home and desperate for answers, Jason washes up on the shores of an ancient land. A mysterious place; a world of bull leaping, of\u2026","poster":"assets/tv-atlantis-2013-poster.jpg","backdrop":"assets/tv-atlantis-2013-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":47054,"ratings":{"rtCritics":62,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.4,"tmdbVotes":155}},{"id":"tv-beat-bobby-flay-2013","title":"Beat Bobby Flay","year":2013,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Reality"],"overview":"Two talented chefs go head-to-head for the chance to Beat Bobby Flay. To get to Bobby the chefs must first face off against each other, creating a spectacular dish with a secret ingredient of Bobby's choice. Judges\u2026","poster":"assets/tv-beat-bobby-flay-2013-poster.jpg","backdrop":"assets/tv-beat-bobby-flay-2013-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":62481,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.5,"tmdbVotes":31}},{"id":"tv-benson-1979","title":"Benson","year":1979,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy"],"overview":"A butler deals with life at the governor's mansion.","poster":"assets/tv-benson-1979-poster.jpg","backdrop":"assets/tv-benson-1979-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1849,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7,"tmdbVotes":46}},{"id":"tv-black-rabbit-2025","title":"Black Rabbit","year":2025,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Crime"],"overview":"A rising-star restaurateur is forced into New York's criminal underworld when his chaotic brother returns to town with loan sharks on his trail.","poster":"assets/tv-black-rabbit-2025-poster.jpg","backdrop":"assets/tv-black-rabbit-2025-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":249039,"ratings":{"rtCritics":66,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.983,"tmdbVotes":240}},{"id":"tv-black-ish-2014","title":"black-ish","year":2014,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy"],"overview":"A family man struggles to gain a sense of cultural identity while raising his kids in a predominantly white, upper-middle-class neighborhood.","poster":"assets/tv-black-ish-2014-poster.jpg","backdrop":"assets/tv-black-ish-2014-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":61381,"ratings":{"rtCritics":92,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.1,"tmdbVotes":352}},{"id":"tv-breaking-bad-2008","title":"Breaking Bad","year":2008,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Crime"],"overview":"Walter White, a New Mexico chemistry teacher, is diagnosed with Stage III cancer and given a prognosis of only two years left to live. He becomes filled with a sense of fearlessness and an unrelenting desire to\u2026","poster":"assets/tv-breaking-bad-2008-poster.jpg","backdrop":"assets/tv-breaking-bad-2008-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"center_crop","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1396,"ratings":{"rtCritics":96,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.959,"tmdbVotes":19030}},{"id":"tv-the-capture-2019","title":"The Capture","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Crime","Drama","Mystery"],"overview":"When soldier Shaun Emery's conviction for a murder in Afghanistan is overturned due to flawed video evidence, he returns to life as a free man with his young daughter. But when damning CCTV footage from a night out\u2026","poster":"assets/tv-the-capture-2019-poster.jpg","backdrop":"assets/tv-the-capture-2019-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":93166,"ratings":{"rtCritics":97,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.634,"tmdbVotes":361}}],"duplicate":[{"id":"movie-the-amazing-spider-man-2012","title":"The Amazing Spider-Man","year":2012,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"A teenage Peter Parker grapples with both high school and amazing super-human crises as his alter-ego Spider-Man.","poster":"assets/movie-the-amazing-spider-man-2012-poster.jpg","backdrop":"assets/movie-the-amazing-spider-man-2012-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1930,"ratings":{"rtCritics":71,"rtCriticsLabel":"Certified Fresh","rtAudience":77,"rtAudienceLabel":"Upright","imdb":7,"imdbVotes":791938,"tmdb":6.768,"tmdbVotes":19312}},{"id":"movie-the-amazing-spider-man-2-2014","title":"The Amazing Spider-Man 2","year":2014,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"For Peter Parker, life is busy. Between taking out the bad guys as Spider-Man and spending time with the person he loves, Gwen Stacy, high school graduation cannot come quickly enough. Peter has not forgotten about\u2026","poster":"assets/movie-the-amazing-spider-man-2-2014-poster.jpg","backdrop":"assets/movie-the-amazing-spider-man-2-2014-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":102382,"ratings":{"rtCritics":51,"rtCriticsLabel":"Rotten","rtAudience":64,"rtAudienceLabel":"Upright","imdb":6.6,"imdbVotes":611981,"tmdb":6.567,"tmdbVotes":14919}},{"id":"movie-the-animatrix-2003","title":"The Animatrix","year":2003,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Science Fiction"],"overview":"Straight from the creators of the groundbreaking Matrix trilogy, this collection of short animated films from the world's leading anime directors fuses computer graphics and Japanese anime to provide the background\u2026","poster":"assets/movie-the-animatrix-2003-poster.jpg","backdrop":"assets/movie-the-animatrix-2003-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":55931,"ratings":{"rtCritics":86,"rtCriticsLabel":"Fresh","rtAudience":78,"rtAudienceLabel":"Upright","imdb":7.3,"imdbVotes":91929,"tmdb":7.221,"tmdbVotes":1872}},{"id":"movie-ant-man-and-the-wasp-quantumania-2023","title":"Ant-Man and the Wasp: Quantumania","year":2023,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"Super-Hero partners Scott Lang and Hope van Dyne, along with with Hope's parents Janet van Dyne and Hank Pym, and Scott's daughter Cassie Lang, find themselves exploring the Quantum Realm, interacting with strange\u2026","poster":"assets/movie-ant-man-and-the-wasp-quantumania-2023-poster.jpg","backdrop":"assets/movie-ant-man-and-the-wasp-quantumania-2023-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":640146,"ratings":{"rtCritics":46,"rtCriticsLabel":"Rotten","rtAudience":81,"rtAudienceLabel":"Upright","imdb":6,"imdbVotes":281738,"tmdb":6.197,"tmdbVotes":6236}},{"id":"movie-appleseed-alpha-2014","title":"Appleseed Alpha","year":2014,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Science Fiction","Action"],"overview":"The Third World War (2099\u20132126) devastated part of the Earth. Former nations are reforming while new powers emerge, and groups of humans struggle to survive in ruined cities. The story follows Deunan Knute and her\u2026","poster":"assets/movie-appleseed-alpha-2014-poster.jpg","backdrop":"assets/movie-appleseed-alpha-2014-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"center_crop","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":269650,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":59,"rtAudienceLabel":"Spilled","imdb":6.5,"imdbVotes":9689,"tmdb":6.808,"tmdbVotes":436}},{"id":"movie-aquaman-and-the-lost-kingdom-2023","title":"Aquaman and the Lost Kingdom","year":2023,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Fantasy"],"overview":"Black Manta seeks revenge on Aquaman for his father's death. Wielding the Black Trident's power, he becomes a formidable foe. To defend Atlantis, Arthur (Aquaman) forges an alliance with his imprisoned brother. They\u2026","poster":"assets/movie-aquaman-and-the-lost-kingdom-2023-poster.jpg","backdrop":"assets/movie-aquaman-and-the-lost-kingdom-2023-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":572802,"ratings":{"rtCritics":33,"rtCriticsLabel":"Rotten","rtAudience":79,"rtAudienceLabel":"Upright","imdb":5.6,"imdbVotes":122422,"tmdb":6.48,"tmdbVotes":3748}},{"id":"movie-the-avengers-2012","title":"The Avengers","year":2012,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Science Fiction","Action","Adventure"],"overview":"When an unexpected enemy emerges and threatens global safety and security, Nick Fury, director of the international peacekeeping agency known as S.H.I.E.L.D., finds himself in need of a team to pull the world back\u2026","poster":"assets/movie-the-avengers-2012-poster.jpg","backdrop":"assets/movie-the-avengers-2012-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":24428,"ratings":{"rtCritics":91,"rtCriticsLabel":"Certified Fresh","rtAudience":91,"rtAudienceLabel":"Upright","imdb":8,"imdbVotes":1590693,"tmdb":8.084,"tmdbVotes":40262}},{"id":"movie-avengers-confidential-black-widow-punisher-2014","title":"Avengers Confidential: Black Widow & Punisher","year":2014,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Science Fiction","Action"],"overview":"When the Punisher takes out a black-market weapons dealer, he stumbles upon a far-reaching terrorist plot devised by a group known as Leviathan.","poster":"assets/movie-avengers-confidential-black-widow-punisher-2014-poster.jpg","backdrop":"assets/movie-avengers-confidential-black-widow-punisher-2014-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":257346,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":55,"rtAudienceLabel":"Spilled","imdb":5.7,"imdbVotes":5166,"tmdb":6.368,"tmdbVotes":303}},{"id":"movie-avengers-age-of-ultron-2015","title":"Avengers: Age of Ultron","year":2015,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"When Tony Stark tries to jumpstart a dormant peacekeeping program, things go awry and Earth\u2019s Mightiest Heroes are put to the ultimate test as the fate of the planet hangs in the balance. As the villainous Ultron\u2026","poster":"assets/movie-avengers-age-of-ultron-2015-poster.jpg","backdrop":"assets/movie-avengers-age-of-ultron-2015-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":99861,"ratings":{"rtCritics":75,"rtCriticsLabel":"Certified Fresh","rtAudience":82,"rtAudienceLabel":"Upright","imdb":7.3,"imdbVotes":1025876,"tmdb":7.278,"tmdbVotes":25289}},{"id":"movie-avengers-infinity-war-2018","title":"Avengers: Infinity War","year":2018,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Adventure","Action","Science Fiction"],"overview":"As the Avengers and their allies have continued to protect the world from threats too large for any one hero to handle, a new danger has emerged from the cosmic shadows: Thanos. A despot of intergalactic infamy, his\u2026","poster":"assets/movie-avengers-infinity-war-2018-poster.jpg","backdrop":"assets/movie-avengers-infinity-war-2018-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":299536,"ratings":{"rtCritics":85,"rtCriticsLabel":"Certified Fresh","rtAudience":92,"rtAudienceLabel":"Upright","imdb":8.4,"imdbVotes":1421954,"tmdb":8.246,"tmdbVotes":33331}},{"id":"movie-batman-ninja-2018","title":"Batman Ninja","year":2018,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Action","Science Fiction"],"overview":"Batman, along with many of his allies and adversaries, finds himself transported to feudal Japan by Gorilla Grodd's time displacement machine.","poster":"assets/movie-batman-ninja-2018-poster.jpg","backdrop":"assets/movie-batman-ninja-2018-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":485942,"ratings":{"rtCritics":84,"rtCriticsLabel":"Fresh","rtAudience":60,"rtAudienceLabel":"Upright","imdb":5.6,"imdbVotes":24579,"tmdb":5.9,"tmdbVotes":1106}},{"id":"movie-batman-v-superman-dawn-of-justice-2016","title":"Batman v Superman: Dawn of Justice","year":2016,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Fantasy"],"overview":"Fearing the actions of a god-like Super Hero left unchecked, Gotham City\u2019s own formidable, forceful vigilante takes on Metropolis\u2019s most revered, modern-day savior, while the world wrestles with what sort of hero it\u2026","poster":"assets/movie-batman-v-superman-dawn-of-justice-2016-poster.jpg","backdrop":"assets/movie-batman-v-superman-dawn-of-justice-2016-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":209112,"ratings":{"rtCritics":28,"rtCriticsLabel":"Rotten","rtAudience":63,"rtAudienceLabel":"Upright","imdb":6.4,"imdbVotes":801382,"tmdb":6.014,"tmdbVotes":19527}},{"id":"movie-batman-the-dark-knight-returns-part-1-2012","title":"Batman: The Dark Knight Returns, Part 1","year":2012,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Science Fiction","Action","Animation"],"overview":"Batman has not been seen for ten years. A new breed of criminal ravages Gotham City, forcing 55-year-old Bruce Wayne back into the cape and cowl. But, does he still have what it takes to fight crime in a new era?","poster":"assets/movie-batman-the-dark-knight-returns-part-1-2012-poster.jpg","backdrop":"assets/movie-batman-the-dark-knight-returns-part-1-2012-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":123025,"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":93,"rtAudienceLabel":"Upright","imdb":7.9,"imdbVotes":68943,"tmdb":7.742,"tmdbVotes":1766}},{"id":"movie-black-adam-2022","title":"Black Adam","year":2022,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"Nearly 5,000 years after he was bestowed with the almighty powers of the Egyptian gods\u2014and imprisoned just as quickly\u2014Black Adam is freed from his earthly tomb, ready to unleash his unique form of justice on the\u2026","poster":"assets/movie-black-adam-2022-poster.jpg","backdrop":"assets/movie-black-adam-2022-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":436270,"ratings":{"rtCritics":39,"rtCriticsLabel":"Rotten","rtAudience":87,"rtAudienceLabel":"Upright","imdb":6.1,"imdbVotes":309624,"tmdb":6.747,"tmdbVotes":7370}},{"id":"movie-black-panther-2018","title":"Black Panther","year":2018,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"King T'Challa returns home to the reclusive, technologically advanced African nation of Wakanda to serve as his country's new leader. However, T'Challa soon finds that he is challenged for the throne by factions\u2026","poster":"assets/movie-black-panther-2018-poster.jpg","backdrop":"assets/movie-black-panther-2018-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":284054,"ratings":{"rtCritics":96,"rtCriticsLabel":"Certified Fresh","rtAudience":null,"rtAudienceLabel":"Spilled","imdb":7.3,"imdbVotes":931120,"tmdb":7.36,"tmdbVotes":24190}},{"id":"movie-black-panther-wakanda-forever-2022","title":"Black Panther: Wakanda Forever","year":2022,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Adventure","Science Fiction"],"overview":"Queen Ramonda, Shuri, M\u2019Baku, Okoye and the Dora Milaje fight to protect their nation from intervening world powers in the wake of King T\u2019Challa\u2019s death. As the Wakandans strive to embrace their next chapter, the\u2026","poster":"assets/movie-black-panther-wakanda-forever-2022-poster.jpg","backdrop":"assets/movie-black-panther-wakanda-forever-2022-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":505642,"ratings":{"rtCritics":84,"rtCriticsLabel":"Certified Fresh","rtAudience":93,"rtAudienceLabel":"Upright","imdb":6.6,"imdbVotes":405088,"tmdb":6.984,"tmdbVotes":7920}},{"id":"movie-blame-2017","title":"BLAME!","year":2017,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Drama","Science Fiction"],"overview":"In the distant technological future, civilization has reached its ultimate Net-based form. An \"infection\" in the past caused the automated systems to spiral out of order, resulting in a multi-leveled city structure\u2026","poster":"assets/movie-blame-2017-poster.jpg","backdrop":"assets/movie-blame-2017-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":409421,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":61,"rtAudienceLabel":"Upright","imdb":6.6,"imdbVotes":10258,"tmdb":6.523,"tmdbVotes":370}},{"id":"movie-bleach-the-movie-fade-to-black-2008","title":"Bleach the Movie: Fade to Black","year":2008,"type":"movie","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action","Animation","Fantasy"],"overview":"A strange disturbance in the World of the Living sends Ichigo and Kon to the Soul Society, where the Seireitei has been devastated by an explosion of reishi and Rukia is missing. Stranger still, none of the Soul\u2026","poster":"assets/movie-bleach-the-movie-fade-to-black-2008-poster.jpg","backdrop":"assets/movie-bleach-the-movie-fade-to-black-2008-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":17165,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":67,"rtAudienceLabel":"Upright","imdb":7.1,"imdbVotes":3693,"tmdb":7.1,"tmdbVotes":206}},{"id":"tv-90-day-fiance-before-the-90-days-2017","title":"90 Day Fianc\u00e9: Before the 90 Days","year":2017,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Reality"],"overview":"Follow couples who have an existing relationship online, but haven't met in person. We'll experience their journey as they travel to the other's foreign country for the first time in an attempt to establish an\u2026","poster":"assets/tv-90-day-fiance-before-the-90-days-2017-poster.jpg","backdrop":"assets/tv-90-day-fiance-before-the-90-days-2017-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":73319,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.5,"tmdbVotes":45}},{"id":"tv-90-day-fiance-the-other-way-2019","title":"90 Day Fianc\u00e9: The Other Way","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Reality"],"overview":"Americans move to a foreign country all in the name of love. Will uprooting their lives in the United States pay off, or will they be packing up and moving back to America brokenhearted?","poster":"assets/tv-90-day-fiance-the-other-way-2019-poster.jpg","backdrop":"assets/tv-90-day-fiance-the-other-way-2019-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":90046,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.8,"tmdbVotes":34}},{"id":"tv-the-100-2014","title":"The 100","year":2014,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Sci-Fi & Fantasy","Action & Adventure","Drama"],"overview":"100 years in the future, when the Earth has been abandoned due to radioactivity, the last surviving humans live on an ark orbiting the planet \u2014 but the ark won't last forever. So the repressive regime picks 100\u2026","poster":"assets/tv-the-100-2014-poster.jpg","backdrop":"assets/tv-the-100-2014-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":48866,"ratings":{"rtCritics":93,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.878,"tmdbVotes":8855}},{"id":"tv-the-abbott-and-costello-show-1952","title":"The Abbott and Costello Show","year":1952,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy"],"overview":"Bud and Lou are unemployed actors living in Mr. Fields\u2019 boarding house. Lou\u2019s girlfriend Hillary lives across the hall. Many situations arise leading to slapstick and puns.","poster":"assets/tv-the-abbott-and-costello-show-1952-poster.jpg","backdrop":"assets/tv-the-abbott-and-costello-show-1952-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":11821,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.2,"tmdbVotes":22}},{"id":"tv-accel-world-2012","title":"Accel World","year":2012,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Action & Adventure","Drama"],"overview":"A short, overweight student uses the Neuro Link, an evolution of the Nerve Gear, to escape himself from the reality. But his skills in the virtual world brings him to the attention of Kuroyukihime, a popular student\u2026","poster":"assets/tv-accel-world-2012-poster.jpg","backdrop":"assets/tv-accel-world-2012-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"center_crop","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":43167,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.429,"tmdbVotes":163}},{"id":"tv-ahsoka-2023","title":"Ahsoka","year":2023,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Sci-Fi & Fantasy","Action & Adventure","Drama"],"overview":"Former Jedi Knight Ahsoka Tano investigates an emerging threat to a vulnerable galaxy.","poster":"assets/tv-ahsoka-2023-poster.jpg","backdrop":"assets/tv-ahsoka-2023-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":114461,"ratings":{"rtCritics":85,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.4,"tmdbVotes":1351}},{"id":"tv-american-dad-2005","title":"American Dad!","year":2005,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Comedy"],"overview":"The series focuses on an eccentric motley crew that is the Smith family and their three housemates: Father, husband, and breadwinner Stan Smith; his better half housewife, Francine Smith; their college-aged daughter,\u2026","poster":"assets/tv-american-dad-2005-poster.jpg","backdrop":"assets/tv-american-dad-2005-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1433,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.022,"tmdbVotes":2481}},{"id":"tv-american-gods-2017","title":"American Gods","year":2017,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Drama","Mystery","Sci-Fi & Fantasy"],"overview":"An ex-con becomes the traveling partner of a conman who turns out to be one of the older gods trying to recruit troops to battle the upstart deities. Based on Neil Gaiman's fantasy novel.","poster":"assets/tv-american-gods-2017-poster.jpg","backdrop":"assets/tv-american-gods-2017-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":46639,"ratings":{"rtCritics":75,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.1,"tmdbVotes":1852}},{"id":"tv-andromeda-2000","title":"Andromeda","year":2000,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action & Adventure","Drama","Sci-Fi & Fantasy"],"overview":"Captain Dylan Hunt and his crew quest to restore a government that once presided over an extended peace and prosperity.","poster":"assets/tv-andromeda-2000-poster.jpg","backdrop":"assets/tv-andromeda-2000-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":2985,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.068,"tmdbVotes":315}},{"id":"tv-aqua-teen-hunger-force-2000","title":"Aqua Teen Hunger Force","year":2000,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Comedy"],"overview":"The surreal adventures of three anthropomorphic fast food items: Master Shake, Frylock and Meatwad, and their human nextdoor neighbor, Carl Brutananadilewski.","poster":"assets/tv-aqua-teen-hunger-force-2000-poster.jpg","backdrop":"assets/tv-aqua-teen-hunger-force-2000-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":251,"ratings":{"rtCritics":null,"rtCriticsLabel":"Rotten","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.5,"tmdbVotes":272}},{"id":"tv-arifureta-from-commonplace-to-world-s-strongest-2019","title":"Arifureta: From Commonplace to World's Strongest","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"Hajime Nagumo and his high school class are suddenly summoned to a fantastical land as heroes. But while most of his classmates have powerful stats and abilities, Hajime does not. Underappreciated and unprepared, he\u2026","poster":"assets/tv-arifureta-from-commonplace-to-world-s-strongest-2019-poster.jpg","backdrop":"assets/tv-arifureta-from-commonplace-to-world-s-strongest-2019-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":86034,"ratings":{"rtCritics":null,"rtCriticsLabel":null,"rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.382,"tmdbVotes":662}},{"id":"tv-arrow-2012","title":"Arrow","year":2012,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Crime","Drama","Action & Adventure"],"overview":"Spoiled billionaire playboy Oliver Queen is missing and presumed dead when his yacht is lost at sea. He returns five years later a changed man, determined to clean up the city as a hooded vigilante armed with a bow.","poster":"assets/tv-arrow-2012-poster.jpg","backdrop":"assets/tv-arrow-2012-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":1412,"ratings":{"rtCritics":86,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.834,"tmdbVotes":6537}},{"id":"tv-avatar-the-last-airbender-2024","title":"Avatar: The Last Airbender","year":2024,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action & Adventure","Sci-Fi & Fantasy","Drama"],"overview":"A young boy known as the Avatar must master the four elemental powers to save a world at war \u2014 and fight a ruthless enemy bent on stopping him.","poster":"assets/tv-avatar-the-last-airbender-2024-poster.jpg","backdrop":"assets/tv-avatar-the-last-airbender-2024-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":82452,"ratings":{"rtCritics":66,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.8,"tmdbVotes":1406}},{"id":"tv-avatar-seven-havens-2026","title":"Avatar: Seven Havens","year":2026,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"In a world shattered by a devastating cataclysm, a young Earthbender discovers she's the new Avatar after Korra. But in this dangerous era, that title marks her as humanity's destroyer, not its savior. Hunted by both\u2026","poster":"assets/tv-avatar-seven-havens-2026-poster.jpg","backdrop":"assets/tv-avatar-seven-havens-2026-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":284833,"ratings":{"rtCritics":100,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":8.9,"tmdbVotes":183}},{"id":"tv-batman-the-brave-and-the-bold-2008","title":"Batman: The Brave and the Bold","year":2008,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Animation","Action & Adventure","Sci-Fi & Fantasy"],"overview":"The Caped Crusader is teamed up with Blue Beetle, Green Arrow, Aquaman and countless others in his quest to uphold justice.","poster":"assets/tv-batman-the-brave-and-the-bold-2008-poster.jpg","backdrop":"assets/tv-batman-the-brave-and-the-bold-2008-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":15804,"ratings":{"rtCritics":96,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.6,"tmdbVotes":295}},{"id":"tv-batwoman-2019","title":"Batwoman","year":2019,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Sci-Fi & Fantasy","Action & Adventure"],"overview":"Kate Kane, armed with a passion for social justice and a flair for speaking her mind, soars onto the streets of Gotham as Batwoman, an out lesbian and highly trained street fighter primed to snuff out the failing\u2026","poster":"assets/tv-batwoman-2019-poster.jpg","backdrop":"assets/tv-batwoman-2019-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":89247,"ratings":{"rtCritics":83,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.8,"tmdbVotes":1619}},{"id":"tv-big-mouth-2017","title":"Big Mouth","year":2017,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Comedy","Animation"],"overview":"Teenage friends find their lives upended by the wonders and horrors of puberty in this edgy comedy from real-life pals Nick Kroll and Andrew Goldberg.","poster":"assets/tv-big-mouth-2017-poster.jpg","backdrop":"assets/tv-big-mouth-2017-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":74204,"ratings":{"rtCritics":95,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":7.591,"tmdbVotes":1274}},{"id":"tv-black-lightning-2018","title":"Black Lightning","year":2018,"type":"tv","runtimeSeconds":null,"seasonCount":null,"communityRating":null,"criticRating":null,"genres":["Action & Adventure","Sci-Fi & Fantasy","Drama"],"overview":"Jefferson Pierce is a man wrestling with a secret. As the father of two daughters and principal of a charter high school that also serves as a safe haven for young people in a New Orleans neighborhood overrun by gang\u2026","poster":"assets/tv-black-lightning-2018-poster.jpg","backdrop":"assets/tv-black-lightning-2018-backdrop.jpg","played":null,"playCount":null,"resumeSeconds":null,"progress":null,"addedAt":null,"lastPlayedAt":null,"availability":"not_here","availabilityEvidence":"retained_profile_membership_and_native_request_ledger","source":"materialized_personal_recommendation","rank":null,"watchStateKnown":false,"artwork":{"posterKind":"poster","backdropKind":"poster_crop"},"availabilityIsSnapshot":true,"tmdbId":71663,"ratings":{"rtCritics":92,"rtCriticsLabel":"Fresh","rtAudience":null,"rtAudienceLabel":null,"imdb":null,"imdbVotes":null,"tmdb":6.907,"tmdbVotes":991}}]}} diff --git a/wolfskin-design/src/test/resources/wolfskin-requests.json b/wolfskin-design/src/test/resources/wolfskin-requests.json new file mode 100644 index 00000000..507ebd65 --- /dev/null +++ b/wolfskin-design/src/test/resources/wolfskin-requests.json @@ -0,0 +1,217 @@ +{ + "source": "Locked Opus fixture/fixture.json; index.html EXAMPLES() pool order", + "items": [ + { + "id": "x1", + "mediaType": "tv", + "tmdbId": 11821, + "title": "The Abbott and Costello Show", + "requesterKey": "justin", + "requesterName": "Justin", + "actorKey": "justin", + "actorName": "Justin", + "stage": "Downloading", + "poster": "tv-the-abbott-and-costello-show-1952-poster.jpg", + "ratings": [ + { + "mark": "tmdb", + "score": 7.2, + "percentage": false + } + ] + }, + { + "id": "x2", + "mediaType": "movie", + "tmdbId": 13483, + "title": "Awake", + "requesterKey": "mindel", + "requesterName": "Mindel", + "actorKey": "justin", + "actorName": "Justin", + "stage": "AlmostReady", + "poster": "movie-awake-2007-poster.jpg", + "ratings": [ + { + "mark": "rotten", + "score": 23, + "percentage": true + }, + { + "mark": "spilled", + "score": 55, + "percentage": true + }, + { + "mark": "imdb", + "score": 6.5, + "percentage": false + } + ] + }, + { + "id": "x3", + "mediaType": "tv", + "tmdbId": 70785, + "title": "Anne with an E", + "requesterKey": "shared", + "requesterName": "Shared", + "actorKey": "mindel", + "actorName": "Mindel", + "stage": "Searching", + "poster": "tv-anne-with-an-e-2017-poster.jpg", + "ratings": [ + { + "mark": "fresh", + "score": 63, + "percentage": true + } + ] + }, + { + "id": "x4", + "mediaType": "movie", + "tmdbId": 99861, + "title": "Avengers: Age of Ultron", + "requesterKey": "justin", + "requesterName": "Justin", + "actorKey": "justin", + "actorName": "Justin", + "stage": "Waiting", + "poster": "movie-avengers-age-of-ultron-2015-poster.jpg", + "ratings": [ + { + "mark": "fresh", + "score": 75, + "percentage": true + }, + { + "mark": "upright", + "score": 82, + "percentage": true + }, + { + "mark": "imdb", + "score": 7.3, + "percentage": false + } + ] + }, + { + "id": "x5", + "mediaType": "movie", + "tmdbId": 1033148, + "title": "Die My Love", + "requesterKey": "mindel", + "requesterName": "Mindel", + "actorKey": "mindel", + "actorName": "Mindel", + "stage": "Failed", + "poster": "movie-die-my-love-2025-poster.jpg", + "ratings": [ + { + "mark": "fresh", + "score": 74, + "percentage": true + }, + { + "mark": "spilled", + "score": 45, + "percentage": true + }, + { + "mark": "imdb", + "score": 6, + "percentage": false + } + ] + }, + { + "id": "x6", + "mediaType": "movie", + "tmdbId": 416153, + "title": "Arctic Dogs", + "requesterKey": "shared", + "requesterName": "Shared", + "actorKey": "justin", + "actorName": "Justin", + "stage": "Ready", + "poster": "movie-arctic-dogs-2019-poster.jpg", + "ratings": [ + { + "mark": "rotten", + "score": 13, + "percentage": true + }, + { + "mark": "upright", + "score": 60, + "percentage": true + }, + { + "mark": "imdb", + "score": 4.9, + "percentage": false + } + ] + }, + { + "id": "x7", + "mediaType": "movie", + "tmdbId": 76203, + "title": "12 Years a Slave", + "requesterKey": "justin", + "requesterName": "Justin", + "actorKey": "shared", + "actorName": "Shared", + "stage": "Waiting", + "poster": "movie-12-years-a-slave-2013-poster.jpg", + "ratings": [ + { + "mark": "fresh", + "score": 95, + "percentage": true + }, + { + "mark": "upright", + "score": 90, + "percentage": true + }, + { + "mark": "imdb", + "score": 8.1, + "percentage": false + } + ] + }, + { + "id": "x8", + "mediaType": "movie", + "tmdbId": 14069, + "title": "The Girl Who Leapt Through Time", + "requesterKey": "mindel", + "requesterName": "Mindel", + "actorKey": "justin", + "actorName": "Justin", + "stage": "Waiting", + "poster": "movie-the-girl-who-leapt-through-time-2006-poster.jpg", + "ratings": [ + { + "mark": "fresh", + "score": 87, + "percentage": true + }, + { + "mark": "upright", + "score": 90, + "percentage": true + }, + { + "mark": "imdb", + "score": 7.6, + "percentage": false + } + ] + } + ] +} diff --git a/wolfskin-design/src/test/resources/wolfskin-requests/movie-12-years-a-slave-2013-poster.jpg b/wolfskin-design/src/test/resources/wolfskin-requests/movie-12-years-a-slave-2013-poster.jpg new file mode 100644 index 00000000..ff1f55e6 Binary files /dev/null and b/wolfskin-design/src/test/resources/wolfskin-requests/movie-12-years-a-slave-2013-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/wolfskin-requests/movie-arctic-dogs-2019-poster.jpg b/wolfskin-design/src/test/resources/wolfskin-requests/movie-arctic-dogs-2019-poster.jpg new file mode 100644 index 00000000..07552443 Binary files /dev/null and b/wolfskin-design/src/test/resources/wolfskin-requests/movie-arctic-dogs-2019-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/wolfskin-requests/movie-avengers-age-of-ultron-2015-poster.jpg b/wolfskin-design/src/test/resources/wolfskin-requests/movie-avengers-age-of-ultron-2015-poster.jpg new file mode 100644 index 00000000..300840ff Binary files /dev/null and b/wolfskin-design/src/test/resources/wolfskin-requests/movie-avengers-age-of-ultron-2015-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/wolfskin-requests/movie-awake-2007-poster.jpg b/wolfskin-design/src/test/resources/wolfskin-requests/movie-awake-2007-poster.jpg new file mode 100644 index 00000000..32595897 Binary files /dev/null and b/wolfskin-design/src/test/resources/wolfskin-requests/movie-awake-2007-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/wolfskin-requests/movie-die-my-love-2025-poster.jpg b/wolfskin-design/src/test/resources/wolfskin-requests/movie-die-my-love-2025-poster.jpg new file mode 100644 index 00000000..f6eca818 Binary files /dev/null and b/wolfskin-design/src/test/resources/wolfskin-requests/movie-die-my-love-2025-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/wolfskin-requests/movie-the-girl-who-leapt-through-time-2006-poster.jpg b/wolfskin-design/src/test/resources/wolfskin-requests/movie-the-girl-who-leapt-through-time-2006-poster.jpg new file mode 100644 index 00000000..ded6cd2a Binary files /dev/null and b/wolfskin-design/src/test/resources/wolfskin-requests/movie-the-girl-who-leapt-through-time-2006-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/wolfskin-requests/tv-anne-with-an-e-2017-poster.jpg b/wolfskin-design/src/test/resources/wolfskin-requests/tv-anne-with-an-e-2017-poster.jpg new file mode 100644 index 00000000..55d443b4 Binary files /dev/null and b/wolfskin-design/src/test/resources/wolfskin-requests/tv-anne-with-an-e-2017-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/wolfskin-requests/tv-the-abbott-and-costello-show-1952-poster.jpg b/wolfskin-design/src/test/resources/wolfskin-requests/tv-the-abbott-and-costello-show-1952-poster.jpg new file mode 100644 index 00000000..7d6768ea Binary files /dev/null and b/wolfskin-design/src/test/resources/wolfskin-requests/tv-the-abbott-and-costello-show-1952-poster.jpg differ diff --git a/wolfskin-design/src/test/resources/wolfskin-shell.json b/wolfskin-design/src/test/resources/wolfskin-shell.json new file mode 100644 index 00000000..d99323a9 --- /dev/null +++ b/wolfskin-design/src/test/resources/wolfskin-shell.json @@ -0,0 +1,78 @@ +{ + "source": "Locked Opus fixture/fixture.json; shell-only projection; debug/test only", + "profiles": [ + { + "key": "justin", + "name": "Justin", + "initial": "J", + "color": "#62c4ff", + "destinations": { + "Home": { + "kind": "home" + }, + "Movies": { + "kind": "library", + "collection": "movies" + }, + "Shows": { + "kind": "library", + "collection": "shows" + }, + "Anime": { + "kind": "library", + "collection": "anime" + }, + "Discover": { + "kind": "discover", + "collection": "discover" + } + } + }, + { + "key": "mindel", + "name": "Mindel", + "initial": "M", + "color": "#ff9d72", + "destinations": { + "Home": { + "kind": "home" + }, + "Movies": { + "kind": "library", + "collection": "movies" + }, + "Shows": { + "kind": "library", + "collection": "shows" + }, + "Discover": { + "kind": "discover", + "collection": "discover" + } + } + }, + { + "key": "shared", + "name": "Shared", + "initial": "S", + "color": "#9be38f", + "destinations": { + "Home": { + "kind": "home" + }, + "Movies": { + "kind": "library", + "collection": "movies" + }, + "Shows": { + "kind": "library", + "collection": "shows" + }, + "Discover": { + "kind": "discover", + "collection": "discover" + } + } + } + ] +} diff --git a/wolfskin-design/title-tokens.json b/wolfskin-design/title-tokens.json new file mode 100644 index 00000000..9f7ad2e6 --- /dev/null +++ b/wolfskin-design/title-tokens.json @@ -0,0 +1,130 @@ +{ + "title": { + "lineGap": {"dp": 11, "px": 22, "source": "index.html:214"}, + "lineLift": {"dp": -2, "px": -4, "source": "index.html:214"}, + "overviewGap": {"dp": 17, "px": 34, "source": "index.html:216"}, + "factsGap": {"dp": 11, "px": 22, "source": "index.html:104"}, + "factsBottom": {"dp": 7, "px": 14, "source": "index.html:104"}, + "factsHeight": {"dp": 19, "px": 38, "source": "index.html:104 .h-meta minimum height"}, + "titleBottom": {"dp": 8, "px": 16, "source": "index.html:103"}, + "iconGap": {"dp": 7, "px": 14, "source": "index.html:108"}, + "iconSize": {"dp": 16, "px": 32, "source": "index.html:275"}, + "captionTop": {"dp": 8, "px": 16, "source": "index.html:281"}, + "progressWidth": {"dp": 160, "px": 320, "source": "index.html:218"}, + "progressBottom": {"dp": 15, "px": 30, "source": "index.html:217"}, + "progressGap": {"dp": 9, "px": 18, "source": "index.html:217"}, + "progressLift": {"dp": -7, "px": -14, "source": "index.html:217"}, + "castHeight": {"dp": 197, "px": 394, "source": "index.html:1018"}, + "castNameTop": {"dp": 108, "px": 216, "source": "index.html:289"}, + "castNameSide": {"dp": 6, "px": 12, "source": "index.html:289"}, + "personTop": {"dp": 85, "px": 170, "source": "index.html:293"}, + "personGap": {"dp": 24, "px": 48, "source": "index.html:293"}, + "personNameBottom": {"dp": 5, "px": 10, "source": "index.html:296"}, + "personNoteBottom": {"dp": 3, "px": 6, "source": "index.html:297"}, + "captionWidth": {"dp": 320, "px": 640, "source": "index.html:1242"}, + "sheetPaddingTop": {"dp": 40, "px": 80, "source": "index.html:227"}, + "sheetPaddingSide": {"dp": 32, "px": 64, "source": "index.html:227"}, + "sheetGap": {"dp": 9, "px": 18, "source": "index.html:227"}, + "sheetSubLift": {"dp": -4, "px": -8, "source": "index.html:229"}, + "sheetSubBottom": {"dp": 7, "px": 14, "source": "index.html:229"}, + "sheetLabelTop": {"dp": 4, "px": 8, "source": "index.html:230"}, + "sheetButtonTop": {"dp": 6, "px": 12, "source": "index.html:241 .sheet .btn margin-top"}, + "sheetRowSide": {"dp": 13, "px": 26, "source": "index.html:231"}, + "versionRowVertical": {"dp": 10, "px": 20, "source": "index.html:1936"}, + "trackHeight": {"dp": 42, "px": 84, "source": "index.html:1941"}, + "trackGap": {"dp": 6, "px": 12, "source": "index.html:1941"}, + "radioSize": {"dp": 20, "px": 40, "source": "index.html:234"}, + "radioDot": {"dp": 8, "px": 16, "source": "index.html:236"}, + "radioBorder": {"dp": 1.5, "px": 3, "source": "index.html:234"}, + "infoGap": {"dp": 7, "px": 14, "source": "index.html:1948"}, + "infoLabelWidth": {"dp": 100, "px": 200, "source": "index.html:318"}, + "infoRowGap": {"dp": 3, "px": 6, "source": "index.html:318"}, + "infoColumnGap": {"dp": 10, "px": 20, "source": "index.html:318"}, + "infoKey": {"$type": "typography", "sp": 12, "px": 24, "weight": 650, "$value": {"fontWeight": 650}, "source": "index.html:319"}, + "gridHeight": {"dp": 244, "px": 488, "source": "index.html:1019"}, + "minimumEndPadding": {"dp": 40, "px": 80, "source": "index.html:1042"}, + "ratingGap": {"dp": 10, "px": 20, "source": "index.html:156"}, + "ratingMarkGap": {"dp": 4, "px": 8, "source": "index.html:157"}, + "initialSize": {"$type": "typography", "sp": 32, "px": 64, "weight": 800, "$value": {"fontWeight": 800}, "source": "index.html:288"}, + "personInitialSize": {"$type": "typography", "sp": 48, "px": 96, "weight": 800, "$value": {"fontWeight": 800}, "source": "index.html:1317"}, + "fallbackHue": {"$value": 260, "source": "index.html:130"}, + "skeletonKickerWidth": {"dp": 210, "px": 420, "source": "index.html:1322"}, + "skeletonKickerHeight": {"dp": 17, "px": 34, "source": "index.html:1322"}, + "skeletonTitleGap": {"dp": 13, "px": 26, "source": "index.html:1322"}, + "skeletonFactsGap": {"dp": 12, "px": 24, "source": "index.html:1322"}, + "skeletonOverviewGap": {"dp": 15, "px": 30, "source": "index.html:1322"}, + "skeletonTitleWidth": {"dp": 380, "px": 760, "source": "index.html:1322"}, + "skeletonTitleHeight": {"dp": 46, "px": 92, "source": "index.html:1322"}, + "skeletonFactsWidth": {"dp": 280, "px": 560, "source": "index.html:1322"}, + "skeletonOverviewWidth": {"dp": 490, "px": 980, "source": "index.html:1322"}, + "skeletonOverviewHeight": {"dp": 55, "px": 110, "source": "index.html:1322"}, + "skeletonPlayWidth": {"dp": 110, "px": 220, "source": "index.html:1322"}, + "dLine": {"$type": "typography", "sp": 13, "px": 26, "weight": 400, "$value": {"fontWeight": 400}, "source": "index.html:214"}, + "iconCaption": {"$type": "typography", "sp": 13, "px": 26, "weight": 400, "$value": {"fontWeight": 400}, "source": "index.html:281"}, + "lineIcon": {"dp": 14, "px": 28, "source": "index.html:215"}, + "chipHeight": {"dp": 34, "px": 68, "source": "index.html:185"}, + "chipPadding": {"dp": 14, "px": 28, "source": "index.html:185"}, + "chipGap": {"dp": 8, "px": 16, "source": "index.html:184"}, + "chipTop": {"dp": 8, "px": 16, "source": "index.html:184"}, + "chipBorder": {"dp": 1, "px": 2, "source": "index.html:188"}, + "heroSheetRight": {"dp": 90, "px": 180, "source": "index.html:97"}, + "heroSheetTop": {"dp": 75, "px": 150, "source": "index.html:97"}, + "gridHeadingTop": {"dp": 12, "px": 24, "source": "index.html:1312"}, + "castName": {"$type": "typography", "sp": 13, "px": 26, "weight": 700, "$value": {"fontWeight": 700}, "source": "index.html:290"}, + "receiptSide": {"dp": 15, "px": 30, "source": "index.html:243"}, + "receiptTop": {"dp": 14, "px": 28, "source": "index.html:243"}, + "receiptGap": {"dp": 5, "px": 10, "source": "index.html:243"}, + "receiptIcon": {"dp": 18, "px": 36, "source": "index.html:245"}, + "receiptTitle": {"$type": "typography", "sp": 18, "px": 36, "weight": 700, "$value": {"fontWeight": 700}, "source": "index.html:244"}, + "toastMaxWidth": {"dp": 380, "px": 760, "source": "index.html:270"}, + "toastSide": {"dp": 14, "px": 28, "source": "index.html:270"}, + "toastTop": {"dp": 11, "px": 22, "source": "index.html:270"}, + "heroAmbientBackground": {"$type": "gradient", "$value": "radial-gradient(120% 90% at 70% 20%,var(--surface3),var(--bg))", "source": "index.html:94"}, + "dimScrollPx": {"$value": 1400, "source": "index.html:1541"}, + "dimMaximum": {"$value": 0.7, "source": "index.html:1541"}, + "errorTop": {"dp": 85, "px": 170, "source": "index.html:1457,194"}, + "errorSide": {"dp": 20, "px": 40, "source": "index.html:194"}, + "errorVertical": {"dp": 17, "px": 34, "source": "index.html:194"}, + "errorHeadingBottom": {"dp": 4, "px": 8, "source": "index.html:195"}, + "errorBodyBottom": {"dp": 12, "px": 24, "source": "index.html:198"}, + "errorTitle": {"$type": "typography", "sp": 18, "px": 36, "weight": 700, "$value": {"fontWeight": 700}, "source": "index.html:195"}, + "fallbackGlyph": {"dp": 22, "px": 44, "source": "index.html:131"}, + "fallbackInset": {"dp": 11, "px": 22, "source": "index.html:130-131"}, + "tileSheetInset": {"dp": 9, "px": 18, "source": "index.html:128"}, + "tileSheetLeft": {"dp": 11, "px": 22, "source": "index.html:128"}, + "tileSheetRadius": {"dp": 5, "px": 10, "source": "index.html:128"}, + "tileAmbientBlur": {"dp": 13, "px": 26, "source": "index.html:129"}, + "tileAmbientInset": {"dp": 15, "px": 30, "source": "index.html:129"}, + "tileShadowRadius": {"dp": 15, "px": 30, "source": "index.html:128"}, + "tileShadowY": {"dp": 5, "px": 10, "source": "index.html:128"}, + "tileShadowOpacity": {"$value": 0.5, "source": "index.html:128"}, + "tileAmbientBrightness": {"$value": 0.5, "source": "index.html:129"}, + "cardFallbackGradient": {"$type": "gradient", "$value": "linear-gradient(160deg,hsl(var(--h) 22% 22%),hsl(var(--h) 26% 10%))", "source": "index.html:130"}, + "personFallbackGradient": {"$type": "gradient", "$value": "linear-gradient(160deg,hsl(var(--h) 24% 30%),hsl(var(--h) 26% 14%))", "source": "index.html:288"}, + "initialsColor": {"$type": "color", "$value": "#ffffffd1", "source": "index.html:288"}, + "fallbackGlyphColor": {"$type": "color", "$value": "#ffffff73", "source": "index.html:131"}, + "fallbackTitle": {"$type": "typography", "sp": 14, "px": 28, "weight": 700, "lineHeight": 1.15, "$value": {"fontWeight": 700}, "source": "index.html:132"}, + "tileOverlayTop": {"dp": 27, "px": 54, "source": "index.html:135"}, + "tileOverlaySide": {"dp": 11, "px": 22, "source": "index.html:135"}, + "tileOverlayBottom": {"dp": 9, "px": 18, "source": "index.html:135"}, + "cardOverlayOpacity": {"$value": 0.92, "source": "index.html:135"}, + "cardProgressInset": {"dp": 9, "px": 18, "source": "index.html:138"}, + "tileProgressBottom": {"dp": 5, "px": 10, "source": "index.html:140"}, + "ambientInset": {"dp": 40, "px": 80, "source": "index.html:96"}, + "ambientScale": {"$value": 1.1, "source": "index.html:96"}, + "posterShadowRadius": {"dp": 40, "px": 80, "source": "index.html:97"}, + "posterShadowY": {"dp": 15, "px": 30, "source": "index.html:97"}, + "posterShadowOpacity": {"$value": 0.6, "source": "index.html:97"}, + "sheetShadowRadius": {"dp": 40, "px": 80, "source": "index.html:227"}, + "sheetShadowX": {"dp": -15, "px": -30, "source": "index.html:227"}, + "sheetShadowOpacity": {"$value": 0.5, "source": "index.html:227"} + }, + "savedIndicator": { + "height": {"dp": 26, "px": 52, "source": "index.html:87"}, + "side": {"dp": 10, "px": 20, "source": "index.html:87"}, + "gap": {"dp": 5, "px": 10, "source": "index.html:87"}, + "icon": {"dp": 14, "px": 28, "source": "index.html:88"}, + "border": {"dp": 1, "px": 2, "source": "index.html:87"}, + "borderOpacity": {"$value": 0.5, "source": "index.html:87"} + } +} diff --git a/wolfskin-design/tokens.css b/wolfskin-design/tokens.css new file mode 100644 index 00000000..4d3f3488 --- /dev/null +++ b/wolfskin-design/tokens.css @@ -0,0 +1,492 @@ +/* Generated from the locked TV token sources. */ +:root { + --color-bg: #07070a; + --color-surface: #13131a; + --color-surface2: #1b1b25; + --color-surface3: #252532; + --color-fg: #f4f4f6; + --color-muted: #f4f4f6bd; + --color-dim: #f4f4f68f; + --color-border: #ffffff1a; + --color-accent: #cc9fff; + --color-accentSoft: #2c1a3f; + --color-accentText: #e4cbff; + --color-ok: #89da9b; + --color-warn: #f4c26a; + --color-fail: #f97770; + --color-onFocus: #0b0b10; + --color-buttonSecondary: #ffffff24; + --color-buttonSecondaryFocused: #ffffff42; + --color-titleButtonSecondary: #2c2c38c7; + --color-titleButtonSecondaryFocused: #464654e6; + --color-chipRest: #ffffff1a; + --color-navBlobRest: #ffffff1a; + --color-listRowRest: #ffffff0d; + --color-sheetScrim: #0000009e; + --color-badgeRest: #07070abf; + --color-badgeWatched: #f4f4f6d9; + --color-progressTrack: #ffffff38; + --color-railEmpty: #f4f4f638; + --personColor-justin: #62c4ff; + --personColor-mindel: #ff9d72; + --personColor-shared: #9be38f; + --gradient-heroScrim: linear-gradient(90deg,rgb(7 7 10 / .92) 0%,rgb(7 7 10 / .55) 42%,rgb(7 7 10 / 0) 70%),linear-gradient(0deg,var(--bg) 0%,rgb(7 7 10 / .6) 26%,rgb(7 7 10 / 0) 48%); + --gradient-detailScrim: linear-gradient(90deg,rgb(7 7 10 / .94) 0%,rgb(7 7 10 / .6) 46%,rgb(7 7 10 / .05) 75%),linear-gradient(0deg,var(--bg) 0%,rgb(7 7 10 / .35) 34%,rgb(7 7 10 / 0) 55%); + --gradient-navBand: linear-gradient(180deg,rgb(7 7 10 / .72),rgb(7 7 10 / 0)); + --gradient-navBandSolid: linear-gradient(180deg,var(--bg) 0%,var(--bg) 84%,rgb(7 7 10 / 0) 100%); + --gradient-ratingPlate: linear-gradient(180deg,rgb(7 7 10 / .9) 0%,rgb(7 7 10 / .72) 52%,rgb(7 7 10 / 0) 100%); + --gradient-tileOverlay: linear-gradient(0deg,rgb(7 7 10 / .92),rgb(7 7 10 / 0)); + --gradient-fallbackArt: linear-gradient(160deg,hsl(var(--h,260) 22% 22%),hsl(var(--h,260) 26% 10%)); + --gradient-entryTile: linear-gradient(150deg,hsl(var(--h) 30% 26%),hsl(var(--h) 30% 12%)); + --gradient-initialsCircle: linear-gradient(160deg,hsl(var(--h) 24% 30%),hsl(var(--h) 26% 14%)); + --type-displayDetail: 88.0px; + --type-displayHero: 84.0px; + --type-screenTitle: 64.0px; + --type-sectionTitle: 56.0px; + --type-sheetTitle: 44.0px; + --type-wordmark: 36.0px; + --type-stateTitle: 36.0px; + --type-rowHeading: 34.0px; + --type-pickerName: 34.0px; + --type-nav: 30.0px; + --type-listTitle: 30.0px; + --type-body: 28.0px; + --type-button: 28.0px; + --type-label: 26.0px; + --type-caption: 24.0px; + --type-ratingPlate: 28.0px; + --radius-card: 16.0px; + --radius-button: 38.0px; + --radius-chip: 34.0px; + --radius-navItem: 32.0px; + --radius-listRow: 24.0px; + --radius-panel: 22.0px; + --radius-menu: 26.0px; + --radius-heroSheet: 18.0px; + --radius-cardSheet: 10.0px; + --radius-thumb: 12.0px; + --radius-pill: 22.0px; + --radius-progress: 4.0px; + --layout-safeSide: 96.0px; + --layout-contentWidth: 1728.0px; + --layout-safeTopPicker: 54.0px; + --layout-navBand: 150.0px; + --layout-navPaddingTop: 44.0px; + --layout-navItemHeight: 64.0px; + --layout-navItemPaddingX: 26.0px; + --layout-navItemGap: 12.0px; + --layout-wordmarkGap: 40.0px; + --layout-navUnderline: 4.0px; + --layout-navBlobAvatarPad: 8.0px; + --layout-navSolidAfter: 40.0px; + --layout-pinnedLine: 168.0px; + --layout-windowAhead: 700.0px; + --layout-rowHeadingBand: 60.0px; + --layout-rowGapAfter: 44.0px; + --layout-gridRowGap: 28.0px; + --layout-row_hero: 820.0px; + --layout-row_phero: 740.0px; + --layout-row_section: 150.0px; + --layout-row_chips: 104.0px; + --layout-row_note: 84.0px; + --layout-row_state: 300.0px; + --layout-row_lhead: 236.0px; + --layout-row_dhead: 900.0px; + --layout-row_phead: 470.0px; + --layout-row_gh: 84.0px; + --layout-row_endcta: 200.0px; + --layout-row_srow: 124.0px; + --layout-heroCopyLeft: 96.0px; + --layout-heroCopyBottom: 110.0px; + --layout-heroCopyWidth: 1000.0px; + --layout-heroOverviewMax: 960.0px; + --layout-detailCopyTop: 200.0px; + --layout-detailCopyWidth: 1060.0px; + --layout-buttonHeight: 76.0px; + --layout-buttonPaddingX: 38.0px; + --layout-buttonGap: 20.0px; + --layout-buttonIcon: 30.0px; + --layout-iconButton: 76.0px; + --layout-iconCaptionLine: 38.0px; + --layout-sheetWidth: 800.0px; + --layout-sheetRow: 100.0px; + --layout-stateWidth: 1100.0px; + --layout-captionOffset: 18.0px; + --layout-badge: 48.0px; + --layout-badgeInset: 14.0px; + --layout-progressBar: 8.0px; + --layout-pickerAvatar: 220.0px; + --layout-pickerGap: 90.0px; + --layout-pickerStackGap: 70.0px; + --layout-gear: 56.0px; + --layout-navAvatar: 64.0px; + --layout-castCircle: 200.0px; + --layout-personPortrait: 240.0px; + --motion-fast: 140ms; + --motion-base: 160ms; + --motion-scroll: 180ms; + --motion-ratingDwell: 350ms; + --motion-toast: 3200ms; + --requests-sheetPaddingY: 80.0px; + --requests-sheetPaddingX: 64.0px; + --requests-sheetGap: 18.0px; + --requests-sheetTitleLineHeight: 56.0px; + --requests-sheetTitleBaseline: 44.0px; + --requests-titleLineHeight: 39.0px; + --requests-titleBaseline: 31.0px; + --requests-factsLineHeight: 31.2px; + --requests-factsBaseline: 24.0px; + --requests-stageLineHeight: 39.6px; + --requests-stageLabelLineHeight: 33.8px; + --requests-stageBaseline: 24.0px; + --requests-emptyMargin: 20.0px; + --requests-rowPaddingY: 14.0px; + --requests-rowPaddingX: 18.0px; + --requests-rowGap: 24.0px; + --requests-listGap: 6.0px; + --requests-stageMargin: 4.0px; + --requests-stageGlyph: 28.0px; + --requests-stageGap: 10.0px; + --requests-readinessGapX: 22.0px; + --requests-readinessGapY: 10.0px; + --requests-readinessMargin: 8.0px; + --requests-readinessGlyph: 26.0px; + --requests-chevron: 30.0px; + --requests-receiptPaddingY: 28.0px; + --requests-receiptPaddingX: 30.0px; + --requests-receiptGap: 10.0px; + --requests-receiptGlyph: 36.0px; + --requests-buttonMargin: 12.0px; + --requests-skeletonTitleWidth: 360.0px; + --requests-skeletonTitleHeight: 34.0px; + --requests-skeletonSubtitleWidth: 240.0px; + --requests-skeletonSubtitleHeight: 26.0px; + --requests-skeletonGap: 12.0px; + --requests-ratingsGap: 20.0px; + --requests-ratingsEntryGap: 8.0px; + --requests-shadowBlur: 80.0px; + --requests-shadowOffset: -30.0px; + --requests-shadowColor: #00000080; + --shell-navLabelFade: 200ms; + --shell-zero: 0.0px; + --shell-stageWidth: 1920.0px; + --shell-stageHeight: 1080.0px; + --shell-wordmarkWidth: 169.0px; + --shell-wordmarkTop: 73.6px; + --shell-navHomeWidth: 149.0px; + --shell-navDiscoverWidth: 198.0px; + --shell-navMoviesWidth: 171.0px; + --shell-navShowsWidth: 161.0px; + --shell-navAnimeWidth: 158.0px; + --shell-navItemTop: 65.0px; + --shell-pickerTitleTop: 272.3px; + --shell-pickerPeopleTop: 425.5px; + --shell-pickerNameGap: 26.0px; + --shell-pickerGearTop: 751.7px; + --shell-pickerGearCaptionTop: 72.0px; + --shell-pickerLetter: 100.0px; + --shell-pickerSkeletonNameWidth: 140.0px; + --shell-pickerSkeletonNameHeight: 40.0px; + --shell-pickerLoadingTitleTop: 247.4px; + --shell-pickerLoadingPeopleTop: 400.6px; + --shell-pickerLoadingButtonTop: 756.6px; + --shell-pickerErrorTitleTop: 297.6px; + --shell-pickerErrorPanelTop: 450.8px; + --shell-pickerErrorPanelWidth: 980.0px; + --shell-pickerErrorPanelHeight: 185.6px; + --shell-pickerErrorButtonTop: 706.4px; + --shell-settingsHeaderTop: 150.0px; + --shell-settingsHeaderAvatar: 52.0px; + --shell-settingsHeaderGap: 24.0px; + --shell-settingsRowTop: 10.0px; + --shell-settingsRowPadding: 30.0px; + --shell-settingsRowGap: 24.0px; + --shell-settingsIcon: 36.0px; + --shell-settingsPillHeight: 40.0px; + --shell-settingsPillStroke: 2.0px; + --shell-settingsPillBorder: #ffffff38; + --shell-settingsPillFocusedBorder: #0b0b1066; + --shell-settingsPillPadding: 16.0px; + --shell-settingsPillGap: 12.0px; + --shell-settingsChevron: 30.0px; + --shell-settingsEndPadding: 620.0px; + --shell-panelPaddingX: 30.0px; + --shell-panelPaddingY: 28.0px; + --shell-panelGap: 10.0px; + --shell-panelHeadingGap: 14.0px; + --shell-panelIcon: 36.0px; + --shell-skeletonRadius: 10.0px; + --library-chipHeight: 68.0px; + --library-chipPadding: 28.0px; + --library-chipGap: 16.0px; + --library-chipTop: 16.0px; + --library-chipIcon: 26.0px; + --library-captionWidth: 640.0px; + --library-captionFactsGap: 18.0px; + --library-badgeIcon: 28.0px; + --library-plateTop: 14.0px; + --library-plateSide: 16.0px; + --library-plateBottom: 46.0px; + --library-plateInlineDescent: 6.6px; + --library-plateFloor: 24.0px; + --library-railWidth: 52.0px; + --library-railLetterHeight: 30.0px; + --library-railFocusHeight: 44.0px; + --library-railLetter: 24.0px; + --library-railFocusedLetter: 28.0px; + --library-panelPaddingX: 40.0px; + --library-panelPaddingY: 34.0px; + --library-panelTextGap: 24.0px; + --library-panelTitleGap: 8.0px; + --library-panelIconGap: 14.0px; + --library-panelTop: 20.0px; + --library-borderWidth: 2.0px; + --library-chipContentGap: 12.0px; + --library-tailIcon: 44.0px; + --library-tailPadding: 20.0px; + --library-tailGap: 10.0px; + --library-badgeRing: 3.0px; + --library-seeAllGap: 8.0px; + --library-tailDescription: 24.0px; + --library-headerSubtitle: 30.0px; + --library-fallbackPadding: 22.0px; + --library-fallbackIcon: 44.0px; + --lift-cardBlur: 50.0px; + --lift-cardY: 18.0px; + --lift-buttonBlur: 40.0px; + --lift-buttonY: 12.0px; + --lift-heroBlur: 80.0px; + --lift-heroY: 30.0px; + --lift-sheetBlur: 80.0px; + --lift-sheetX: -30.0px; + --title-lineGap: 22.0px; + --title-lineLift: -4.0px; + --title-overviewGap: 34.0px; + --title-factsGap: 22.0px; + --title-factsBottom: 14.0px; + --title-factsHeight: 38.0px; + --title-titleBottom: 16.0px; + --title-iconGap: 14.0px; + --title-iconSize: 32.0px; + --title-captionTop: 16.0px; + --title-progressWidth: 320.0px; + --title-progressBottom: 30.0px; + --title-progressGap: 18.0px; + --title-progressLift: -14.0px; + --title-castHeight: 394.0px; + --title-castNameTop: 216.0px; + --title-castNameSide: 12.0px; + --title-personTop: 170.0px; + --title-personGap: 48.0px; + --title-personNameBottom: 10.0px; + --title-personNoteBottom: 6.0px; + --title-captionWidth: 640.0px; + --title-sheetPaddingTop: 80.0px; + --title-sheetPaddingSide: 64.0px; + --title-sheetGap: 18.0px; + --title-sheetSubLift: -8.0px; + --title-sheetSubBottom: 14.0px; + --title-sheetLabelTop: 8.0px; + --title-sheetButtonTop: 12.0px; + --title-sheetRowSide: 26.0px; + --title-versionRowVertical: 20.0px; + --title-trackHeight: 84.0px; + --title-trackGap: 12.0px; + --title-radioSize: 40.0px; + --title-radioDot: 16.0px; + --title-radioBorder: 3.0px; + --title-infoGap: 14.0px; + --title-infoLabelWidth: 200.0px; + --title-infoRowGap: 6.0px; + --title-infoColumnGap: 20.0px; + --title-infoKey: 24.0px; + --title-gridHeight: 488.0px; + --title-minimumEndPadding: 80.0px; + --title-ratingGap: 20.0px; + --title-ratingMarkGap: 8.0px; + --title-initialSize: 64.0px; + --title-personInitialSize: 96.0px; + --title-skeletonKickerWidth: 420.0px; + --title-skeletonKickerHeight: 34.0px; + --title-skeletonTitleGap: 26.0px; + --title-skeletonFactsGap: 24.0px; + --title-skeletonOverviewGap: 30.0px; + --title-skeletonTitleWidth: 760.0px; + --title-skeletonTitleHeight: 92.0px; + --title-skeletonFactsWidth: 560.0px; + --title-skeletonOverviewWidth: 980.0px; + --title-skeletonOverviewHeight: 110.0px; + --title-skeletonPlayWidth: 220.0px; + --title-dLine: 26.0px; + --title-iconCaption: 26.0px; + --title-lineIcon: 28.0px; + --title-chipHeight: 68.0px; + --title-chipPadding: 28.0px; + --title-chipGap: 16.0px; + --title-chipTop: 16.0px; + --title-chipBorder: 2.0px; + --title-heroSheetRight: 180.0px; + --title-heroSheetTop: 150.0px; + --title-gridHeadingTop: 24.0px; + --title-castName: 26.0px; + --title-receiptSide: 30.0px; + --title-receiptTop: 28.0px; + --title-receiptGap: 10.0px; + --title-receiptIcon: 36.0px; + --title-receiptTitle: 36.0px; + --title-toastMaxWidth: 760.0px; + --title-toastSide: 28.0px; + --title-toastTop: 22.0px; + --title-heroAmbientBackground: radial-gradient(120% 90% at 70% 20%,var(--surface3),var(--bg)); + --title-errorTop: 170.0px; + --title-errorSide: 40.0px; + --title-errorVertical: 34.0px; + --title-errorHeadingBottom: 8.0px; + --title-errorBodyBottom: 24.0px; + --title-errorTitle: 36.0px; + --title-fallbackGlyph: 44.0px; + --title-fallbackInset: 22.0px; + --title-tileSheetInset: 18.0px; + --title-tileSheetLeft: 22.0px; + --title-tileSheetRadius: 10.0px; + --title-tileAmbientBlur: 26.0px; + --title-tileAmbientInset: 30.0px; + --title-tileShadowRadius: 30.0px; + --title-tileShadowY: 10.0px; + --title-cardFallbackGradient: linear-gradient(160deg,hsl(var(--h) 22% 22%),hsl(var(--h) 26% 10%)); + --title-personFallbackGradient: linear-gradient(160deg,hsl(var(--h) 24% 30%),hsl(var(--h) 26% 14%)); + --title-initialsColor: #ffffffd1; + --title-fallbackGlyphColor: #ffffff73; + --title-fallbackTitle: 28.0px; + --title-tileOverlayTop: 54.0px; + --title-tileOverlaySide: 22.0px; + --title-tileOverlayBottom: 18.0px; + --title-cardProgressInset: 18.0px; + --title-tileProgressBottom: 10.0px; + --title-ambientInset: 80.0px; + --title-posterShadowRadius: 80.0px; + --title-posterShadowY: 30.0px; + --title-sheetShadowRadius: 80.0px; + --title-sheetShadowX: -30.0px; + --savedIndicator-height: 52.0px; + --savedIndicator-side: 20.0px; + --savedIndicator-gap: 10.0px; + --savedIndicator-icon: 28.0px; + --savedIndicator-border: 2.0px; + --home-kickerGap: 12.0px; + --home-kickerBottom: 10.0px; + --home-titleBottom: 16.0px; + --home-factsHeight: 38.0px; + --home-factsBottom: 14.0px; + --home-factsGap: 22.0px; + --home-overviewBottom: 30.0px; + --home-cardPadding: 22.0px; + --home-cardOverlayTop: 54.0px; + --home-cardOverlayBottom: 18.0px; + --home-sectionTop: 40.0px; + --home-sectionAvatar: 56.0px; + --home-sectionGap: 22.0px; + --home-stateTextBottom: 24.0px; + --home-stateTop: 20.0px; + --home-statePaddingX: 40.0px; + --home-statePaddingY: 34.0px; + --home-stateGap: 8.0px; + --home-stateIcon: 36.0px; + --home-captionWidth: 640.0px; + --home-plateTop: 14.0px; + --home-plateSide: 16.0px; + --home-plateFade: 46.0px; + --home-ratingGap: 20.0px; + --home-ratingMarkGap: 8.0px; + --home-heroSkeletonWidth: 640.0px; + --home-heroSkeletonHeight: 84.0px; + --home-heroSkeletonFactsWidth: 460.0px; + --home-heroSkeletonFactsHeight: 34.0px; + --home-heroSkeletonButtonWidth: 260.0px; + --home-heroSkeletonGap: 22.0px; + --home-heroSkeletonButtonGap: 40.0px; + --home-artGlyph: 44.0px; + --home-cardSheetLeft: 22.0px; + --home-cardSheetTop: 18.0px; + --home-cardSheetInset: 36.0px; + --home-heroSheetRight: 180.0px; + --home-heroSheetTop: 150.0px; + --home-cardBlur: 26.0px; + --home-heroBlur: 60.0px; + --home-progressInset: 18.0px; + --home-progressBottom: 10.0px; + --home-endTop: 40.0px; + --home-frameBottom: 80.0px; + --home-toastPadding: 28.0px; + --home-toastTop: 150.0px; + --home-toastWidth: 760.0px; + --home-toastPaddingY: 22.0px; + --home-toastGap: 14.0px; + --home-toastShadowBlur: 60.0px; + --home-toastShadowY: 20.0px; + --home-cardWashInset: 30.0px; + --home-heroWashInset: 80.0px; + --home-noteTop: 14.0px; + --home-noteGap: 16.0px; + --home-hairline: 2.0px; + --home-savedHeight: 52.0px; + --home-savedPadding: 20.0px; + --home-savedGap: 10.0px; + --home-savedIcon: 28.0px; + --home-savedRadius: 28.0px; + --home-posterProgressBottom: 12.0px; + --discover-sheetPaddingX: 64.0px; + --discover-sheetPaddingY: 80.0px; + --discover-sheetGap: 18.0px; + --discover-sheetSubGap: 14.0px; + --discover-sheetRowPadding: 26.0px; + --discover-sheetAvatar: 60.0px; + --discover-sheetRadio: 40.0px; + --discover-sheetRadioDot: 16.0px; + --discover-sheetPersonGap: 24.0px; + --discover-sheetButtonTop: 12.0px; + --discover-chipTop: 16.0px; + --discover-chipHeight: 68.0px; + --discover-chipPadding: 28.0px; + --discover-chipGap: 16.0px; + --discover-heroTitleGap: 16.0px; + --discover-heroKickerGap: 10.0px; + --discover-heroMetaGap: 14.0px; + --discover-heroOverviewGap: 30.0px; + --discover-heroFactsGap: 22.0px; + --discover-heroFactsHeight: 38.0px; + --discover-heroSheetRight: 180.0px; + --discover-heroSheetTop: 140.0px; + --discover-heroSheetWidth: 360.0px; + --discover-heroSheetHeight: 540.0px; + --discover-dotSize: 14.0px; + --discover-dotActive: 44.0px; + --discover-dotGap: 14.0px; + --discover-dotMargin: 18.0px; + --discover-dotChevron: 40.0px; + --discover-stateTop: 20.0px; + --discover-statePaddingX: 40.0px; + --discover-statePaddingY: 34.0px; + --discover-stateTextGap: 24.0px; + --discover-noteTop: 14.0px; + --discover-headerTop: 150.0px; + --discover-headerGap: 24.0px; + --discover-entryPaddingX: 22.0px; + --discover-entryPaddingY: 20.0px; + --discover-entryText: 30.0px; + --discover-sheetRadioRing: 3.0px; + --discover-skeletonNameWidth: 260.0px; + --discover-skeletonNameHeight: 34.0px; + --discover-sheetSubTop: -8.0px; + --discover-sheetRatingTop: -10.0px; + --discover-sheetRatingBottom: 6.0px; + --discover-sheetLabelTop: 8.0px; + --discover-noteIcon: 30.0px; + --discover-noteGap: 16.0px; + --discover-frameBottomMin: 80.0px; + --discover-anchorFitTop: 700.0px; + --discover-anchorBottomClearance: 40.0px; + --discover-stageGap: 10.0px; + --discover-ambientInset: 80.0px; + --discover-ambientBlur: 60.0px; +} diff --git a/wolfskin-design/tokens.json b/wolfskin-design/tokens.json new file mode 100644 index 00000000..95fa62f2 --- /dev/null +++ b/wolfskin-design/tokens.json @@ -0,0 +1,1592 @@ +{ + "$description": "Wolfskin TV design tokens, extracted by script from the locked prototype (data/tv-v2/opus-final-2026-11-05/index.html, sha256 ee8844fc...). Values are CSS px on the 1920x1080 stage; the box renders 1920x1080 at 320 dpi = density 2.0, so dp/sp = px / 2. Format follows the W3C design-tokens draft ($type/$value); extra keys: px, dp|sp, source (page file:line), usedBy, page (the page value where q1 consolidated it).", + "meta": { + "density": 2.0, + "stagePx": [ + 1920, + 1080 + ], + "stageDp": [ + 960, + 540 + ], + "source": "data/tv-v2/opus-final-2026-11-05/index.html", + "sourceSha256": "ee8844fc6d0237a3727de0d9454db8e5cf3bb14083fb7877d7bb0f4233c6e23d", + "generator": "data/tv-spec-lane/scratch/extract.py + build_tokens.py" + }, + "color": { + "bg": { + "$type": "color", + "$value": "#07070a", + "css": "#07070a", + "source": "index.html:10", + "usedBy": "app background; stage; focus-ring gap colour; hero/detail scrim end; nav band when solid" + }, + "surface": { + "$type": "color", + "$value": "#13131a", + "css": "#13131a", + "source": "index.html:10", + "usedBy": "sheets (side panels), state panels, See all card, skeleton blocks, Try again/Show more tail cards" + }, + "surface2": { + "$type": "color", + "$value": "#1b1b25", + "css": "#1b1b25", + "source": "index.html:10", + "usedBy": "card art placeholder behind images; menus; toast; person-page portrait placeholder" + }, + "surface3": { + "$type": "color", + "$value": "#252532", + "css": "#252532", + "source": "index.html:10", + "usedBy": "hero radial placeholder; Coming-in thumbnail placeholder" + }, + "fg": { + "$type": "color", + "$value": "#f4f4f6", + "css": "#f4f4f6", + "source": "index.html:11", + "usedBy": "primary text; primary button fill; focused nav blob; focused chip/row/list fill (inverse focus); white focus ring on avatars and the gear" + }, + "muted": { + "$type": "color", + "$value": "#f4f4f6bd", + "css": "rgb(244 244 246 / .74)", + "source": "index.html:11", + "usedBy": "secondary text: facts lines, overviews, captions under cards, unfocused nav labels, row descriptions" + }, + "dim": { + "$type": "color", + "$value": "#f4f4f68f", + "css": "rgb(244 244 246 / .56)", + "source": "index.html:11", + "usedBy": "tertiary text: sheet labels, small print, pill text, the resting gear" + }, + "border": { + "$type": "color", + "$value": "#ffffff1a", + "css": "rgb(255 255 255 / .10)", + "source": "index.html:11", + "usedBy": "hairline borders on See all/tail cards and state panels" + }, + "accent": { + "$type": "color", + "$value": "#cc9fff", + "css": "oklch(78% 0.14 305)", + "source": "index.html:12", + "usedBy": "lilac focus ring on cards and buttons; progress fills; current-destination underline; See all glyph; requested badge ring; Downloading/Almost ready stage words" + }, + "accentSoft": { + "$type": "color", + "$value": "#2c1a3f", + "css": "oklch(26% 0.07 305)", + "source": "index.html:12", + "usedBy": "selected chip fill (chip.on)" + }, + "accentText": { + "$type": "color", + "$value": "#e4cbff", + "css": "oklch(88% 0.08 305)", + "source": "index.html:12", + "usedBy": "kicker line above hero titles; d-line on title pages; availability words in captions; selected chip text; wordmark \"skin\"" + }, + "ok": { + "$type": "color", + "$value": "#89da9b", + "css": "oklch(82% 0.12 150)", + "source": "index.html:13", + "usedBy": "held badge (green check); Ready stage word; readiness Done" + }, + "warn": { + "$type": "color", + "$value": "#f4c26a", + "css": "oklch(84% 0.12 80)", + "source": "index.html:13", + "usedBy": "Saved HH:MM chip; warning state titles and icons; toast icon; Try again tail glyph" + }, + "fail": { + "$type": "color", + "$value": "#f97770", + "css": "oklch(72% 0.16 25)", + "source": "index.html:13", + "usedBy": "failed-request badge ring; Failed stage word; Refused receipt title" + }, + "onFocus": { + "$type": "color", + "$value": "#0b0b10", + "css": "#0b0b10", + "source": "index.html:84", + "usedBy": "text and icons on any white focus fill: focused nav item, primary button label, focused chip/row/list item, avatar letters" + }, + "buttonSecondary": { + "$type": "color", + "$value": "#ffffff24", + "css": "rgb(255 255 255 / .14)", + "source": "index.html:107", + "usedBy": "secondary (non-primary) pill button at rest on hero rows" + }, + "buttonSecondaryFocused": { + "$type": "color", + "$value": "#ffffff42", + "css": "rgb(255 255 255 / .26)", + "source": "index.html:111", + "usedBy": "secondary pill button while focused (plus the accent ring)" + }, + "titleButtonSecondary": { + "$type": "color", + "$value": "#2c2c38c7", + "css": "rgb(44 44 56 / .78)", + "source": "index.html:279", + "usedBy": "title-page secondary and icon buttons at rest (dark backing so labels read over bright art)" + }, + "titleButtonSecondaryFocused": { + "$type": "color", + "$value": "#464654e6", + "css": "rgb(70 70 84 / .9)", + "source": "index.html:280", + "usedBy": "title-page secondary and icon buttons while focused" + }, + "chipRest": { + "$type": "color", + "$value": "#ffffff1a", + "css": "rgb(255 255 255 / .10)", + "source": "index.html:185", + "usedBy": "filter/sort/season chips at rest" + }, + "navBlobRest": { + "$type": "color", + "$value": "#ffffff1a", + "css": "rgb(255 255 255 / .10)", + "source": "index.html:76", + "usedBy": "nav indicator resting behind the current destination while focus is elsewhere" + }, + "listRowRest": { + "$type": "color", + "$value": "#ffffff0d", + "css": "rgb(255 255 255 / .05)", + "source": "index.html:231", + "usedBy": "sheet rows (person, version, track) at rest; Settings rows (.srow) use the same value" + }, + "sheetScrim": { + "$type": "color", + "$value": "#0000009e", + "css": "rgb(0 0 0 / .62)", + "source": "index.html:226", + "usedBy": "full-screen scrim behind every side sheet" + }, + "badgeRest": { + "$type": "color", + "$value": "#07070abf", + "css": "rgb(7 7 10 / .75)", + "source": "index.html:141", + "usedBy": "badge disc behind the requested/failed glyph" + }, + "badgeWatched": { + "$type": "color", + "$value": "#f4f4f6d9", + "css": "rgb(244 244 246 / .85)", + "source": "index.html:145", + "usedBy": "watched badge disc (defined in CSS; no surface draws it in the locked page) [unused]" + }, + "progressTrack": { + "$type": "color", + "$value": "#ffffff38", + "css": "rgb(255 255 255 / .22)", + "source": "index.html:138", + "usedBy": "progress-bar track on wide cards; title-page progress track uses rgb(255 255 255 / .2) (.d-prog i)" + }, + "railEmpty": { + "$type": "color", + "$value": "#f4f4f638", + "css": "rgb(244 244 246 / .22)", + "source": "index.html:206", + "usedBy": "letter rail: letters with no titles (rail shown only at >= 200 titles)" + } + }, + "personColor": { + "justin": { + "$type": "color", + "$value": "#62c4ff", + "initial": "J", + "source": "fixture/fixture.json profiles[].color", + "usedBy": "Justin: avatar fill in Who's watching (220 px), nav avatar (64 px), person rows in sheets (60 px), library/settings headers (52/56 px); letter in color.onFocus" + }, + "mindel": { + "$type": "color", + "$value": "#ff9d72", + "initial": "M", + "source": "fixture/fixture.json profiles[].color", + "usedBy": "Mindel: avatar fill in Who's watching (220 px), nav avatar (64 px), person rows in sheets (60 px), library/settings headers (52/56 px); letter in color.onFocus" + }, + "shared": { + "$type": "color", + "$value": "#9be38f", + "initial": "S", + "source": "fixture/fixture.json profiles[].color", + "usedBy": "Shared: avatar fill in Who's watching (220 px), nav avatar (64 px), person rows in sheets (60 px), library/settings headers (52/56 px); letter in color.onFocus" + } + }, + "gradient": { + "heroScrim": { + "$type": "gradient", + "$value": "linear-gradient(90deg,rgb(7 7 10 / .92) 0%,rgb(7 7 10 / .55) 42%,rgb(7 7 10 / 0) 70%),linear-gradient(0deg,var(--bg) 0%,rgb(7 7 10 / .6) 26%,rgb(7 7 10 / 0) 48%)", + "source": "index.html:99", + "usedBy": "Home hero and Discover picks hero: left-to-right darkening (92% at 0, 55% at 42%, 0 at 70%) plus bottom fade into bg (0..48%)" + }, + "detailScrim": { + "$type": "gradient", + "$value": "linear-gradient(90deg,rgb(7 7 10 / .94) 0%,rgb(7 7 10 / .6) 46%,rgb(7 7 10 / .05) 75%),linear-gradient(0deg,var(--bg) 0%,rgb(7 7 10 / .35) 34%,rgb(7 7 10 / 0) 55%)", + "source": "index.html:210", + "usedBy": "title page backdrop scrim (94% / 60% at 46% / 5% at 75%; bottom fade to 55%)" + }, + "navBand": { + "$type": "gradient", + "$value": "linear-gradient(180deg,rgb(7 7 10 / .72),rgb(7 7 10 / 0))", + "source": "index.html:71", + "usedBy": "nav band at scrollTop <= 40: 72% bg fading to 0 over 150 px" + }, + "navBandSolid": { + "$type": "gradient", + "$value": "linear-gradient(180deg,var(--bg) 0%,var(--bg) 84%,rgb(7 7 10 / 0) 100%)", + "source": "index.html:72", + "usedBy": "nav band once the frame scrolled > 40 px: solid bg to 84% of 150 px, then fades" + }, + "ratingPlate": { + "$type": "gradient", + "$value": "linear-gradient(180deg,rgb(7 7 10 / .9) 0%,rgb(7 7 10 / .72) 52%,rgb(7 7 10 / 0) 100%)", + "source": "index.html:162", + "usedBy": "rating plate on the focused card: 90% bg at top, 72% at 52%, 0 at bottom" + }, + "tileOverlay": { + "$type": "gradient", + "$value": "linear-gradient(0deg,rgb(7 7 10 / .92),rgb(7 7 10 / 0))", + "source": "index.html:135", + "usedBy": "bottom gradient under tile/wide titles" + }, + "fallbackArt": { + "$type": "gradient", + "$value": "linear-gradient(160deg,hsl(var(--h,260) 22% 22%),hsl(var(--h,260) 26% 10%))", + "source": "index.html:130", + "usedBy": "no-art card: 160deg two-tone gradient, hue = hash(title) (hueOf, index.html:744)" + }, + "entryTile": { + "$type": "gradient", + "$value": "linear-gradient(150deg,hsl(var(--h) 30% 26%),hsl(var(--h) 30% 12%))", + "source": "index.html:149", + "usedBy": "service entry tiles: 150deg gradient, hue per service (SERVICE_HUE, index.html:663)" + }, + "initialsCircle": { + "$type": "gradient", + "$value": "linear-gradient(160deg,hsl(var(--h) 24% 30%),hsl(var(--h) 26% 14%))", + "source": "index.html:288", + "usedBy": "cast circle / person portrait without a photo: initials on a 160deg tinted gradient, hue = hash(name)" + }, + "heroAmbientFilter": { + "$type": "filter", + "$value": "blur(60px) saturate(1.2) brightness(.55)", + "inset": "-80px", + "scale": 1.1, + "source": "index.html:96", + "usedBy": "poster-only hero/title art: blurred wash of the poster behind the one-sheet (Compose: RenderEffect blur 30 dp, saturation 1.2, brightness .55) [INFERENCE: Compose mapping]" + }, + "cardAmbientFilter": { + "$type": "filter", + "$value": "blur(26px) brightness(.5)", + "inset": "-30px", + "source": "index.html:129", + "usedBy": "poster-only art in a landscape card: blurred wash behind the one-sheet" + } + }, + "font": { + "family": { + "$type": "fontFamily", + "$value": "system-ui,-apple-system,\"Segoe UI\",Roboto,\"Noto Sans\",Ubuntu,Cantarell,sans-serif", + "source": "index.html:14", + "usedBy": "all stage text", + "note": "On the box this resolves to the platform sans (Roboto) [INFERENCE]; Compose uses the default FontFamily." + }, + "tabularNumbers": { + "$value": "font-variant-numeric: tabular-nums", + "source": "index.html:156", + "usedBy": "every ratings row" + } + }, + "type": { + "displayDetail": { + "$type": "typography", + "px": 88.0, + "sp": 44.0, + "source": "index.html:213", + "usedBy": "title page title (film, series, episode = series name); clamp 2 lines", + "weight": 800, + "weightSource": "index.html:103", + "lineHeight": 1.02, + "lineHeightSource": "index.html:103", + "letterSpacingEm": -0.02, + "$value": { + "fontSize": "44sp", + "fontWeight": 800 + } + }, + "displayHero": { + "$type": "typography", + "px": 84.0, + "sp": 42.0, + "source": "index.html:103", + "usedBy": "Home hero and Discover picks hero title; clamp 2 lines", + "weight": 800, + "weightSource": "index.html:103", + "lineHeight": 1.02, + "lineHeightSource": "index.html:103", + "letterSpacingEm": -0.02, + "$value": { + "fontSize": "42sp", + "fontWeight": 800 + } + }, + "screenTitle": { + "$type": "typography", + "px": 64.0, + "sp": 32.0, + "source": "index.html:200", + "usedBy": "screen headers: library (Movies/Shows/Anime), See all, service page, Settings, Discover-without-hero; also \"Who's watching?\" (.picker h1) and person name (.p-head h1)", + "weight": 800, + "weightSource": "index.html:200", + "letterSpacingEm": -0.02, + "$value": { + "fontSize": "32sp", + "fontWeight": 800 + } + }, + "sectionTitle": { + "$type": "typography", + "px": 56.0, + "sp": 28.0, + "source": "index.html:181", + "usedBy": "the \"Discover\" section header inside Home; player hand-off title (.player h2)", + "weight": 800, + "weightSource": "index.html:181", + "letterSpacingEm": -0.02, + "$value": { + "fontSize": "28sp", + "fontWeight": 800 + } + }, + "sheetTitle": { + "$type": "typography", + "px": 44.0, + "sp": 22.0, + "source": "index.html:228", + "usedBy": "side-sheet titles (Request, Version, Coming in, ...)", + "weight": 800, + "weightSource": "index.html:228", + "letterSpacingEm": -0.01, + "$value": { + "fontSize": "22sp", + "fontWeight": 800 + } + }, + "wordmark": { + "$type": "typography", + "px": 36.0, + "sp": 18.0, + "source": "index.html:79", + "usedBy": "the \"Wolfskin\" wordmark at the left of the nav and in the picker", + "weight": 800, + "weightSource": "index.html:79", + "letterSpacingEm": -0.02, + "$value": { + "fontSize": "18sp", + "fontWeight": 800 + } + }, + "stateTitle": { + "$type": "typography", + "px": 36.0, + "sp": 18.0, + "source": "index.html:195", + "usedBy": "state panel titles and receipt titles (.receipt h3)", + "$value": { + "fontSize": "18sp", + "fontWeight": 400 + } + }, + "rowHeading": { + "$type": "typography", + "px": 34.0, + "sp": 17.0, + "source": "index.html:119", + "usedBy": "row headings above every shelf and grid section", + "weight": 700, + "weightSource": "index.html:119", + "letterSpacingEm": -0.01, + "$value": { + "fontSize": "17sp", + "fontWeight": 700 + } + }, + "pickerName": { + "$type": "typography", + "px": 34.0, + "sp": 17.0, + "source": "index.html:260", + "usedBy": "names under avatars in Who's watching", + "weight": 650, + "weightSource": "index.html:260", + "$value": { + "fontSize": "17sp", + "fontWeight": 650 + } + }, + "nav": { + "$type": "typography", + "px": 30.0, + "sp": 15.0, + "source": "index.html:81", + "usedBy": "nav destination labels", + "weight": 600, + "weightSource": "index.html:81", + "$value": { + "fontSize": "15sp", + "fontWeight": 600 + } + }, + "listTitle": { + "$type": "typography", + "px": 30.0, + "sp": 15.0, + "source": "index.html:231", + "usedBy": "sheet row names; Settings row titles (.srow .tx b); Coming-in row titles (.crow .tx b); See all label; service entry wordmark", + "weight": 650, + "weightSource": "index.html:231", + "$value": { + "fontSize": "15sp", + "fontWeight": 650 + } + }, + "body": { + "$type": "typography", + "px": 28.0, + "sp": 14.0, + "source": "index.html:104", + "usedBy": "facts lines (h-meta), overviews (h-ov, d-ov), card caption title (.cap b), tile titles (.card .ov b), buttons (.btn), state text, receipts, toast, rating numbers and marks", + "$value": { + "fontSize": "14sp", + "fontWeight": 400 + } + }, + "button": { + "$type": "typography", + "px": 28.0, + "sp": 14.0, + "source": "index.html:107", + "usedBy": "pill buttons (primary and secondary)", + "weight": 700, + "weightSource": "index.html:107", + "$value": { + "fontSize": "14sp", + "fontWeight": 700 + } + }, + "label": { + "$type": "typography", + "px": 26.0, + "sp": 13.0, + "source": "index.html:185", + "usedBy": "chips; kicker (26/650); d-line; d-prog; icon-button caption (.bcap); cast name (.pnm b, 26/700); sheet section labels (.sheet .lab)", + "weight": 650, + "weightSource": "index.html:185", + "$value": { + "fontSize": "13sp", + "fontWeight": 650 + } + }, + "caption": { + "$type": "typography", + "px": 24.0, + "sp": 12.0, + "source": "index.html:154", + "usedBy": "THE FLOOR. Card facts under a focused poster; tile second lines; pills; small print; character names; readiness stages; letter rail; rating-plate floor. Nothing on the stage is smaller.", + "$value": { + "fontSize": "12sp", + "fontWeight": 400 + } + }, + "ratingPlate": { + "$type": "typography", + "px": 28.0, + "sp": 14.0, + "floorPx": 24, + "floorSp": 12.0, + "stepPx": 0.5, + "weight": 700, + "lineHeight": 1.2, + "source": "index.html:164", + "floorSource": "index.html:802", + "$value": { + "fontSize": "14sp", + "min": "12sp", + "fontWeight": 700 + }, + "usedBy": "rating plate on the focused card: starts at 28 px (14 sp, the fork titleSmall), shrinks in 0.5 px steps to the 24 px floor, then drops trailing entries (fitRow, D9)" + }, + "avatarLetter": { + "$type": "typography", + "weight": 800, + "source": "index.html:89", + "sizes": { + "picker": 100, + "nav": 30, + "sheetRow": 28, + "shelfHead": 24, + "chip": 24, + "libHeader": 26, + "sectionHeader": 28 + }, + "usedBy": "avatar letters (px per context)" + }, + "stageLineHeight": { + "$type": "number", + "$value": 1.3, + "source": "index.html:61", + "usedBy": "default line height for all stage text (1.3)" + } + }, + "radius": { + "card": { + "$type": "dimension", + "$value": "8dp", + "px": 16.0, + "dp": 8.0, + "source": "index.html:125", + "usedBy": "every card (poster, tile, wide, entry, See all, tail, skeleton)" + }, + "button": { + "$type": "dimension", + "$value": "19dp", + "px": 38.0, + "dp": 19.0, + "source": "index.html:107", + "usedBy": "pill buttons = height / 2" + }, + "chip": { + "$type": "dimension", + "$value": "17dp", + "px": 34.0, + "dp": 17.0, + "source": "index.html:185", + "usedBy": "chips = height / 2" + }, + "navItem": { + "$type": "dimension", + "$value": "16dp", + "px": 32.0, + "dp": 16.0, + "source": "index.html:81", + "usedBy": "nav item and blob = height / 2" + }, + "listRow": { + "$type": "dimension", + "$value": "12dp", + "px": 24.0, + "dp": 12.0, + "source": "index.html:231", + "usedBy": "sheet rows and Settings rows" + }, + "panel": { + "$type": "dimension", + "$value": "11dp", + "px": 22.0, + "dp": 11.0, + "source": "index.html:194", + "usedBy": "state panels, receipts, Coming-in rows, toast" + }, + "menu": { + "$type": "dimension", + "$value": "13dp", + "px": 26.0, + "dp": 13.0, + "source": "index.html:264", + "usedBy": "menu panel" + }, + "heroSheet": { + "$type": "dimension", + "$value": "9dp", + "px": 18.0, + "dp": 9.0, + "source": "index.html:97", + "usedBy": "upright poster (\"one-sheet\") on poster-only hero/title art" + }, + "cardSheet": { + "$type": "dimension", + "$value": "5dp", + "px": 10.0, + "dp": 5.0, + "source": "index.html:128", + "usedBy": "one-sheet inside a landscape card" + }, + "thumb": { + "$type": "dimension", + "$value": "6dp", + "px": 12.0, + "dp": 6.0, + "source": "index.html:248", + "usedBy": "Coming-in poster thumbnail 96x144" + }, + "pill": { + "$type": "dimension", + "$value": "11dp", + "px": 22.0, + "dp": 11.0, + "source": "index.html:122", + "usedBy": "sample/Saved/Wolfskin/upstream pills" + }, + "progress": { + "$type": "dimension", + "$value": "2dp", + "px": 4.0, + "dp": 2.0, + "source": "index.html:138", + "usedBy": "progress bars" + }, + "circle": { + "$type": "dimension", + "$value": "50%", + "source": "index.html:89", + "usedBy": "avatars, badges, person circles, gear" + } + }, + "layout": { + "safeSide": { + "$type": "dimension", + "$value": "48dp", + "px": 96, + "dp": 48.0, + "source": "index.html:654", + "usedBy": "left/right safe inset on every screen (5% of 1920); first card x, all copy blocks" + }, + "contentWidth": { + "$type": "dimension", + "$value": "864dp", + "px": 1728, + "dp": 864.0, + "source": "index.html:1035", + "usedBy": "content measure 1920 - 2 x 96; slotsOf() = floor((1728 + gap + 8) / (w + gap))" + }, + "safeTopPicker": { + "$type": "dimension", + "$value": "27dp", + "px": 54.0, + "dp": 27.0, + "source": "index.html:258", + "usedBy": "top inset of the wordmark in Who's watching (5% of 1080)" + }, + "navBand": { + "$type": "dimension", + "$value": "75dp", + "px": 150.0, + "dp": 75.0, + "source": "index.html:71", + "usedBy": "nav band height on every non-full-screen screen" + }, + "navPaddingTop": { + "$type": "dimension", + "$value": "22dp", + "px": 44.0, + "dp": 22.0, + "source": "index.html:74", + "usedBy": "nav row top padding; items are vertically centred in 44..150, so a 64 px item spans y 65..129 (measured)" + }, + "navItemHeight": { + "$type": "dimension", + "$value": "32dp", + "px": 64.0, + "dp": 32.0, + "source": "index.html:81", + "usedBy": "nav item / blob height; nav avatar is 64x64" + }, + "navItemPaddingX": { + "$type": "dimension", + "$value": "13dp", + "px": 26.0, + "dp": 13.0, + "source": "index.html:81", + "usedBy": "nav item horizontal padding" + }, + "navItemGap": { + "$type": "dimension", + "$value": "6dp", + "px": 12.0, + "dp": 6.0, + "source": "index.html:74", + "usedBy": "gap between nav items" + }, + "wordmarkGap": { + "$type": "dimension", + "$value": "20dp", + "px": 40.0, + "dp": 20.0, + "source": "index.html:79", + "usedBy": "space after the wordmark before Home" + }, + "navUnderline": { + "$type": "dimension", + "$value": "2dp", + "px": 4.0, + "dp": 2.0, + "source": "index.html:83", + "usedBy": "accent underline under the current destination, inset 26 px each side, 4 px above the item bottom; hidden while that item is focused" + }, + "navBlobAvatarPad": { + "$type": "dimension", + "$value": "4dp", + "px": 8, + "dp": 4.0, + "source": "index.html:1681", + "usedBy": "the blob grows 8 px each side around the avatar (80x80 circle)" + }, + "navSolidAfter": { + "$type": "dimension", + "$value": "20dp", + "px": 40, + "dp": 20.0, + "source": "index.html:1668", + "usedBy": "the nav band switches to the solid gradient once the frame scrollTop > 40" + }, + "pinnedLine": { + "$type": "dimension", + "$value": "84dp", + "px": 168, + "dp": 84.0, + "source": "index.html:654", + "usedBy": "focus-follow: a focused row (not hero) scrolls so its heading top sits 168 px from the top; rows whose bottom fits the first screen (y < 700 and y + h <= 1040) do not scroll" + }, + "windowAhead": { + "$type": "dimension", + "$value": "350dp", + "px": 700, + "dp": 350.0, + "source": "index.html:654", + "usedBy": "prototype windowing distance (rows within 700 px of the viewport exist); in Compose lazy layouts do this" + }, + "rowHeadingBand": { + "$type": "dimension", + "$value": "30dp", + "px": 60, + "dp": 30.0, + "source": "index.html:1018", + "usedBy": "shelf row: heading band (44 px heading at top 0) before the cards start at y + 60" + }, + "rowGapAfter": { + "$type": "dimension", + "$value": "22dp", + "px": 44, + "dp": 22.0, + "source": "index.html:1018", + "usedBy": "shelf row: space after cards (+ caption band) before the next row; shelf row height = 60 + card h + caption + 44" + }, + "gridRowGap": { + "$type": "dimension", + "$value": "14dp", + "px": 28, + "dp": 14.0, + "source": "index.html:1019", + "usedBy": "grid row height = 384 + 76 + 28 = 488 (library, See all, person)" + }, + "row_hero": { + "$type": "dimension", + "$value": "410dp", + "px": 820, + "dp": 410.0, + "source": "index.html:1016", + "usedBy": "Home hero row height (the hero art itself is 1920x1080 behind it)" + }, + "row_phero": { + "$type": "dimension", + "$value": "370dp", + "px": 740, + "dp": 370.0, + "source": "index.html:1017", + "usedBy": "Discover picks-hero row height" + }, + "row_section": { + "$type": "dimension", + "$value": "75dp", + "px": 150, + "dp": 75.0, + "source": "index.html:1020", + "usedBy": "Home \"Discover\" section header row" + }, + "row_chips": { + "$type": "dimension", + "$value": "52dp", + "px": 104, + "dp": 52.0, + "source": "index.html:1021", + "usedBy": "chip row (Discover filters, library toolbar, See all/service type chips, seasons)" + }, + "row_note": { + "$type": "dimension", + "$value": "42dp", + "px": 84, + "dp": 42.0, + "source": "index.html:1022", + "usedBy": "one-line note row (picks unavailable, no seeds, episode note)" + }, + "row_state": { + "$type": "dimension", + "$value": "150dp", + "px": 300, + "dp": 150.0, + "source": "index.html:1023", + "usedBy": "state panel row (calm or warning, with recovery buttons)" + }, + "row_lhead": { + "$type": "dimension", + "$value": "118dp", + "px": 236, + "dp": 118.0, + "source": "index.html:1024", + "usedBy": "screen header row (library, See all, service, Settings, Discover without hero)" + }, + "row_dhead": { + "$type": "dimension", + "$value": "450dp", + "px": 900, + "dp": 450.0, + "source": "index.html:1025", + "usedBy": "title page header row (copy + buttons over the backdrop)" + }, + "row_phead": { + "$type": "dimension", + "$value": "235dp", + "px": 470, + "dp": 235.0, + "source": "index.html:1026", + "usedBy": "person page header row" + }, + "row_gh": { + "$type": "dimension", + "$value": "42dp", + "px": 84, + "dp": 42.0, + "source": "index.html:1027", + "usedBy": "grid section heading row (person page)" + }, + "row_endcta": { + "$type": "dimension", + "$value": "100dp", + "px": 200, + "dp": 100.0, + "source": "index.html:1028", + "usedBy": "Home end action row (\"Explore more in Discover\")" + }, + "row_srow": { + "$type": "dimension", + "$value": "62dp", + "px": 124, + "dp": 62.0, + "source": "index.html:1029", + "usedBy": "Settings list row pitch (row 104 + 20)" + }, + "heroCopyLeft": { + "$type": "dimension", + "$value": "48dp", + "px": 96.0, + "dp": 48.0, + "source": "index.html:100", + "usedBy": "hero copy block x" + }, + "heroCopyBottom": { + "$type": "dimension", + "$value": "55dp", + "px": 110.0, + "dp": 55.0, + "source": "index.html:100", + "usedBy": "hero copy block anchored 110 px above the 1080 art bottom (bottom edge of buttons at y 710 on Home)" + }, + "heroCopyWidth": { + "$type": "dimension", + "$value": "500dp", + "px": 1000.0, + "dp": 500.0, + "source": "index.html:100", + "usedBy": "hero copy block width" + }, + "heroOverviewMax": { + "$type": "dimension", + "$value": "480dp", + "px": 960.0, + "dp": 480.0, + "source": "index.html:105", + "usedBy": "hero overview max width; 2-line clamp" + }, + "detailCopyTop": { + "$type": "dimension", + "$value": "100dp", + "px": 200.0, + "dp": 100.0, + "source": "index.html:212", + "usedBy": "title page copy block top" + }, + "detailCopyWidth": { + "$type": "dimension", + "$value": "530dp", + "px": 1060.0, + "dp": 530.0, + "source": "index.html:212", + "usedBy": "title page copy block width; overview 3-line clamp" + }, + "heroSheet": { + "$type": "dimension", + "px": [ + 420, + 630 + ], + "dp": [ + 210, + 315 + ], + "right": 180, + "top": 150, + "source": "index.html:97", + "usedBy": "one-sheet poster on a poster-only Home hero/title page; Discover picks hero uses 360x540 at top 140 (.row-phero .art-sheet)" + }, + "buttonHeight": { + "$type": "dimension", + "$value": "38dp", + "px": 76.0, + "dp": 38.0, + "source": "index.html:107", + "usedBy": "pill button height (primary, secondary, sheet buttons)" + }, + "buttonPaddingX": { + "$type": "dimension", + "$value": "19dp", + "px": 38.0, + "dp": 19.0, + "source": "index.html:107", + "usedBy": "pill button horizontal padding" + }, + "buttonGap": { + "$type": "dimension", + "$value": "10dp", + "px": 20.0, + "dp": 10.0, + "source": "index.html:106", + "usedBy": "gap between buttons in a row" + }, + "buttonIcon": { + "$type": "dimension", + "$value": "15dp", + "px": 30.0, + "dp": 15.0, + "source": "index.html:108", + "usedBy": "glyph inside a pill button; icon gap 14" + }, + "iconButton": { + "$type": "dimension", + "$value": "38dp", + "px": 76.0, + "dp": 38.0, + "source": "index.html:274", + "usedBy": "round icon button (Restart, Version, Audio and subtitles, Mark watched, Trailer, More); glyph 32" + }, + "iconCaptionLine": { + "$type": "dimension", + "$value": "19dp", + "px": 38.0, + "dp": 19.0, + "source": "index.html:281", + "usedBy": "reserved caption line under a button row that has icon buttons (margin-top 16); shows \"label ยท note\" of the focused icon button" + }, + "sheetWidth": { + "$type": "dimension", + "$value": "400dp", + "px": 800.0, + "dp": 400.0, + "source": "index.html:227", + "usedBy": "right-side sheet width; padding 80 top/bottom, 64 sides; vertical gap 18" + }, + "sheetRow": { + "$type": "dimension", + "$value": "50dp", + "px": 100.0, + "dp": 50.0, + "source": "index.html:231", + "usedBy": "person row in request sheets (version rows auto height, padding 20/26; track rows 84)" + }, + "settingsRow": { + "$type": "dimension", + "px": [ + 1300, + 104 + ], + "dp": [ + 650, + 52 + ], + "source": "index.html:321", + "usedBy": "Settings list row (icon 36, title 30/700, one-line description 24, pills, chevron)" + }, + "stateWidth": { + "$type": "dimension", + "$value": "550dp", + "px": 1100.0, + "dp": 550.0, + "source": "index.html:194", + "usedBy": "state panel width; padding 34/40; title 36; text 28" + }, + "captionOffset": { + "$type": "dimension", + "px": 18, + "dp": 9, + "source": "index.html:1242", + "usedBy": "caption under a focused poster starts 18 px below the card bottom (capHtml top = headH + h + 18); width 640" + }, + "plateInset": { + "$type": "dimension", + "px": { + "top": 14, + "side": 16, + "bottomFade": 46 + }, + "available": "card width - 32", + "source": "index.html:162, index.html:1234", + "usedBy": "rating plate padding; the plate row must fit width - 32 px" + }, + "badge": { + "$type": "dimension", + "$value": "24dp", + "px": 48.0, + "dp": 24.0, + "source": "index.html:141", + "usedBy": "state badge circle, 14 px from right and bottom; glyph 28" + }, + "badgeInset": { + "$type": "dimension", + "$value": "7dp", + "px": 14.0, + "dp": 7.0, + "source": "index.html:141", + "usedBy": "badge inset from the card corner" + }, + "progressBar": { + "$type": "dimension", + "$value": "4dp", + "px": 8.0, + "dp": 4.0, + "source": "index.html:138", + "usedBy": "progress bar on wide cards (inset 18 left/right, 12 from bottom); title page bar is 320x8" + }, + "pickerAvatar": { + "$type": "dimension", + "$value": "110dp", + "px": 220.0, + "dp": 110.0, + "source": "index.html:261", + "usedBy": "Who's watching avatar; letter 100 px; avatars 90 px apart; name 26 px below" + }, + "pickerGap": { + "$type": "dimension", + "$value": "45dp", + "px": 90.0, + "dp": 45.0, + "source": "index.html:259", + "usedBy": "gap between people in the picker (also between gear slots)" + }, + "pickerStackGap": { + "$type": "dimension", + "$value": "35dp", + "px": 70.0, + "dp": 35.0, + "source": "index.html:256", + "usedBy": "vertical gap between \"Who's watching?\", the people and the gear row (gear row margin-top -34)" + }, + "gear": { + "$type": "dimension", + "$value": "28dp", + "px": 56.0, + "dp": 28.0, + "source": "index.html:306", + "usedBy": "Settings gear under the last person; glyph 30; caption 24 px, 72 px below the gear top, visible only on focus" + }, + "navAvatar": { + "$type": "dimension", + "$value": "32dp", + "px": 64.0, + "dp": 32.0, + "source": "index.html:90", + "usedBy": "avatar at the right end of the nav" + }, + "castCircle": { + "$type": "dimension", + "$value": "100dp", + "px": 200, + "dp": 100.0, + "source": "index.html:285", + "usedBy": "cast circle; name 26/700 at 216 px; character 24 muted; card 290 tall" + }, + "personPortrait": { + "$type": "dimension", + "$value": "120dp", + "px": 240.0, + "dp": 120.0, + "source": "index.html:294", + "usedBy": "person page portrait circle; header at x 96, y 170, gap 48" + }, + "thumb": { + "$type": "dimension", + "px": [ + 96, + 144 + ], + "dp": [ + 48, + 72 + ], + "source": "index.html:248", + "usedBy": "Coming-in poster thumbnail" + }, + "toast": { + "$type": "dimension", + "px": { + "right": 96, + "top": 150, + "maxWidth": 760 + }, + "source": "index.html:270", + "usedBy": "toast position (top right under the nav)" + }, + "letterRail": { + "$type": "dimension", + "px": { + "width": 52, + "letterHeight": 30, + "focusedLetterHeight": 44, + "right": 96, + "top": 150 + }, + "source": "index.html:204", + "usedBy": "letter rail (only for destinations with >= 200 titles)" + } + }, + "card": { + "poster": { + "$type": "card", + "px": { + "w": 256, + "h": 384, + "gap": 24, + "pitch": 280, + "captionBand": 76 + }, + "dp": { + "w": 128.0, + "h": 192.0, + "gap": 12.0, + "pitch": 140.0, + "captionBand": 38.0 + }, + "ratio": "2:3", + "fullSlotsPerRow": 6, + "source": "index.html:656", + "usedBy": "every title shelf, library grid, See all grid, More like this, person filmography; art only at rest" + }, + "tile": { + "$type": "card", + "px": { + "w": 416, + "h": 234, + "gap": 24, + "pitch": 440, + "captionBand": 0 + }, + "dp": { + "w": 208.0, + "h": 117.0, + "gap": 12.0, + "pitch": 220.0, + "captionBand": 0.0 + }, + "ratio": "16:9", + "fullSlotsPerRow": 4, + "source": "index.html:657", + "usedBy": "Next up, New in your library, season episodes; title + second line on a bottom gradient" + }, + "wide": { + "$type": "card", + "px": { + "w": 560, + "h": 315, + "gap": 24, + "pitch": 584, + "captionBand": 0 + }, + "dp": { + "w": 280.0, + "h": 157.5, + "gap": 12.0, + "pitch": 292.0, + "captionBand": 0.0 + }, + "ratio": "16:9", + "fullSlotsPerRow": 3, + "source": "index.html:658", + "usedBy": "Continue watching (only when a person has more than one resume item; the first resume is the hero)" + }, + "entry": { + "$type": "card", + "px": { + "w": 256, + "h": 144, + "gap": 24, + "pitch": 280, + "captionBand": 0 + }, + "dp": { + "w": 128.0, + "h": 72.0, + "gap": 12.0, + "pitch": 140.0, + "captionBand": 0.0 + }, + "ratio": "16:9", + "fullSlotsPerRow": 6, + "source": "index.html:659", + "usedBy": "Discover Services row (text wordmark on a tinted gradient; no third-party logos)" + }, + "person": { + "$type": "card", + "px": { + "w": 200, + "h": 290, + "gap": 28, + "pitch": 228, + "captionBand": 0 + }, + "dp": { + "w": 100.0, + "h": 145.0, + "gap": 14.0, + "pitch": 114.0, + "captionBand": 0.0 + }, + "ratio": "1:1 circle", + "fullSlotsPerRow": 7, + "source": "index.html:660", + "usedBy": "Cast row: 200 px circle + name + character, 290 px tall" + } + }, + "focus": { + "scaleCard": { + "$type": "number", + "$value": 1.08, + "source": "index.html:134", + "page": { + ".card.f": 1.08, + ".pp.f (picker person)": 1.08, + ".pgear.f": 1.08, + "person circle": 1.08 + }, + "usedBy": "cards of every kind, cast circles, picker people, the gear" + }, + "scaleControl": { + "$type": "number", + "$value": 1.05, + "source": "index.html:189", + "page": { + ".btn.f": 1.06, + ".chip.f": 1.05 + }, + "usedBy": "pill and icon buttons, chips", + "note": "q1 = 3 scales, settled by Justin 2026-11-05 (corr=c248698d8546e1ab): buttons 1.05. The page button scale 1.06 folds into 1.05 (delta 0.01 = 2 px on a 200 px button). Spec 4.5, 12.4 #1." + }, + "scaleRow": { + "$type": "number", + "$value": 1.02, + "source": "index.html:327", + "page": { + ".prow.f": 1.03, + ".crow.f": 1.02, + ".srow.f": 1.02 + }, + "usedBy": "full-width list rows: sheet rows, Coming-in rows, Settings rows", + "note": "q1, settled by Justin 2026-11-05 (corr=c248698d8546e1ab): sheet rows 1.02. The page sheet-row scale 1.03 folds into 1.02. Spec 4.5, 12.4 #1." + }, + "ringCard": { + "$type": "shadow", + "$value": "0 0 0 4px var(--bg),0 0 0 8px var(--accent),0 18px 50px rgb(0 0 0 / .65)", + "gapPx": 4, + "ringPx": 4, + "gapDp": 2, + "ringDp": 2, + "gapColor": "color.bg", + "ringColor": "color.accent", + "liftShadow": "0 18px 50px rgb(0 0 0 / .65)", + "source": "index.html:134", + "usedBy": "focused card: a 4 px bg-coloured gap then a 4 px lilac ring OUTSIDE the art (never covers it), plus a lift shadow; drawn on the circle for cast cards" + }, + "ringButton": { + "$type": "shadow", + "$value": "0 0 0 4px var(--bg),0 0 0 8px var(--accent),0 12px 40px rgb(0 0 0 / .5)", + "gapPx": 4, + "ringPx": 4, + "ringColor": "color.accent", + "liftShadow": "0 12px 40px rgb(0 0 0 / .5)", + "source": "index.html:110", + "usedBy": "focused pill and icon buttons (primary stays white, secondary lightens to buttonSecondaryFocused)" + }, + "ringAvatar": { + "$type": "shadow", + "$value": "0 0 0 4px var(--bg),0 0 0 8px var(--fg)", + "gapPx": 4, + "ringPx": 4, + "ringColor": "color.fg", + "source": "index.html:92", + "usedBy": "focused nav avatar and focused gear (white ring, not lilac)" + }, + "ringPicker": { + "$type": "shadow", + "$value": "0 0 0 6px var(--bg),0 0 0 12px var(--fg)", + "gapPx": 6, + "ringPx": 6, + "ringColor": "color.fg", + "source": "index.html:263", + "usedBy": "focused person in Who's watching (white 6 + 6 ring; name turns fg)" + }, + "fillInverse": { + "$type": "rule", + "$value": "background color.fg, text color.onFocus", + "source": "index.html:189, index.html:237, index.html:327, index.html:253", + "usedBy": "focused chip, sheet row, Settings row, Coming-in row and nav blob: white fill with dark text (no ring)" + } + }, + "motion": { + "fast": { + "$type": "duration", + "$value": "140ms", + "easing": "ease = cubic-bezier(.25,.1,.25,1)", + "source": "index.html:125", + "page": { + ".card/.btn/.chip/.pp/.prow/.crow/.srow/.pgear transform": "140ms", + ".cap opacity (caption fade-in)": "120ms", + ".dots svg opacity": "140ms" + }, + "usedBy": "focus scale + ring in and out on every focusable; caption fade under a focused poster (page 120 ms folds in)", + "note": "q1, settled by Justin 2026-11-05 (corr=c248698d8546e1ab): the caption fade is 140 ms. Three durations in total (140, 160, 180) plus the blob spring." + }, + "base": { + "$type": "duration", + "$value": "160ms", + "easing": "ease", + "source": "index.html:162", + "page": { + ".rplate opacity": "160ms", + "#nav background": "160ms", + ".track transform (row slide)": "160ms", + ".chips transform": "160ms", + ".dbg .dim opacity": "160ms", + ".toast opacity": "160ms" + }, + "usedBy": "rating plate fade, nav band solid/transparent, row track slide by one card, chip strip shift, title-page dim as it scrolls" + }, + "scroll": { + "$type": "duration", + "$value": "180ms", + "easing": "ease-out cubic: 1 - (1 - t)^3 = cubic-bezier(.33,1,.68,1)", + "source": "index.html:1076", + "usedBy": "vertical frame scroll to the pinned line (Compose BringIntoViewSpec animation spec)" + }, + "navBlob": { + "$type": "transition", + "$value": { + "type": "spring", + "dampingRatio": 1.0, + "stiffness": 650 + }, + "page": { + "transition": "transform .2s ease-out,width .2s ease-out,height .2s ease-out,background-color .2s ease-out", + "measured": "x 478 -> 688 px: 557.4 at 50 ms, 621.8 at 99 ms (68.5% of travel), 668.4 at 150 ms, at rest by 200 ms; width 198 -> 171 animates with it" + }, + "source": "index.html:76", + "usedBy": "nav indicator: x, width, height and colour (white when the nav has focus, rest colour behind the current destination when not); label colour follows (page .ni color .2s ease-out)", + "verified": { + "script": "data/tv-spec/spring_check.py", + "method": "mass 1, x'' = -k(x-1) - 2*zeta*sqrt(k)*x', integrated at 0.01 ms steps; k searched 400-1000 step 10 for least error against the page measurements", + "pxAt50_99_150_200ms": [ + 554.5, + 628.7, + 665.9, + 680.2 + ], + "pageMeasuredPx": [ + 557.4, + 621.8, + 668.4, + 688.0 + ], + "reaches95pctMs": 186, + "reaches99pctMs": 260, + "within1pxMs": 294, + "maxOvershoot": 0, + "previousStiffness": "530 (revision 1, reached 66.4% at 99 ms against the page 68.5%)" + }, + "note": "q1 = spring, settled by Justin 2026-11-05 (corr=c248698d8546e1ab): a no-bounce spring matched to the measured 200 ms ease-out. Damping ratio 1.0 is critically damped, so it cannot overshoot. Stiffness 650 is the best fit to the measured curve (revision 1 had 530, an untested derivation). Visually settled (95%) by 186 ms; the last pixel arrives at about 300 ms. Snap with no animation when the system animator scale is 0." + }, + "ratingDwell": { + "$type": "duration", + "$value": "350ms", + "source": "index.html:860", + "usedBy": "a focused card requests ratings only after 350 ms of dwell; moving on cancels; cached ratings show at once (fork DEBOUNCE_MILLIS 350)" + }, + "toast": { + "$type": "duration", + "$value": "3200ms", + "source": "index.html:1733", + "usedBy": "toast visible time" + }, + "reducedMotion": { + "$type": "rule", + "$value": "all transitions instant", + "source": "index.html:330", + "usedBy": "when Settings.Global ANIMATOR_DURATION_SCALE == 0: no scale animation, no scroll animation, blob snaps" + } + }, + "image": { + "posterRequest": { + "px": [ + 256, + 384 + ], + "decode": "RGB565", + "source": "index.html:548 (memory table), answers p3", + "usedBy": "poster cards; decode at min(source, slot); fixture sources are 300x450" + }, + "tileRequest": { + "px": [ + 416, + 234 + ], + "decode": "ARGB_8888", + "source": "index.html:549", + "usedBy": "tile cards" + }, + "wideRequest": { + "px": [ + 560, + 315 + ], + "decode": "ARGB_8888", + "source": "index.html:401", + "usedBy": "Continue watching cards" + }, + "heroRequest": { + "px": [ + 1280, + 720 + ], + "decode": "ARGB_8888", + "bytes": 3686400, + "source": "index.html:549", + "usedBy": "Home hero, Discover hero, title backdrop: the 1280x720 source, never upscaled; released when scrolled past" + }, + "castRequest": { + "px": [ + 200, + 200 + ], + "source": "index.html:550", + "usedBy": "cast portraits: decode min(source 185x278, slot)" + }, + "crossfade": { + "$value": false, + "source": "index.html:536; answers p3", + "usedBy": "no crossfade on cards (Coil crossfade off)" + }, + "memoryCacheMB": { + "$value": 64, + "source": "index.html:552; answers p3", + "usedBy": "Coil memory cache cap (not a heap percentage)" + }, + "diskCacheMB": { + "$value": 128, + "source": "index.html:553", + "usedBy": "Coil disk cache" + }, + "concurrentReads": { + "$value": { + "catalogue": 2, + "image": 4 + }, + "source": "index.html:489 (Rules row)", + "usedBy": "at most 2 catalogue reads and 4 image reads at once" + } + }, + "behaviour": { + "rowLimit": { + "$value": 20, + "source": "index.html:666", + "usedBy": "cards per shelf before See all (D3)" + }, + "letterRailMin": { + "$value": 200, + "source": "index.html:667", + "usedBy": "the letter rail exists only for a destination of >= 200 titles, sort A-Z (n4)" + }, + "gridColumns": { + "$value": 6, + "source": "index.html:1425", + "usedBy": "library, See all and person grids" + }, + "libraryChunk": { + "$value": 200, + "source": "index.html:469", + "usedBy": "library read in 200-item chunks ahead of focus" + }, + "laneLoadRows": { + "$value": 2, + "source": "index.html:472", + "usedBy": "catalogue lane is read when within 2 rows of focus" + }, + "nextPageCards": { + "$value": 10, + "source": "index.html:472", + "usedBy": "catalogue page 2+ is read when focus is 10 cards from the row end" + }, + "heroSlides": { + "$value": 5, + "source": "index.html:883", + "usedBy": "Discover picks hero slides" + }, + "cacheRatingsHours": { + "$value": 6, + "entries": 300, + "source": "index.html:473", + "usedBy": "ratings cache per (type, tmdb) and per (series, season)" + }, + "laneCacheMinutes": { + "$value": 30, + "source": "index.html:472", + "usedBy": "last-known-good per catalogue lane" + }, + "libraryRefreshMinutes": { + "$value": 10, + "source": "index.html:469", + "usedBy": "library snapshot refreshed on open if older than 10 min" + }, + "requestsPollSeconds": { + "$value": 30, + "source": "index.html:479", + "usedBy": "Requests (Coming in) poll while a request is unsettled or the sheet is open" + }, + "comingInVisibleRows": { + "$value": 5, + "expanded": 4, + "source": "index.html:1907", + "usedBy": "Coming-in sheet shows 5 rows (4 while one is expanded), window follows focus" + } + } +} \ No newline at end of file diff --git a/wolfskin-design/tokens.sha256 b/wolfskin-design/tokens.sha256 new file mode 100644 index 00000000..ba5f6201 --- /dev/null +++ b/wolfskin-design/tokens.sha256 @@ -0,0 +1,8 @@ +1f22175c1ce3987c4efa14d573601641a61e1a915e2c464c943b6c400356adb4 discover-tokens.json +85109c394255f6120a621fbefe8e58df82832974ccd6a6a975a61567f641ea2a generate_tokens.py +25985087986a46f00e2819917d0421ff2b437ec21c54f6ce6412b84c0eb05302 home-tokens.json +be3af0ddcb0d67abef0805d19d7a33cdb55428bcace656b50f0a38935f212028 shell-tokens.json +1c805ae8eacbca1c63fbf91e19d7f9fea6c27b54e709e91f6bd46720d5048a41 src/main/java/org/justinvisser/wolfskin/design/WolfskinTokens.kt +7ed093cc63b0fd6f47fe951da5df26ee7258865b8d0a51345a408ab64f037de0 title-tokens.json +3b14b60264e1f97c02be3e57d0c0bd9477e982044ee944c8c8a5b71e939fa8fb tokens.css +5b939f1f3eb90b428008fda75720f6e3a4e844c486668931db3d52bffb987b53 tokens.json