summaryrefslogtreecommitdiff
path: root/app/src
diff options
context:
space:
mode:
Diffstat (limited to 'app/src')
-rw-r--r--app/src/androidTest/java/org/terst/listen/data/MigrationTest.kt40
-rw-r--r--app/src/main/java/org/terst/listen/data/AppDatabase.kt17
-rw-r--r--app/src/main/java/org/terst/listen/data/Entities.kt8
3 files changed, 63 insertions, 2 deletions
diff --git a/app/src/androidTest/java/org/terst/listen/data/MigrationTest.kt b/app/src/androidTest/java/org/terst/listen/data/MigrationTest.kt
index 98f5ad1..fa070de 100644
--- a/app/src/androidTest/java/org/terst/listen/data/MigrationTest.kt
+++ b/app/src/androidTest/java/org/terst/listen/data/MigrationTest.kt
@@ -517,4 +517,44 @@ class MigrationTest {
assertEquals("the crown jewel must survive", 616161L, cursor.getLong(2))
}
}
+
+ /**
+ * Existing rows were written before anything knew what kind of break they were, and the only
+ * safe assumption is the one that matches old behaviour: everything was skipped, so call it
+ * advertising. The server overwrites each episode's ranges on its next download anyway.
+ */
+ @Test
+ fun migrate12To13KeepsExistingBreaksAndCallsThemAdvertising() {
+ helper.createDatabase(name, 12).apply {
+ execSQL(
+ """INSERT INTO subscriptions
+ (id, feedUrl, kind, title, addedAtMs, skipIntroMs, skipOutroMs, dripEnabled,
+ dripIntervalMs, dripCount, dripOldestFirst, skipAdChapters, bedtime)
+ VALUES ('s1', 'https://example.com/feed.xml', 'PODCAST', 'A Show', 1000, 0, 0,
+ 0, 86400000, 1, 1, 1, 0)"""
+ )
+ execSQL(
+ """INSERT INTO episodes
+ (id, subscriptionId, guid, title, mediaUrl, mediaType, discoveredAtMs,
+ positionMs, downloadState)
+ VALUES ('e1', 's1', 'g1', 'One', 'https://cdn/1.mp3', 'audio/mpeg', 1000,
+ 0, 'NONE')"""
+ )
+ execSQL(
+ "INSERT INTO episode_midrolls (episodeId, candidateId, startMs, endMs) " +
+ "VALUES ('e1', 'server-0', 1000, 2000)"
+ )
+ close()
+ }
+
+ val db = helper.runMigrationsAndValidate(name, 13, true, AppDatabase.MIGRATION_12_13)
+
+ db.query("SELECT startMs, endMs, kind FROM episode_midrolls WHERE episodeId = 'e1'").use {
+ assertEquals("the break was lost", 1, it.count)
+ it.moveToFirst()
+ assertEquals(1000L, it.getLong(0))
+ assertEquals(2000L, it.getLong(1))
+ assertEquals("ad", it.getString(2))
+ }
+ }
}
diff --git a/app/src/main/java/org/terst/listen/data/AppDatabase.kt b/app/src/main/java/org/terst/listen/data/AppDatabase.kt
index 443a23d..6bc7df4 100644
--- a/app/src/main/java/org/terst/listen/data/AppDatabase.kt
+++ b/app/src/main/java/org/terst/listen/data/AppDatabase.kt
@@ -30,7 +30,7 @@ class Converters {
ShowMidrollEntity::class,
EpisodeMidrollEntity::class,
],
- version = 12,
+ version = 13,
exportSchema = true,
)
@TypeConverters(Converters::class)
@@ -346,6 +346,19 @@ abstract class AppDatabase : RoomDatabase() {
}
}
+ /**
+ * Breaks gain a kind, so advertising and a show's own intro, break cue and credits can
+ * be skipped on different terms.
+ *
+ * Existing rows become "ad" because that is what they behaved as: everything in this
+ * table was skipped unconditionally before the kind existed.
+ */
+ val MIGRATION_12_13 = object : Migration(12, 13) {
+ override fun migrate(db: SupportSQLiteDatabase) {
+ db.execSQL("ALTER TABLE `episode_midrolls` ADD COLUMN `kind` TEXT NOT NULL DEFAULT 'ad'")
+ }
+ }
+
fun get(context: Context): AppDatabase = instance ?: synchronized(this) {
instance ?: build(context.applicationContext).also { instance = it }
}
@@ -357,7 +370,7 @@ abstract class AppDatabase : RoomDatabase() {
.addMigrations(
MIGRATION_1_2, MIGRATION_2_3, MIGRATION_3_4, MIGRATION_4_5, MIGRATION_5_6,
MIGRATION_6_7, MIGRATION_7_8, MIGRATION_8_9, MIGRATION_9_10,
- MIGRATION_10_11, MIGRATION_11_12,
+ MIGRATION_10_11, MIGRATION_11_12, MIGRATION_12_13,
)
.addCallback(SEED_DEFAULT_FILTERS)
// No fallbackToDestructiveMigration. A listener's playback positions and play
diff --git a/app/src/main/java/org/terst/listen/data/Entities.kt b/app/src/main/java/org/terst/listen/data/Entities.kt
index b14ed2b..7480101 100644
--- a/app/src/main/java/org/terst/listen/data/Entities.kt
+++ b/app/src/main/java/org/terst/listen/data/Entities.kt
@@ -441,6 +441,14 @@ data class EpisodeMidrollEntity(
val candidateId: String,
val startMs: Long,
val endMs: Long,
+ /**
+ * "ad" for inserted advertising, or "intro", "cue" or "outro" for the show's own audio.
+ *
+ * Defaulted to "ad" rather than left null: a row written before kinds existed was skipped
+ * unconditionally, and advertising is the kind that is still skipped unconditionally, so the
+ * default preserves exactly what those rows already did.
+ */
+ @ColumnInfo(defaultValue = "ad") val kind: String = "ad",
)
/**