refactor(reader): Use SQLDelight to load chapter url

This commit is contained in:
Ahmad Ansori Palembani 2024-08-16 19:59:27 +07:00
parent a6ef46a90f
commit ce94bd2ad6
Signed by: null2264
GPG key ID: BA64F8B60AF3EFB6
6 changed files with 34 additions and 11 deletions

View file

@ -67,8 +67,6 @@ interface ChapterQueries : DbProvider {
) )
.prepare() .prepare()
fun insertChapter(chapter: Chapter) = db.put().`object`(chapter).prepare()
fun insertChapters(chapters: List<Chapter>) = db.put().objects(chapters).prepare() fun insertChapters(chapters: List<Chapter>) = db.put().objects(chapters).prepare()
fun updateKnownChaptersBackup(chapters: List<Chapter>) = db.put() fun updateKnownChaptersBackup(chapters: List<Chapter>) = db.put()

View file

@ -48,12 +48,13 @@ import eu.kanade.tachiyomi.util.isLocal
import eu.kanade.tachiyomi.util.storage.DiskUtil import eu.kanade.tachiyomi.util.storage.DiskUtil
import eu.kanade.tachiyomi.util.system.ImageUtil import eu.kanade.tachiyomi.util.system.ImageUtil
import eu.kanade.tachiyomi.util.system.e import eu.kanade.tachiyomi.util.system.e
import eu.kanade.tachiyomi.util.system.executeOnIO
import eu.kanade.tachiyomi.util.system.launchIO import eu.kanade.tachiyomi.util.system.launchIO
import eu.kanade.tachiyomi.util.system.launchNonCancellableIO import eu.kanade.tachiyomi.util.system.launchNonCancellableIO
import eu.kanade.tachiyomi.util.system.localeContext import eu.kanade.tachiyomi.util.system.localeContext
import eu.kanade.tachiyomi.util.system.withIOContext import eu.kanade.tachiyomi.util.system.withIOContext
import eu.kanade.tachiyomi.util.system.withUIContext import eu.kanade.tachiyomi.util.system.withUIContext
import java.util.Date
import java.util.concurrent.CancellationException
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
@ -76,14 +77,15 @@ import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import yokai.domain.chapter.interactor.GetChapter import yokai.domain.chapter.interactor.GetChapter
import yokai.domain.chapter.interactor.InsertChapter
import yokai.domain.download.DownloadPreferences import yokai.domain.download.DownloadPreferences
import yokai.domain.manga.interactor.GetManga
import yokai.domain.manga.interactor.InsertManga
import yokai.domain.manga.interactor.UpdateManga import yokai.domain.manga.interactor.UpdateManga
import yokai.domain.manga.models.MangaUpdate import yokai.domain.manga.models.MangaUpdate
import yokai.domain.storage.StorageManager import yokai.domain.storage.StorageManager
import yokai.i18n.MR import yokai.i18n.MR
import yokai.util.lang.getString import yokai.util.lang.getString
import java.util.*
import java.util.concurrent.*
/** /**
* Presenter used by the activity to perform background operations. * Presenter used by the activity to perform background operations.
@ -100,6 +102,9 @@ class ReaderViewModel(
private val downloadPreferences: DownloadPreferences = Injekt.get(), private val downloadPreferences: DownloadPreferences = Injekt.get(),
) : ViewModel() { ) : ViewModel() {
private val getChapter: GetChapter by injectLazy() private val getChapter: GetChapter by injectLazy()
private val insertChapter: InsertChapter by injectLazy()
private val getManga: GetManga by injectLazy()
private val insertManga: InsertManga by injectLazy()
private val updateManga: UpdateManga by injectLazy() private val updateManga: UpdateManga by injectLazy()
private val mutableState = MutableStateFlow(State()) private val mutableState = MutableStateFlow(State())
@ -310,8 +315,8 @@ class ReaderViewModel(
context.getString(MR.strings.source_not_installed), context.getString(MR.strings.source_not_installed),
) )
if (chapterUrl != null) { if (chapterUrl != null) {
val dbChapter = db.getChapters(chapterUrl).executeOnIO().find { val dbChapter = getChapter.awaitAllByUrl(chapterUrl, false).find {
val source = db.getManga(it.manga_id!!).executeOnIO()?.source ?: return@find false val source = getManga.awaitById(it.manga_id!!)?.source ?: return@find false
if (source == sourceId) { if (source == sourceId) {
true true
} else { } else {
@ -327,11 +332,11 @@ class ReaderViewModel(
val info = delegatedSource.fetchMangaFromChapterUrl(url) val info = delegatedSource.fetchMangaFromChapterUrl(url)
if (info != null) { if (info != null) {
val (chapter, manga, chapters) = info val (chapter, manga, chapters) = info
val id = db.insertManga(manga).executeOnIO().insertedId() val id = insertManga.await(manga)
manga.id = id ?: manga.id manga.id = id ?: manga.id
chapter.manga_id = manga.id chapter.manga_id = manga.id
val matchingChapterId = val matchingChapterId =
db.getChapters(manga).executeOnIO().find { it.url == chapter.url }?.id getChapter.awaitAll(manga.id!!, false).find { it.url == chapter.url }?.id
if (matchingChapterId != null) { if (matchingChapterId != null) {
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
this@ReaderViewModel.init(manga.id!!, matchingChapterId) this@ReaderViewModel.init(manga.id!!, matchingChapterId)
@ -348,7 +353,7 @@ class ReaderViewModel(
?: error(context.getString(MR.strings.chapter_not_found)) ?: error(context.getString(MR.strings.chapter_not_found))
} else { } else {
chapter.date_fetch = Date().time chapter.date_fetch = Date().time
chapterId = db.insertChapter(chapter).executeOnIO().insertedId() ?: error( chapterId = insertChapter.await(chapter) ?: error(
context.getString(MR.strings.unknown_error), context.getString(MR.strings.unknown_error),
) )
} }

View file

@ -16,6 +16,9 @@ class ChapterRepositoryImpl(private val handler: DatabaseHandler) : ChapterRepos
override fun getChaptersAsFlow(mangaId: Long, filterScanlators: Boolean): Flow<List<Chapter>> = override fun getChaptersAsFlow(mangaId: Long, filterScanlators: Boolean): Flow<List<Chapter>> =
handler.subscribeToList { chaptersQueries.getChaptersByMangaId(mangaId, filterScanlators.toInt().toLong(), Chapter::mapper) } handler.subscribeToList { chaptersQueries.getChaptersByMangaId(mangaId, filterScanlators.toInt().toLong(), Chapter::mapper) }
override suspend fun getChaptersByUrl(url: String, filterScanlators: Boolean): List<Chapter> =
handler.awaitList { chaptersQueries.getChaptersByUrl(url, filterScanlators.toInt().toLong(), Chapter::mapper) }
override suspend fun getRecents(filterScanlators: Boolean, search: String, limit: Long, offset: Long): List<MangaChapter> = override suspend fun getRecents(filterScanlators: Boolean, search: String, limit: Long, offset: Long): List<MangaChapter> =
handler.awaitList { chaptersQueries.getRecents(search, filterScanlators.toInt().toLong(), limit, offset, MangaChapter::mapper) } handler.awaitList { chaptersQueries.getRecents(search, filterScanlators.toInt().toLong(), limit, offset, MangaChapter::mapper) }

View file

@ -9,6 +9,8 @@ interface ChapterRepository {
suspend fun getChapters(mangaId: Long, filterScanlators: Boolean): List<Chapter> suspend fun getChapters(mangaId: Long, filterScanlators: Boolean): List<Chapter>
fun getChaptersAsFlow(mangaId: Long, filterScanlators: Boolean): Flow<List<Chapter>> fun getChaptersAsFlow(mangaId: Long, filterScanlators: Boolean): Flow<List<Chapter>>
suspend fun getChaptersByUrl(url: String, filterScanlators: Boolean): List<Chapter>
suspend fun getRecents(filterScanlators: Boolean, search: String = "", limit: Long = 25L, offset: Long = 0L): List<MangaChapter> suspend fun getRecents(filterScanlators: Boolean, search: String = "", limit: Long = 25L, offset: Long = 0L): List<MangaChapter>
suspend fun getScanlatorsByChapter(mangaId: Long): List<String> suspend fun getScanlatorsByChapter(mangaId: Long): List<String>

View file

@ -6,9 +6,13 @@ import yokai.domain.chapter.ChapterRepository
class GetChapter( class GetChapter(
private val chapterRepository: ChapterRepository, private val chapterRepository: ChapterRepository,
) { ) {
suspend fun awaitAll(mangaId: Long, filterScanlators: Boolean) = chapterRepository.getChapters(mangaId, filterScanlators) suspend fun awaitAll(mangaId: Long, filterScanlators: Boolean) =
chapterRepository.getChapters(mangaId, filterScanlators)
suspend fun awaitAll(manga: Manga, filterScanlators: Boolean? = null) = suspend fun awaitAll(manga: Manga, filterScanlators: Boolean? = null) =
awaitAll(manga.id!!, filterScanlators ?: (manga.filtered_scanlators?.isNotEmpty() == true)) awaitAll(manga.id!!, filterScanlators ?: (manga.filtered_scanlators?.isNotEmpty() == true))
suspend fun awaitAllByUrl(chapterUrl: String, filterScanlators: Boolean) =
chapterRepository.getChaptersByUrl(chapterUrl, filterScanlators)
fun subscribeAll(mangaId: Long, filterScanlators: Boolean) = chapterRepository.getChaptersAsFlow(mangaId, filterScanlators) fun subscribeAll(mangaId: Long, filterScanlators: Boolean) = chapterRepository.getChaptersAsFlow(mangaId, filterScanlators)
} }

View file

@ -32,6 +32,17 @@ AND (
:apply_filter = 0 OR S.name IS NULL :apply_filter = 0 OR S.name IS NULL
); );
getChaptersByUrl:
SELECT C.*
FROM chapters AS C
LEFT JOIN scanlators_view AS S
ON C.manga_id = S.manga_id
AND ifnull(C.scanlator, 'N/A') = ifnull(S.name, '/<INVALID>/') -- I assume if it's N/A it shouldn't be filtered
WHERE C.url = :url
AND (
:apply_filter = 0 OR S.name IS NULL
);
getRecents: getRecents:
SELECT SELECT
M.*, M.*,