diff --git a/VERIFICATION-0.47.0.md b/VERIFICATION-0.47.0.md new file mode 100644 index 0000000..c944d99 --- /dev/null +++ b/VERIFICATION-0.47.0.md @@ -0,0 +1,26 @@ +# Orbit TV 0.44.0 to 0.47.0 verification + +Bigger pools from reviewed suggestions, a Toonami-inspired Vortex and tighter rules. + +## Changed +- 0.44: rule-based suggestions from Emby by community rating, with reasons, a review screen, and accepted and rejected choices saved apart from the schedule. Includes 0.43's launch retry. +- 0.45: Vortex lineup of daytime cartoons and evening anime, Toonami-inspired, as Paul asked. +- 0.46: asks Emby for year, age rating and score, which my first version omitted. Leaves out family films, animation, documentaries, music films and films under 70 minutes. Exact titles on Vortex. Saving finishes if you leave the screen. +- 0.47: After Dark sci-fi rule leaves out adventure films, and its thriller rule leaves out science fiction. Vortex's evening rule is action anime only, no TV-MA. After Dark's film rest is 7 days, since the pool is big enough. Failed pool reads are logged. + +## Checked on the box with 0.46, 2 November 2026 +| Channel | Pool | Your review | Programmes in 7 days | Requests | Read | Plan | Stored | Repeats in the week | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | +| After Dark | 140 films | 107 kept, 32 rejected | 93 | 30 | 35.6 s | 1.8 s | 50 KB | 20, shortest gap 51.3 h | +| Vortex | 75 shows, 4,136 episodes | 50 kept, 0 rejected | 433 | 125 | 42.4 s | 9.6 s | 385 KB | None | + +- Suggestion checks: 12 requests in 3.4 s for After Dark, 3 requests in 4.6 s for Vortex. +- catalogue.db fingerprint unchanged (b630828b...). + +## Unit tests +- assembleDebug, testDebugUnitTest and lintDebug pass; 210 tests, 0 failures. + +## Not checked +- 0.47 hasn't run on the box. Its rules and rest period only show after install and another review. +- Vortex's pool didn't refresh at 07:35 after its list changed, though it did when Paul saved. The cause wasn't found, which is why 0.47 logs read failures. +- How well the suggestions fit is Paul's judgement. Some choices are still marked unsure. diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index 34b0587..e1cd334 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -9,8 +9,8 @@ android { applicationId = "tv.orbit.classic" minSdk = 26 targetSdk = 36 - versionCode = 47 - versionName = "0.46.0-suggestion-rules" + versionCode = 48 + versionName = "0.47.0-tighter-pools" } buildFeatures { compose = true } compileOptions { sourceCompatibility = JavaVersion.VERSION_17; targetCompatibility = JavaVersion.VERSION_17 } diff --git a/android/app/src/main/java/tv/orbit/classic/ChannelSchedule.kt b/android/app/src/main/java/tv/orbit/classic/ChannelSchedule.kt index a5141c5..3ba09cf 100644 --- a/android/app/src/main/java/tv/orbit/classic/ChannelSchedule.kt +++ b/android/app/src/main/java/tv/orbit/classic/ChannelSchedule.kt @@ -31,21 +31,21 @@ internal val SmartChannels = listOf( ChannelProgramming(102, "After Dark", listOf("The Thing", "The Evil Dead", "Re-Animator", "Hellraiser", "Videodrome", "An American Werewolf in London", "Halloween", "Day of the Dead", "They Live", "Escape from New York", "The Fog", "Near Dark", "The Lost Boys", "Fright Night", "Society", "Tremors", "Basket Case", "Phantasm", "Repo Man", "Donnie Darko", "The Wicker Man", "Suspiria", "Eraserhead", "Blue Velvet", "From Dusk Till Dawn", "Scream", - "Poltergeist", "The Howling", "Creepshow", "Prince of Darkness"), seriesCount = 40, filmRestMs = 48 * 60 * 60_000L, + "Poltergeist", "The Howling", "Creepshow", "Prince of Darkness"), seriesCount = 40, filmRestMs = 7 * 24 * 60 * 60_000L, dayParts = listOf(DayPart(21, 5), DayPart(5, 21, listOf("The 'Burbs", "'Til Death Do Us Part", "Tremors", "The Lost Boys", "Fright Night", "Poltergeist", "Scream", "Escape from New York", "They Live", "Repo Man", "Donnie Darko", "From Dusk Till Dawn", "Creepshow", "Near Dark", "Halloween", "The Fog", "Blue Velvet", "The Wicker Man", "An American Werewolf in London", "Prince of Darkness"), group = "day")), suggestionRules = listOf( SuggestionRule("day", "Daytime", "Movie", listOf("Horror", "Comedy"), 1975..2010, 6f, setOf("NC-17", "X"), 40, NotCultCinema, 70), // Capped so the biggest blockbusters stay out: this channel is cult cinema. - SuggestionRule("day", "Daytime", "Movie", listOf("Science Fiction", "Action"), 1975..2005, 6.5f, setOf("NC-17", "X"), 40, NotCultCinema, 70, 7.9f), - SuggestionRule("day", "Daytime", "Movie", listOf("Thriller", "Mystery"), 1975..2005, 6.5f, setOf("NC-17", "X"), 30, NotCultCinema, 70, 7.9f), + SuggestionRule("day", "Daytime", "Movie", listOf("Science Fiction", "Action"), 1975..2005, 6.5f, setOf("NC-17", "X"), 40, NotCultCinema + "Adventure", 70, 7.9f), + SuggestionRule("day", "Daytime", "Movie", listOf("Thriller", "Mystery"), 1975..2005, 6.5f, setOf("NC-17", "X"), 30, NotCultCinema + "Science Fiction", 70, 7.9f), SuggestionRule("late", "Late night", "Movie", listOf("Horror"), 1970..2010, 6f, emptySet(), 90, NotCultCinema, 70))), ChannelProgramming(103, "Vortex", VortexDaytime + VortexEvening, seriesCount = 40, finishTogether = true, exactTitles = true, dayParts = listOf(DayPart(6, 18, VortexDaytime, group = "day"), DayPart(18, 6, VortexEvening, group = "night")), suggestionRules = listOf( SuggestionRule("day", "Daytime", "Series", listOf("Animation", "Action"), 1985..2015, 7f, setOf("TV-MA"), 30), - SuggestionRule("night", "Evening", "Series", listOf("Anime"), 1985..2020, 7.5f, emptySet(), 20))), + SuggestionRule("night", "Evening", "Series", listOf("Anime", "Action"), 1985..2020, 7f, setOf("TV-MA"), 30))), ChannelProgramming(140, "Terra", listOf("The Blue Planet", "Blue Planet II", "Planet Earth", "Planet Earth II", "Planet Earth III", "Frozen Planet", "Frozen Planet II", "Life on Earth", "The Living Planet", "The Trials of Life", "Our Planet", "Our Planet II", "Dynasties", "Dynasties II", "Seven Worlds, One Planet", "A Perfect Planet", "Hostile Planet", "Africa", "Wild China", "South Pacific", "Great Barrier Reef", "The Hunt", "The Life of Mammals", "The Life of Birds", "Nature's Great Events", "Green Planet", "Prehistoric Planet"), diff --git a/android/app/src/main/java/tv/orbit/classic/ChannelScheduler.kt b/android/app/src/main/java/tv/orbit/classic/ChannelScheduler.kt index e9bb9db..da529b6 100644 --- a/android/app/src/main/java/tv/orbit/classic/ChannelScheduler.kt +++ b/android/app/src/main/java/tv/orbit/classic/ChannelScheduler.kt @@ -49,7 +49,10 @@ internal class ChannelScheduler(private val store: ScheduleStore, private val cl pool = ScheduleStore.SavedPool(read.series, now, signature) store.savePool(userId, number, pool) } - } catch (failure: EmbyCheckException) { if (cached == null) throw failure } + } catch (failure: EmbyCheckException) { + Log.w("OrbitSchedule", "channel=$number poolReadFailed status=${failure.httpStatus} retryable=${failure.retryable} keptCache=${cached != null}") + if (cached == null) throw failure + } } val started = android.os.SystemClock.elapsedRealtime() val existing = store.loadPlan(userId, number) diff --git a/android/app/src/main/java/tv/orbit/classic/EmbyClient.kt b/android/app/src/main/java/tv/orbit/classic/EmbyClient.kt index c8c5bec..29a0fdb 100644 --- a/android/app/src/main/java/tv/orbit/classic/EmbyClient.kt +++ b/android/app/src/main/java/tv/orbit/classic/EmbyClient.kt @@ -41,7 +41,7 @@ internal class HttpsEmbyTransport(internal val deviceId: String = UUID.randomUUI connection.connectTimeout = 10_000 connection.readTimeout = request.readTimeoutMs ?: if (request.path == "/Sessions/Logout") 5_000 else 15_000 connection.setRequestProperty("Accept", "application/json") - connection.setRequestProperty("X-Emby-Authorization", "Emby Client=\"Orbit TV\", Device=\"Orbit TV\", DeviceId=\"$deviceId\", Version=\"0.46.0\"") + connection.setRequestProperty("X-Emby-Authorization", "Emby Client=\"Orbit TV\", Device=\"Orbit TV\", DeviceId=\"$deviceId\", Version=\"0.47.0\"") request.token?.let { connection.setRequestProperty("X-Emby-Token", it) } if (request.method == "POST") { val bytes = request.body.orEmpty().toByteArray(Charsets.UTF_8) diff --git a/android/app/src/main/java/tv/orbit/classic/SecureMediaDataSource.kt b/android/app/src/main/java/tv/orbit/classic/SecureMediaDataSource.kt index 60988f8..494e4e3 100644 --- a/android/app/src/main/java/tv/orbit/classic/SecureMediaDataSource.kt +++ b/android/app/src/main/java/tv/orbit/classic/SecureMediaDataSource.kt @@ -33,7 +33,7 @@ internal class SecureMediaDataSource(private val session: EmbySampleSession) : B next.instanceFollowRedirects = false next.connectTimeout = 10_000 next.readTimeout = 20_000 - next.setRequestProperty("User-Agent", "OrbitTV/0.46.0") + next.setRequestProperty("User-Agent", "OrbitTV/0.47.0") next.setRequestProperty("Accept-Encoding", "identity") session.mediaHeaders(address).forEach { (key, value) -> next.setRequestProperty(key, value) } if (dataSpec.position != 0L || dataSpec.length != C.LENGTH_UNSET.toLong()) { diff --git a/docs/roadmap.md b/docs/roadmap.md index 1eeb359..a9f8017 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -71,7 +71,7 @@ Audit and phased plan are in review, from `docs/briefs/indexing-programming-engi ## Smart channels status -Phase A of [the Smart Channels Foundation brief](briefs/smart-channels-foundation-2026-11-01.md) passed Paul's review on 2 November 2026, with Paradox on the box (VERIFICATION-0.39.0.md). Phase B (Terra and After Dark, VERIFICATION-0.40.0.md) and Phase C (Vortex, plus fewer repeats on Terra, VERIFICATION-0.41.0.md) are on the box as 0.41, tested and awaiting Paul's review. Day parts are on the box on Vortex and After Dark (VERIFICATION-0.42.0.md). Phase D (the remaining channels) needs separate approval. Pools are the current limit: Paul's library has far more films and shows than the curated lists use, which is the job for the programming director's reviewed suggestions. Animated idents are design files only and aren't in the app yet. +Phase A of [the Smart Channels Foundation brief](briefs/smart-channels-foundation-2026-11-01.md) passed Paul's review on 2 November 2026, with Paradox on the box (VERIFICATION-0.39.0.md). Phase B (Terra and After Dark, VERIFICATION-0.40.0.md) and Phase C (Vortex, plus fewer repeats on Terra, VERIFICATION-0.41.0.md) are on the box as 0.41, tested and awaiting Paul's review. Day parts are on the box on Vortex and After Dark (VERIFICATION-0.42.0.md). Phase D (the remaining channels) needs separate approval. Reviewed suggestions are built and in use on After Dark and Vortex (VERIFICATION-0.47.0.md), the first piece of the programming director. Next: a Vortex Movie Night as the first weekday event, then further channels. Animated idents are design files only and aren't in the app yet. ## Programming director