Skip to content

Commit

Permalink
Account for the max sql number when migrating the bookmarks.
Browse files Browse the repository at this point in the history
  • Loading branch information
PaulWoitaschek committed Aug 1, 2022
1 parent 8c8e56d commit d399946
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 41 deletions.
7 changes: 4 additions & 3 deletions data/src/main/kotlin/voice/data/RunForMaxSqlVariableNumber.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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 <T, R> List<T>.runForMaxSqlVariableNumber(
inline fun <T, R> List<T>.runForMaxSqlVariableNumber(
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
limit: Int = SQLITE_MAX_VARIABLE_NUMBER,
action: (List<T>) -> List<R>,
): List<R> {
return when {
size == 0 -> emptyList()
isEmpty() -> emptyList()
size <= limit -> action(this)
else -> chunked(limit).flatMap(action)
}
Expand Down
40 changes: 3 additions & 37 deletions scanner/src/main/kotlin/voice/app/scanner/BookParser.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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<Chapter>, file: DocumentFile): BookContent {
Expand All @@ -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) }
Expand Down Expand Up @@ -94,37 +91,6 @@ class BookParser
val playbackPosition: Long,
)

private suspend fun migrateBookmarks(migrationMetaData: LegacyBookMetaData, chapters: List<Chapter>, 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) {
Expand All @@ -150,7 +116,7 @@ internal fun validateIntegrity(content: BookContent, chapters: List<Chapter>) {
Book(content, chapters)
}

private fun Uri.filePath(): String? {
internal fun Uri.filePath(): String? {
return pathSegments.lastOrNull()
?.dropWhile { it != ':' }
?.removePrefix(":")
Expand Down
54 changes: 54 additions & 0 deletions scanner/src/main/kotlin/voice/app/scanner/BookmarkMigrator.kt
Original file line number Diff line number Diff line change
@@ -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<Chapter>, 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,
),
)
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
),
),
)

Expand Down

0 comments on commit d399946

Please sign in to comment.