From d3999465f648b594814e235f5e6a5fbe2e7a6ff7 Mon Sep 17 00:00:00 2001 From: Paul Woitaschek Date: Mon, 1 Aug 2022 18:47:09 +0200 Subject: [PATCH] Account for the max sql number when migrating the bookmarks. --- .../voice/data/RunForMaxSqlVariableNumber.kt | 7 +-- .../kotlin/voice/app/scanner/BookParser.kt | 40 ++------------ .../voice/app/scanner/BookmarkMigrator.kt | 54 +++++++++++++++++++ .../voice/app/scanner/MediaScannerTest.kt | 5 +- 4 files changed, 65 insertions(+), 41 deletions(-) create mode 100644 scanner/src/main/kotlin/voice/app/scanner/BookmarkMigrator.kt diff --git a/data/src/main/kotlin/voice/data/RunForMaxSqlVariableNumber.kt b/data/src/main/kotlin/voice/data/RunForMaxSqlVariableNumber.kt index dbf7d13e37..a2ee1bb50b 100644 --- a/data/src/main/kotlin/voice/data/RunForMaxSqlVariableNumber.kt +++ b/data/src/main/kotlin/voice/data/RunForMaxSqlVariableNumber.kt @@ -2,17 +2,18 @@ package voice.data import androidx.annotation.VisibleForTesting -private const val SQLITE_MAX_VARIABLE_NUMBER = 990 +@PublishedApi +internal const val SQLITE_MAX_VARIABLE_NUMBER = 990 // we can only query SQLITE_MAX_VARIABLE_NUMBER at once (999 bugs on some devices so we use a number a little smaller.) // if it's larger than the limit, we query in chunks. -internal inline fun List.runForMaxSqlVariableNumber( +inline fun List.runForMaxSqlVariableNumber( @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) limit: Int = SQLITE_MAX_VARIABLE_NUMBER, action: (List) -> List, ): List { return when { - size == 0 -> emptyList() + isEmpty() -> emptyList() size <= limit -> action(this) else -> chunked(limit).flatMap(action) } diff --git a/scanner/src/main/kotlin/voice/app/scanner/BookParser.kt b/scanner/src/main/kotlin/voice/app/scanner/BookParser.kt index e5fe753f9e..bf4d41c55d 100644 --- a/scanner/src/main/kotlin/voice/app/scanner/BookParser.kt +++ b/scanner/src/main/kotlin/voice/app/scanner/BookParser.kt @@ -6,12 +6,9 @@ import androidx.documentfile.provider.DocumentFile import voice.common.BookId import voice.data.Book import voice.data.BookContent -import voice.data.Bookmark import voice.data.Chapter -import voice.data.legacy.LegacyBookMetaData import voice.data.legacy.LegacyBookSettings import voice.data.repo.BookContentRepo -import voice.data.repo.internals.dao.BookmarkDao import voice.data.repo.internals.dao.LegacyBookDao import voice.data.toUri import voice.logging.core.Logger @@ -25,7 +22,7 @@ class BookParser private val mediaAnalyzer: MediaAnalyzer, private val legacyBookDao: LegacyBookDao, private val application: Application, - private val bookmarkDao: BookmarkDao, + private val bookmarkMigrator: BookmarkMigrator, ) { suspend fun parseAndStore(chapters: List, file: DocumentFile): BookContent { @@ -43,7 +40,7 @@ class BookParser } if (migrationMetaData != null) { - migrateBookmarks(migrationMetaData, chapters, id) + bookmarkMigrator.migrate(migrationMetaData, chapters, id) } val migratedPlaybackPosition = migrationSettings?.let { findMigratedPlaybackPosition(it, chapters) } @@ -94,37 +91,6 @@ class BookParser val playbackPosition: Long, ) - private suspend fun migrateBookmarks(migrationMetaData: LegacyBookMetaData, chapters: List, id: BookId) { - val legacyChapters = legacyBookDao.chapters() - .filter { - it.bookId == migrationMetaData.id - } - - legacyBookDao.bookmarksByFiles(legacyChapters.map { it.file }) - .forEach { legacyBookmark -> - val legacyChapter = legacyChapters.find { it.file == legacyBookmark.mediaFile } - if (legacyChapter != null) { - val matchingChapter = chapters.find { - val chapterFilePath = it.id.toUri().filePath() ?: return@find false - legacyChapter.file.absolutePath.endsWith(chapterFilePath) - } - if (matchingChapter != null) { - bookmarkDao.addBookmark( - Bookmark( - bookId = id, - addedAt = legacyBookmark.addedAt, - chapterId = matchingChapter.id, - id = Bookmark.Id.random(), - setBySleepTimer = legacyBookmark.setBySleepTimer, - time = legacyBookmark.time, - title = legacyBookmark.title, - ), - ) - } - } - } - } - private fun DocumentFile.bookName(): String { val fileName = name return if (fileName == null) { @@ -150,7 +116,7 @@ internal fun validateIntegrity(content: BookContent, chapters: List) { Book(content, chapters) } -private fun Uri.filePath(): String? { +internal fun Uri.filePath(): String? { return pathSegments.lastOrNull() ?.dropWhile { it != ':' } ?.removePrefix(":") diff --git a/scanner/src/main/kotlin/voice/app/scanner/BookmarkMigrator.kt b/scanner/src/main/kotlin/voice/app/scanner/BookmarkMigrator.kt new file mode 100644 index 0000000000..7e03c4c0fa --- /dev/null +++ b/scanner/src/main/kotlin/voice/app/scanner/BookmarkMigrator.kt @@ -0,0 +1,54 @@ +package voice.app.scanner + +import voice.common.BookId +import voice.data.Bookmark +import voice.data.Chapter +import voice.data.legacy.LegacyBookMetaData +import voice.data.repo.internals.dao.BookmarkDao +import voice.data.repo.internals.dao.LegacyBookDao +import voice.data.runForMaxSqlVariableNumber +import voice.data.toUri +import javax.inject.Inject + +class BookmarkMigrator +@Inject constructor( + private val legacyBookDao: LegacyBookDao, + private val bookmarkDao: BookmarkDao, +) { + + suspend fun migrate(migrationMetaData: LegacyBookMetaData, chapters: List, id: BookId) { + legacyBookDao.chapters() + .filter { + it.bookId == migrationMetaData.id + } + .map { it.file } + .runForMaxSqlVariableNumber { legacyBookDao.bookmarksByFiles(it) } + .forEach { legacyBookmark -> + val legacyChapter = legacyBookDao.chapters() + .filter { + it.bookId == migrationMetaData.id + } + .find { it.file == legacyBookmark.mediaFile } + + if (legacyChapter != null) { + val matchingChapter = chapters.find { + val chapterFilePath = it.id.toUri().filePath() ?: return@find false + legacyChapter.file.absolutePath.endsWith(chapterFilePath) + } + if (matchingChapter != null) { + bookmarkDao.addBookmark( + Bookmark( + bookId = id, + addedAt = legacyBookmark.addedAt, + chapterId = matchingChapter.id, + id = Bookmark.Id.random(), + setBySleepTimer = legacyBookmark.setBySleepTimer, + time = legacyBookmark.time, + title = legacyBookmark.title, + ), + ) + } + } + } + } +} diff --git a/scanner/src/test/kotlin/voice/app/scanner/MediaScannerTest.kt b/scanner/src/test/kotlin/voice/app/scanner/MediaScannerTest.kt index b93582e55f..dfd2540175 100644 --- a/scanner/src/test/kotlin/voice/app/scanner/MediaScannerTest.kt +++ b/scanner/src/test/kotlin/voice/app/scanner/MediaScannerTest.kt @@ -141,8 +141,11 @@ class MediaScannerTest { contentRepo = bookContentRepo, mediaAnalyzer = mediaAnalyzer, application = ApplicationProvider.getApplicationContext(), - bookmarkDao = db.bookmarkDao(), legacyBookDao = db.legacyBookDao(), + bookmarkMigrator = BookmarkMigrator( + legacyBookDao = db.legacyBookDao(), + bookmarkDao = db.bookmarkDao(), + ), ), )