Use SQLDelight for all Manga related queries (#7447)
(cherry picked from commit 17951cfd68)
# Conflicts:
# app/src/main/java/eu/kanade/domain/DomainModule.kt
# app/src/main/java/eu/kanade/domain/manga/repository/MangaRepository.kt
# app/src/main/java/eu/kanade/tachiyomi/data/database/DatabaseHelper.kt
# app/src/main/java/eu/kanade/tachiyomi/data/database/DbExtensions.kt
# app/src/main/java/eu/kanade/tachiyomi/data/database/DbProvider.kt
# app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/ChapterTypeMapping.kt
# app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/MangaCategoryTypeMapping.kt
# app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/MangaTypeMapping.kt
# app/src/main/java/eu/kanade/tachiyomi/data/database/queries/MangaQueries.kt
# app/src/main/java/eu/kanade/tachiyomi/data/database/queries/RawQueries.kt
# app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/ChapterProgressPutResolver.kt
# app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/LibraryMangaGetResolver.kt
# app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaFlagsPutResolver.kt
# app/src/main/java/eu/kanade/tachiyomi/data/database/tables/CategoryTable.kt
# app/src/main/java/eu/kanade/tachiyomi/data/database/tables/ChapterTable.kt
# app/src/main/java/eu/kanade/tachiyomi/data/database/tables/MangaCategoryTable.kt
# app/src/main/java/eu/kanade/tachiyomi/data/database/tables/MangaTable.kt
# app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt
# app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/SearchController.kt
# app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourcePresenter.kt
# app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt
# app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt
This commit is contained in:
@@ -2,21 +2,21 @@
|
||||
|
||||
package exh
|
||||
|
||||
import android.content.Context
|
||||
import androidx.core.content.edit
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.pushtorefresh.storio.sqlite.queries.Query
|
||||
import eu.kanade.data.DatabaseHandler
|
||||
import eu.kanade.data.chapter.chapterMapper
|
||||
import eu.kanade.domain.chapter.interactor.DeleteChapters
|
||||
import eu.kanade.domain.chapter.interactor.UpdateChapter
|
||||
import eu.kanade.domain.chapter.model.ChapterUpdate
|
||||
import eu.kanade.domain.manga.interactor.GetManga
|
||||
import eu.kanade.domain.manga.interactor.GetMangaBySource
|
||||
import eu.kanade.domain.manga.interactor.InsertMergedReference
|
||||
import eu.kanade.domain.manga.interactor.UpdateManga
|
||||
import eu.kanade.domain.manga.model.MangaUpdate
|
||||
import eu.kanade.tachiyomi.BuildConfig
|
||||
import eu.kanade.tachiyomi.data.backup.BackupCreatorJob
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.database.tables.ChapterTable
|
||||
import eu.kanade.tachiyomi.data.library.LibraryUpdateJob
|
||||
import eu.kanade.tachiyomi.data.preference.MANGA_NON_COMPLETED
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceKeys
|
||||
@@ -39,7 +39,6 @@ import eu.kanade.tachiyomi.util.preference.minusAssign
|
||||
import eu.kanade.tachiyomi.util.system.DeviceUtil
|
||||
import exh.eh.EHentaiUpdateWorker
|
||||
import exh.log.xLogE
|
||||
import exh.log.xLogW
|
||||
import exh.merged.sql.models.MergedMangaReference
|
||||
import exh.source.BlacklistedSources
|
||||
import exh.source.EH_SOURCE_ID
|
||||
@@ -69,12 +68,14 @@ import java.net.URISyntaxException
|
||||
import eu.kanade.domain.manga.model.Manga as DomainManga
|
||||
|
||||
object EXHMigrations {
|
||||
private val db: DatabaseHelper by injectLazy()
|
||||
private val handler: DatabaseHandler by injectLazy()
|
||||
private val sourceManager: SourceManager by injectLazy()
|
||||
private val getManga: GetManga by injectLazy()
|
||||
private val getMangaBySource: GetMangaBySource by injectLazy()
|
||||
private val updateManga: UpdateManga by injectLazy()
|
||||
private val updateChapter: UpdateChapter by injectLazy()
|
||||
private val deleteChapters: DeleteChapters by injectLazy()
|
||||
private val insertMergedReference: InsertMergedReference by injectLazy()
|
||||
|
||||
/**
|
||||
* Performs a migration when the application is updated.
|
||||
@@ -125,89 +126,73 @@ object EXHMigrations {
|
||||
updateSourceId(NHentai.otherId, 6907)
|
||||
}
|
||||
if (oldVersion under 7) {
|
||||
db.inTransaction {
|
||||
val mergedMangas = runBlocking { getMangaBySource.await(MERGED_SOURCE_ID) }
|
||||
val mergedMangas = runBlocking { getMangaBySource.await(MERGED_SOURCE_ID) }
|
||||
|
||||
if (mergedMangas.isNotEmpty()) {
|
||||
val mangaConfigs = mergedMangas.mapNotNull { mergedManga -> readMangaConfig(mergedManga)?.let { mergedManga to it } }
|
||||
if (mangaConfigs.isNotEmpty()) {
|
||||
val mangaToUpdate = mutableListOf<MangaUpdate>()
|
||||
val mergedMangaReferences = mutableListOf<MergedMangaReference>()
|
||||
mangaConfigs.onEach { mergedManga ->
|
||||
val newFirst = mergedManga.second.children.firstOrNull()?.url?.let {
|
||||
if (runBlocking { getManga.await(it, MERGED_SOURCE_ID) } != null) return@onEach
|
||||
mangaToUpdate += MangaUpdate(id = mergedManga.first.id, url = it)
|
||||
mergedManga.first.copy(url = it)
|
||||
} ?: mergedManga.first
|
||||
if (mergedMangas.isNotEmpty()) {
|
||||
val mangaConfigs = mergedMangas.mapNotNull { mergedManga -> readMangaConfig(mergedManga)?.let { mergedManga to it } }
|
||||
if (mangaConfigs.isNotEmpty()) {
|
||||
val mangaToUpdate = mutableListOf<MangaUpdate>()
|
||||
val mergedMangaReferences = mutableListOf<MergedMangaReference>()
|
||||
mangaConfigs.onEach { mergedManga ->
|
||||
val newFirst = mergedManga.second.children.firstOrNull()?.url?.let {
|
||||
if (runBlocking { getManga.await(it, MERGED_SOURCE_ID) } != null) return@onEach
|
||||
mangaToUpdate += MangaUpdate(id = mergedManga.first.id, url = it)
|
||||
mergedManga.first.copy(url = it)
|
||||
} ?: mergedManga.first
|
||||
mergedMangaReferences += MergedMangaReference(
|
||||
id = null,
|
||||
isInfoManga = false,
|
||||
getChapterUpdates = false,
|
||||
chapterSortMode = 0,
|
||||
chapterPriority = 0,
|
||||
downloadChapters = false,
|
||||
mergeId = newFirst.id,
|
||||
mergeUrl = newFirst.url,
|
||||
mangaId = newFirst.id,
|
||||
mangaUrl = newFirst.url,
|
||||
mangaSourceId = MERGED_SOURCE_ID,
|
||||
)
|
||||
mergedManga.second.children.distinct().forEachIndexed { index, mangaSource ->
|
||||
val load = mangaSource.load() ?: return@forEachIndexed
|
||||
mergedMangaReferences += MergedMangaReference(
|
||||
id = null,
|
||||
isInfoManga = false,
|
||||
getChapterUpdates = false,
|
||||
isInfoManga = index == 0,
|
||||
getChapterUpdates = true,
|
||||
chapterSortMode = 0,
|
||||
chapterPriority = 0,
|
||||
downloadChapters = false,
|
||||
mergeId = mergedManga.first.id,
|
||||
mergeUrl = mergedManga.first.url,
|
||||
mangaId = mergedManga.first.id,
|
||||
mangaUrl = mergedManga.first.url,
|
||||
mangaSourceId = MERGED_SOURCE_ID,
|
||||
downloadChapters = true,
|
||||
mergeId = newFirst.id,
|
||||
mergeUrl = newFirst.url,
|
||||
mangaId = load.manga.id,
|
||||
mangaUrl = load.manga.url,
|
||||
mangaSourceId = load.source.id,
|
||||
)
|
||||
mergedManga.second.children.distinct().forEachIndexed { index, mangaSource ->
|
||||
val load = mangaSource.load(db, sourceManager) ?: return@forEachIndexed
|
||||
mergedMangaReferences += MergedMangaReference(
|
||||
id = null,
|
||||
isInfoManga = index == 0,
|
||||
getChapterUpdates = true,
|
||||
chapterSortMode = 0,
|
||||
chapterPriority = 0,
|
||||
downloadChapters = true,
|
||||
mergeId = mergedManga.first.id,
|
||||
mergeUrl = mergedManga.first.url,
|
||||
mangaId = load.manga.id!!,
|
||||
mangaUrl = load.manga.url,
|
||||
mangaSourceId = load.source.id,
|
||||
)
|
||||
}
|
||||
}
|
||||
runBlocking {
|
||||
updateManga.awaitAll(mangaToUpdate)
|
||||
}
|
||||
db.insertMergedMangas(mergedMangaReferences).executeAsBlocking()
|
||||
}
|
||||
runBlocking {
|
||||
updateManga.awaitAll(mangaToUpdate)
|
||||
insertMergedReference.awaitAll(mergedMangaReferences)
|
||||
}
|
||||
|
||||
val loadedMangaList = mangaConfigs.map { it.second.children }.flatten().mapNotNull { it.load(db, sourceManager) }.distinct()
|
||||
val chapters = db.db.get()
|
||||
.listOfObjects(Chapter::class.java)
|
||||
.withQuery(
|
||||
Query.builder()
|
||||
.table(ChapterTable.TABLE)
|
||||
.where("${ChapterTable.COL_MANGA_ID} IN (${mergedMangas.joinToString { it.id.toString() }})")
|
||||
.build(),
|
||||
val loadedMangaList = mangaConfigs.map { it.second.children }.flatten().mapNotNull { it.load() }.distinct()
|
||||
val chapters = runBlocking { handler.awaitList { ehQueries.getChaptersByMangaIds(mergedMangas.map { it.id }, chapterMapper) } }
|
||||
val mergedMangaChapters = runBlocking { handler.awaitList { ehQueries.getChaptersByMangaIds(loadedMangaList.map { it.manga.id }, chapterMapper) } }
|
||||
|
||||
val mergedMangaChaptersMatched = mergedMangaChapters.mapNotNull { chapter -> loadedMangaList.firstOrNull { it.manga.id == chapter.id }?.let { it to chapter } }
|
||||
val parsedChapters = chapters.filter { it.read || it.lastPageRead != 0L }.mapNotNull { chapter -> readUrlConfig(chapter.url)?.let { chapter to it } }
|
||||
val chaptersToUpdate = mutableListOf<ChapterUpdate>()
|
||||
parsedChapters.forEach { parsedChapter ->
|
||||
mergedMangaChaptersMatched.firstOrNull { it.second.url == parsedChapter.second.url && it.first.source.id == parsedChapter.second.source && it.first.manga.url == parsedChapter.second.mangaUrl }?.let {
|
||||
chaptersToUpdate += ChapterUpdate(
|
||||
it.second.id,
|
||||
read = parsedChapter.first.read,
|
||||
lastPageRead = parsedChapter.first.lastPageRead,
|
||||
)
|
||||
.prepare()
|
||||
.executeAsBlocking()
|
||||
val mergedMangaChapters = db.db.get()
|
||||
.listOfObjects(Chapter::class.java)
|
||||
.withQuery(
|
||||
Query.builder()
|
||||
.table(ChapterTable.TABLE)
|
||||
.where("${ChapterTable.COL_MANGA_ID} IN (${loadedMangaList.filter { it.manga.id != null }.joinToString { it.manga.id.toString() }})")
|
||||
.build(),
|
||||
)
|
||||
.prepare()
|
||||
.executeAsBlocking()
|
||||
val mergedMangaChaptersMatched = mergedMangaChapters.mapNotNull { chapter -> loadedMangaList.firstOrNull { it.manga.id == chapter.id }?.let { it to chapter } }
|
||||
val parsedChapters = chapters.filter { it.read || it.last_page_read != 0 }.mapNotNull { chapter -> readUrlConfig(chapter.url)?.let { chapter to it } }
|
||||
val chaptersToUpdate = mutableListOf<Chapter>()
|
||||
parsedChapters.forEach { parsedChapter ->
|
||||
mergedMangaChaptersMatched.firstOrNull { it.second.url == parsedChapter.second.url && it.first.source.id == parsedChapter.second.source && it.first.manga.url == parsedChapter.second.mangaUrl }?.let {
|
||||
chaptersToUpdate += it.second.apply {
|
||||
read = parsedChapter.first.read
|
||||
last_page_read = parsedChapter.first.last_page_read
|
||||
}
|
||||
}
|
||||
}
|
||||
db.deleteChapters(mergedMangaChapters).executeAsBlocking()
|
||||
db.updateChaptersProgress(chaptersToUpdate).executeAsBlocking()
|
||||
}
|
||||
runBlocking {
|
||||
deleteChapters.await(mergedMangaChapters.map { it.id })
|
||||
updateChapter.awaitAll(chaptersToUpdate)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -471,18 +456,6 @@ object EXHMigrations {
|
||||
}
|
||||
}
|
||||
|
||||
private fun backupDatabase(context: Context, oldMigrationVersion: Int) {
|
||||
val backupLocation = File(File(context.filesDir, "exh_db_bck"), "$oldMigrationVersion.bck.db")
|
||||
if (backupLocation.exists()) return // Do not backup same version twice
|
||||
|
||||
val dbLocation = context.getDatabasePath(db.lowLevel().sqliteOpenHelper().databaseName)
|
||||
try {
|
||||
dbLocation.copyTo(backupLocation, overwrite = true)
|
||||
} catch (t: Throwable) {
|
||||
xLogW("Failed to backup database!")
|
||||
}
|
||||
}
|
||||
|
||||
private fun getUrlWithoutDomain(orig: String): String {
|
||||
return try {
|
||||
val uri = URI(orig)
|
||||
@@ -536,8 +509,8 @@ object EXHMigrations {
|
||||
@SerialName("u")
|
||||
val url: String,
|
||||
) {
|
||||
fun load(db: DatabaseHelper, sourceManager: SourceManager): LoadedMangaSource? {
|
||||
val manga = db.getManga(url, source).executeAsBlocking() ?: return null
|
||||
fun load(): LoadedMangaSource? {
|
||||
val manga = runBlocking { getManga.await(url, source) } ?: return null
|
||||
val source = sourceManager.getOrStub(source)
|
||||
return LoadedMangaSource(source, manga)
|
||||
}
|
||||
@@ -551,7 +524,7 @@ object EXHMigrations {
|
||||
}
|
||||
}
|
||||
|
||||
private data class LoadedMangaSource(val source: Source, val manga: Manga)
|
||||
private data class LoadedMangaSource(val source: Source, val manga: DomainManga)
|
||||
|
||||
private fun updateSourceId(newId: Long, oldId: Long) {
|
||||
runBlocking {
|
||||
|
||||
@@ -2,7 +2,6 @@ package exh.debug
|
||||
|
||||
import android.app.Application
|
||||
import androidx.work.WorkManager
|
||||
import eu.kanade.data.AndroidDatabaseHandler
|
||||
import eu.kanade.data.DatabaseHandler
|
||||
import eu.kanade.domain.manga.interactor.GetAllManga
|
||||
import eu.kanade.domain.manga.interactor.GetExhFavoriteMangaWithMetadata
|
||||
@@ -12,7 +11,6 @@ import eu.kanade.domain.manga.interactor.GetSearchMetadata
|
||||
import eu.kanade.domain.manga.interactor.InsertFlatMetadata
|
||||
import eu.kanade.domain.manga.interactor.UpdateManga
|
||||
import eu.kanade.domain.manga.model.toMangaInfo
|
||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
import eu.kanade.tachiyomi.source.online.all.NHentai
|
||||
@@ -110,16 +108,7 @@ object DebugFunctions {
|
||||
}
|
||||
|
||||
fun addAllMangaInDatabaseToLibrary() {
|
||||
(handler as AndroidDatabaseHandler).rawQuery {
|
||||
it.execute(
|
||||
null,
|
||||
"""
|
||||
UPDATE ${MangaTable.TABLE}
|
||||
SET ${MangaTable.COL_FAVORITE} = 1
|
||||
""".trimIndent(),
|
||||
0,
|
||||
)
|
||||
}
|
||||
runBlocking { handler.await { ehQueries.addAllMangaInDatabaseToLibrary() } }
|
||||
}
|
||||
|
||||
fun countMangaInDatabaseInLibrary() = runBlocking { getFavorites.await().size }
|
||||
@@ -200,16 +189,8 @@ object DebugFunctions {
|
||||
fun cancelAllScheduledJobs() = app.jobScheduler.cancelAll()
|
||||
|
||||
private fun convertSources(from: Long, to: Long) {
|
||||
(handler as AndroidDatabaseHandler).rawQuery {
|
||||
it.execute(
|
||||
null,
|
||||
"""
|
||||
UPDATE ${MangaTable.TABLE}
|
||||
SET ${MangaTable.COL_SOURCE} = $to
|
||||
WHERE ${MangaTable.COL_SOURCE} = $from
|
||||
""".trimIndent(),
|
||||
0,
|
||||
)
|
||||
runBlocking {
|
||||
handler.await { ehQueries.migrateSource(to, from) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,60 +273,20 @@ object DebugFunctions {
|
||||
}*/
|
||||
|
||||
fun fixReaderViewerBackupBug() {
|
||||
(handler as AndroidDatabaseHandler).rawQuery {
|
||||
it.execute(
|
||||
null,
|
||||
"""
|
||||
UPDATE ${MangaTable.TABLE}
|
||||
SET ${MangaTable.COL_VIEWER} = 0
|
||||
WHERE ${MangaTable.COL_VIEWER} = -1
|
||||
""".trimIndent(),
|
||||
0,
|
||||
)
|
||||
}
|
||||
runBlocking { handler.await { ehQueries.fixReaderViewerBackupBug() } }
|
||||
}
|
||||
|
||||
fun resetReaderViewerForAllManga() {
|
||||
(handler as AndroidDatabaseHandler).rawQuery {
|
||||
it.execute(
|
||||
null,
|
||||
"""
|
||||
UPDATE ${MangaTable.TABLE}
|
||||
SET ${MangaTable.COL_VIEWER} = 0
|
||||
""".trimIndent(),
|
||||
0,
|
||||
)
|
||||
}
|
||||
runBlocking { handler.await { ehQueries.resetReaderViewerForAllManga() } }
|
||||
}
|
||||
|
||||
fun migrateAllNhentaiToOtherLang() {
|
||||
val sources = nHentaiSourceIds.toMutableList()
|
||||
.also { it.remove(NHentai.otherId) }
|
||||
.joinToString(separator = ",")
|
||||
val sources = nHentaiSourceIds - NHentai.otherId
|
||||
|
||||
(handler as AndroidDatabaseHandler).rawQuery {
|
||||
it.execute(
|
||||
null,
|
||||
"""
|
||||
UPDATE ${MangaTable.TABLE}
|
||||
SET ${MangaTable.COL_SOURCE} = ${NHentai.otherId}
|
||||
WHERE ${MangaTable.COL_FAVORITE} = 1 AND ${MangaTable.COL_SOURCE} in ($sources)
|
||||
""".trimIndent(),
|
||||
0,
|
||||
)
|
||||
}
|
||||
runBlocking { handler.await { ehQueries.migrateAllNhentaiToOtherLang(NHentai.otherId, sources) } }
|
||||
}
|
||||
|
||||
fun resetFilteredScanlatorsForAllManga() {
|
||||
(handler as AndroidDatabaseHandler).rawQuery {
|
||||
it.execute(
|
||||
null,
|
||||
"""
|
||||
UPDATE ${MangaTable.TABLE}
|
||||
SET ${MangaTable.COL_FILTERED_SCANLATORS} = NULL
|
||||
""".trimIndent(),
|
||||
0,
|
||||
)
|
||||
}
|
||||
runBlocking { handler.await { ehQueries.resetFilteredScanlatorsForAllManga() } }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,11 +12,13 @@ import androidx.work.WorkerParameters
|
||||
import com.elvishew.xlog.Logger
|
||||
import com.elvishew.xlog.XLog
|
||||
import eu.kanade.data.DatabaseHandler
|
||||
import eu.kanade.data.manga.mangaMapper
|
||||
import eu.kanade.domain.chapter.interactor.GetChapterByMangaId
|
||||
import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource
|
||||
import eu.kanade.domain.chapter.model.Chapter
|
||||
import eu.kanade.domain.chapter.model.toDbChapter
|
||||
import eu.kanade.domain.manga.interactor.GetExhFavoriteMangaWithMetadata
|
||||
import eu.kanade.domain.manga.interactor.GetFlatMetadataById
|
||||
import eu.kanade.domain.manga.interactor.InsertFlatMetadata
|
||||
import eu.kanade.domain.manga.interactor.UpdateManga
|
||||
import eu.kanade.domain.manga.model.Manga
|
||||
import eu.kanade.domain.manga.model.toDbManga
|
||||
@@ -33,11 +35,6 @@ import exh.debug.DebugToggles
|
||||
import exh.eh.EHentaiUpdateWorkerConstants.UPDATES_PER_ITERATION
|
||||
import exh.log.xLog
|
||||
import exh.metadata.metadata.EHentaiSearchMetadata
|
||||
import exh.metadata.metadata.base.awaitFlatMetadataForManga
|
||||
import exh.metadata.metadata.base.awaitInsertFlatMetadata
|
||||
import exh.source.EH_SOURCE_ID
|
||||
import exh.source.EXH_SOURCE_ID
|
||||
import exh.source.isEhBasedManga
|
||||
import exh.util.cancellable
|
||||
import kotlinx.coroutines.flow.asFlow
|
||||
import kotlinx.coroutines.flow.mapNotNull
|
||||
@@ -53,7 +50,6 @@ import kotlin.time.Duration.Companion.days
|
||||
|
||||
class EHentaiUpdateWorker(private val context: Context, workerParams: WorkerParameters) :
|
||||
CoroutineWorker(context, workerParams) {
|
||||
private val handler: DatabaseHandler by injectLazy()
|
||||
private val prefs: PreferencesHelper by injectLazy()
|
||||
private val sourceManager: SourceManager by injectLazy()
|
||||
private val updateHelper: EHentaiUpdateHelper by injectLazy()
|
||||
@@ -61,6 +57,9 @@ class EHentaiUpdateWorker(private val context: Context, workerParams: WorkerPara
|
||||
private val updateManga: UpdateManga by injectLazy()
|
||||
private val syncChaptersWithSource: SyncChaptersWithSource by injectLazy()
|
||||
private val getChapterByMangaId: GetChapterByMangaId by injectLazy()
|
||||
private val getFlatMetadataById: GetFlatMetadataById by injectLazy()
|
||||
private val insertFlatMetadata: InsertFlatMetadata by injectLazy()
|
||||
private val getExhFavoriteMangaWithMetadata: GetExhFavoriteMangaWithMetadata by injectLazy()
|
||||
|
||||
private val updateNotifier by lazy { LibraryUpdateNotifier(context) }
|
||||
|
||||
@@ -84,16 +83,12 @@ class EHentaiUpdateWorker(private val context: Context, workerParams: WorkerPara
|
||||
val startTime = System.currentTimeMillis()
|
||||
|
||||
logger.d("Finding manga with metadata...")
|
||||
val metadataManga = handler.awaitList { mangasQueries.getEhMangaWithMetadata(EH_SOURCE_ID, EXH_SOURCE_ID, mangaMapper) }
|
||||
val metadataManga = getExhFavoriteMangaWithMetadata.await()
|
||||
|
||||
logger.d("Filtering manga and raising metadata...")
|
||||
val curTime = System.currentTimeMillis()
|
||||
val allMeta = metadataManga.asFlow().cancellable().mapNotNull { manga ->
|
||||
if (!manga.isEhBasedManga()) {
|
||||
return@mapNotNull null
|
||||
}
|
||||
|
||||
val meta = handler.awaitFlatMetadataForManga(manga.id)
|
||||
val meta = getFlatMetadataById.await(manga.id)
|
||||
?: return@mapNotNull null
|
||||
|
||||
val raisedMeta = meta.raise<EHentaiSearchMetadata>()
|
||||
@@ -221,12 +216,12 @@ class EHentaiUpdateWorker(private val context: Context, workerParams: WorkerPara
|
||||
return new to getChapterByMangaId.await(manga.id)
|
||||
} catch (t: Throwable) {
|
||||
if (t is EHentai.GalleryNotFoundException) {
|
||||
val meta = handler.awaitFlatMetadataForManga(manga.id)?.raise<EHentaiSearchMetadata>()
|
||||
val meta = getFlatMetadataById.await(manga.id)?.raise<EHentaiSearchMetadata>()
|
||||
if (meta != null) {
|
||||
// Age dead galleries
|
||||
logger.d("Aged %s - notfound", manga.id)
|
||||
meta.aged = true
|
||||
handler.awaitInsertFlatMetadata(meta.flatten())
|
||||
insertFlatMetadata.await(meta)
|
||||
}
|
||||
throw GalleryNotUpdatedException(false, t)
|
||||
}
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
package exh.merged.sql.mappers
|
||||
|
||||
import android.database.Cursor
|
||||
import androidx.core.content.contentValuesOf
|
||||
import androidx.core.database.getLongOrNull
|
||||
import com.pushtorefresh.storio.sqlite.SQLiteTypeMapping
|
||||
import com.pushtorefresh.storio.sqlite.operations.delete.DefaultDeleteResolver
|
||||
import com.pushtorefresh.storio.sqlite.operations.get.DefaultGetResolver
|
||||
import com.pushtorefresh.storio.sqlite.operations.put.DefaultPutResolver
|
||||
import com.pushtorefresh.storio.sqlite.queries.DeleteQuery
|
||||
import com.pushtorefresh.storio.sqlite.queries.InsertQuery
|
||||
import com.pushtorefresh.storio.sqlite.queries.UpdateQuery
|
||||
import exh.merged.sql.models.MergedMangaReference
|
||||
import exh.merged.sql.tables.MergedTable.COL_CHAPTER_PRIORITY
|
||||
import exh.merged.sql.tables.MergedTable.COL_CHAPTER_SORT_MODE
|
||||
import exh.merged.sql.tables.MergedTable.COL_DOWNLOAD_CHAPTERS
|
||||
import exh.merged.sql.tables.MergedTable.COL_GET_CHAPTER_UPDATES
|
||||
import exh.merged.sql.tables.MergedTable.COL_ID
|
||||
import exh.merged.sql.tables.MergedTable.COL_IS_INFO_MANGA
|
||||
import exh.merged.sql.tables.MergedTable.COL_MANGA_ID
|
||||
import exh.merged.sql.tables.MergedTable.COL_MANGA_SOURCE
|
||||
import exh.merged.sql.tables.MergedTable.COL_MANGA_URL
|
||||
import exh.merged.sql.tables.MergedTable.COL_MERGE_ID
|
||||
import exh.merged.sql.tables.MergedTable.COL_MERGE_URL
|
||||
import exh.merged.sql.tables.MergedTable.TABLE
|
||||
|
||||
class MergedMangaTypeMapping : SQLiteTypeMapping<MergedMangaReference>(
|
||||
MergedMangaPutResolver(),
|
||||
MergedMangaGetResolver(),
|
||||
MergedMangaDeleteResolver(),
|
||||
)
|
||||
|
||||
class MergedMangaPutResolver : DefaultPutResolver<MergedMangaReference>() {
|
||||
|
||||
override fun mapToInsertQuery(obj: MergedMangaReference) = InsertQuery.builder()
|
||||
.table(TABLE)
|
||||
.build()
|
||||
|
||||
override fun mapToUpdateQuery(obj: MergedMangaReference) = UpdateQuery.builder()
|
||||
.table(TABLE)
|
||||
.where("$COL_ID = ?")
|
||||
.whereArgs(obj.id)
|
||||
.build()
|
||||
|
||||
override fun mapToContentValues(obj: MergedMangaReference) = contentValuesOf(
|
||||
COL_ID to obj.id,
|
||||
COL_IS_INFO_MANGA to obj.isInfoManga,
|
||||
COL_GET_CHAPTER_UPDATES to obj.getChapterUpdates,
|
||||
COL_CHAPTER_SORT_MODE to obj.chapterSortMode,
|
||||
COL_CHAPTER_PRIORITY to obj.chapterPriority,
|
||||
COL_DOWNLOAD_CHAPTERS to obj.downloadChapters,
|
||||
COL_MERGE_ID to obj.mergeId,
|
||||
COL_MERGE_URL to obj.mergeUrl,
|
||||
COL_MANGA_ID to obj.mangaId,
|
||||
COL_MANGA_URL to obj.mangaUrl,
|
||||
COL_MANGA_SOURCE to obj.mangaSourceId,
|
||||
)
|
||||
}
|
||||
|
||||
class MergedMangaGetResolver : DefaultGetResolver<MergedMangaReference>() {
|
||||
|
||||
override fun mapFromCursor(cursor: Cursor): MergedMangaReference = MergedMangaReference(
|
||||
id = cursor.getLong(cursor.getColumnIndexOrThrow(COL_ID)),
|
||||
isInfoManga = cursor.getInt(cursor.getColumnIndexOrThrow(COL_IS_INFO_MANGA)) == 1,
|
||||
getChapterUpdates = cursor.getInt(cursor.getColumnIndexOrThrow(COL_GET_CHAPTER_UPDATES)) == 1,
|
||||
chapterSortMode = cursor.getInt(cursor.getColumnIndexOrThrow(COL_CHAPTER_SORT_MODE)),
|
||||
chapterPriority = cursor.getInt(cursor.getColumnIndexOrThrow(COL_CHAPTER_PRIORITY)),
|
||||
downloadChapters = cursor.getInt(cursor.getColumnIndexOrThrow(COL_DOWNLOAD_CHAPTERS)) == 1,
|
||||
mergeId = cursor.getLong(cursor.getColumnIndexOrThrow(COL_MERGE_ID)),
|
||||
mergeUrl = cursor.getString(cursor.getColumnIndexOrThrow(COL_MERGE_URL)),
|
||||
mangaId = cursor.getLongOrNull(cursor.getColumnIndexOrThrow(COL_MANGA_ID)),
|
||||
mangaUrl = cursor.getString(cursor.getColumnIndexOrThrow(COL_MANGA_URL)),
|
||||
mangaSourceId = cursor.getLong(cursor.getColumnIndexOrThrow(COL_MANGA_SOURCE)),
|
||||
)
|
||||
}
|
||||
|
||||
class MergedMangaDeleteResolver : DefaultDeleteResolver<MergedMangaReference>() {
|
||||
|
||||
override fun mapToDeleteQuery(obj: MergedMangaReference) = DeleteQuery.builder()
|
||||
.table(TABLE)
|
||||
.where("$COL_ID = ?")
|
||||
.whereArgs(obj.id)
|
||||
.build()
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
package exh.merged.sql.queries
|
||||
|
||||
import com.pushtorefresh.storio.sqlite.queries.DeleteQuery
|
||||
import com.pushtorefresh.storio.sqlite.queries.Query
|
||||
import com.pushtorefresh.storio.sqlite.queries.RawQuery
|
||||
import eu.kanade.tachiyomi.data.database.DbProvider
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.database.queries.getMergedMangaForDownloadingQuery
|
||||
import eu.kanade.tachiyomi.data.database.queries.getMergedMangaQuery
|
||||
import exh.merged.sql.models.MergedMangaReference
|
||||
import exh.merged.sql.resolvers.MergeMangaSettingsPutResolver
|
||||
import exh.merged.sql.resolvers.MergedMangaIdPutResolver
|
||||
import exh.merged.sql.resolvers.MergedMangaSettingsPutResolver
|
||||
import exh.merged.sql.tables.MergedTable
|
||||
|
||||
interface MergedQueries : DbProvider {
|
||||
fun getMergedMangaReferences(mergedMangaId: Long) = db.get()
|
||||
.listOfObjects(MergedMangaReference::class.java)
|
||||
.withQuery(
|
||||
Query.builder()
|
||||
.table(MergedTable.TABLE)
|
||||
.where("${MergedTable.COL_MERGE_ID} = ?")
|
||||
.whereArgs(mergedMangaId)
|
||||
.build(),
|
||||
)
|
||||
.prepare()
|
||||
|
||||
fun deleteMangaForMergedManga(mergedMangaId: Long) = db.delete()
|
||||
.byQuery(
|
||||
DeleteQuery.builder()
|
||||
.table(MergedTable.TABLE)
|
||||
.where("${MergedTable.COL_MERGE_ID} = ?")
|
||||
.whereArgs(mergedMangaId)
|
||||
.build(),
|
||||
)
|
||||
.prepare()
|
||||
|
||||
fun getMergedMangas(mergedMangaId: Long) = db.get()
|
||||
.listOfObjects(Manga::class.java)
|
||||
.withQuery(
|
||||
RawQuery.builder()
|
||||
.query(getMergedMangaQuery())
|
||||
.args(mergedMangaId)
|
||||
.build(),
|
||||
)
|
||||
.prepare()
|
||||
|
||||
fun getMergedMangasForDownloading(mergedMangaId: Long) = db.get()
|
||||
.listOfObjects(Manga::class.java)
|
||||
.withQuery(
|
||||
RawQuery.builder()
|
||||
.query(getMergedMangaForDownloadingQuery())
|
||||
.args(mergedMangaId)
|
||||
.build(),
|
||||
)
|
||||
.prepare()
|
||||
|
||||
fun insertMergedManga(mergedManga: MergedMangaReference) = db.put().`object`(mergedManga).prepare()
|
||||
|
||||
fun insertNewMergedMangaId(mergedManga: MergedMangaReference) = db.put().`object`(mergedManga).withPutResolver(MergedMangaIdPutResolver()).prepare()
|
||||
|
||||
fun insertMergedMangas(mergedManga: List<MergedMangaReference>) = db.put().objects(mergedManga).prepare()
|
||||
|
||||
fun updateMergedMangaSettings(mergedManga: List<MergedMangaReference>) = db.put().objects(mergedManga).withPutResolver(MergedMangaSettingsPutResolver()).prepare()
|
||||
|
||||
fun updateMergeMangaSettings(mergeManga: MergedMangaReference) = db.put().`object`(mergeManga).withPutResolver(MergeMangaSettingsPutResolver()).prepare()
|
||||
|
||||
fun deleteMergedManga(mergedManga: MergedMangaReference) = db.delete().`object`(mergedManga).prepare()
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package exh.merged.sql.resolvers
|
||||
|
||||
import androidx.core.content.contentValuesOf
|
||||
import com.pushtorefresh.storio.sqlite.StorIOSQLite
|
||||
import com.pushtorefresh.storio.sqlite.operations.put.PutResolver
|
||||
import com.pushtorefresh.storio.sqlite.operations.put.PutResult
|
||||
import com.pushtorefresh.storio.sqlite.queries.UpdateQuery
|
||||
import eu.kanade.tachiyomi.data.database.inTransactionReturn
|
||||
import exh.merged.sql.models.MergedMangaReference
|
||||
import exh.merged.sql.tables.MergedTable
|
||||
|
||||
class MergeMangaSettingsPutResolver(val reset: Boolean = false) : PutResolver<MergedMangaReference>() {
|
||||
|
||||
override fun performPut(db: StorIOSQLite, mergedMangaReference: MergedMangaReference) = db.inTransactionReturn {
|
||||
val updateQuery = mapToUpdateQuery(mergedMangaReference)
|
||||
val contentValues = mapToContentValues(mergedMangaReference)
|
||||
|
||||
val numberOfRowsUpdated = db.lowLevel().update(updateQuery, contentValues)
|
||||
PutResult.newUpdateResult(numberOfRowsUpdated, updateQuery.table())
|
||||
}
|
||||
|
||||
fun mapToUpdateQuery(mergedMangaReference: MergedMangaReference) = UpdateQuery.builder()
|
||||
.table(MergedTable.TABLE)
|
||||
.where("${MergedTable.COL_ID} = ?")
|
||||
.whereArgs(mergedMangaReference.id)
|
||||
.build()
|
||||
|
||||
fun mapToContentValues(mergedMangaReference: MergedMangaReference) = contentValuesOf(
|
||||
MergedTable.COL_CHAPTER_SORT_MODE to mergedMangaReference.chapterSortMode,
|
||||
)
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package exh.merged.sql.resolvers
|
||||
|
||||
import androidx.core.content.contentValuesOf
|
||||
import com.pushtorefresh.storio.sqlite.StorIOSQLite
|
||||
import com.pushtorefresh.storio.sqlite.operations.put.PutResolver
|
||||
import com.pushtorefresh.storio.sqlite.operations.put.PutResult
|
||||
import com.pushtorefresh.storio.sqlite.queries.UpdateQuery
|
||||
import eu.kanade.tachiyomi.data.database.inTransactionReturn
|
||||
import exh.merged.sql.models.MergedMangaReference
|
||||
import exh.merged.sql.tables.MergedTable
|
||||
|
||||
class MergedMangaIdPutResolver : PutResolver<MergedMangaReference>() {
|
||||
|
||||
override fun performPut(db: StorIOSQLite, mergedMangaReference: MergedMangaReference) = db.inTransactionReturn {
|
||||
val updateQuery = mapToUpdateQuery(mergedMangaReference)
|
||||
val contentValues = mapToContentValues(mergedMangaReference)
|
||||
|
||||
val numberOfRowsUpdated = db.lowLevel().update(updateQuery, contentValues)
|
||||
PutResult.newUpdateResult(numberOfRowsUpdated, updateQuery.table())
|
||||
}
|
||||
|
||||
fun mapToUpdateQuery(mergedMangaReference: MergedMangaReference) = UpdateQuery.builder()
|
||||
.table(MergedTable.TABLE)
|
||||
.where("${MergedTable.COL_ID} = ?")
|
||||
.whereArgs(mergedMangaReference.id)
|
||||
.build()
|
||||
|
||||
fun mapToContentValues(mergedMangaReference: MergedMangaReference) = contentValuesOf(
|
||||
MergedTable.COL_MANGA_ID to mergedMangaReference.mangaId,
|
||||
)
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package exh.merged.sql.resolvers
|
||||
|
||||
import androidx.core.content.contentValuesOf
|
||||
import com.pushtorefresh.storio.sqlite.StorIOSQLite
|
||||
import com.pushtorefresh.storio.sqlite.operations.put.PutResolver
|
||||
import com.pushtorefresh.storio.sqlite.operations.put.PutResult
|
||||
import com.pushtorefresh.storio.sqlite.queries.UpdateQuery
|
||||
import eu.kanade.tachiyomi.data.database.inTransactionReturn
|
||||
import exh.merged.sql.models.MergedMangaReference
|
||||
import exh.merged.sql.tables.MergedTable
|
||||
|
||||
class MergedMangaSettingsPutResolver(val reset: Boolean = false) : PutResolver<MergedMangaReference>() {
|
||||
|
||||
override fun performPut(db: StorIOSQLite, mergedMangaReference: MergedMangaReference) = db.inTransactionReturn {
|
||||
val updateQuery = mapToUpdateQuery(mergedMangaReference)
|
||||
val contentValues = mapToContentValues(mergedMangaReference)
|
||||
|
||||
val numberOfRowsUpdated = db.lowLevel().update(updateQuery, contentValues)
|
||||
PutResult.newUpdateResult(numberOfRowsUpdated, updateQuery.table())
|
||||
}
|
||||
|
||||
fun mapToUpdateQuery(mergedMangaReference: MergedMangaReference) = UpdateQuery.builder()
|
||||
.table(MergedTable.TABLE)
|
||||
.where("${MergedTable.COL_ID} = ?")
|
||||
.whereArgs(mergedMangaReference.id)
|
||||
.build()
|
||||
|
||||
fun mapToContentValues(mergedMangaReference: MergedMangaReference) = contentValuesOf(
|
||||
MergedTable.COL_GET_CHAPTER_UPDATES to mergedMangaReference.getChapterUpdates,
|
||||
MergedTable.COL_DOWNLOAD_CHAPTERS to mergedMangaReference.downloadChapters,
|
||||
MergedTable.COL_IS_INFO_MANGA to mergedMangaReference.isInfoManga,
|
||||
MergedTable.COL_CHAPTER_PRIORITY to mergedMangaReference.chapterPriority,
|
||||
)
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package exh.merged.sql.tables
|
||||
|
||||
object MergedTable {
|
||||
|
||||
const val TABLE = "merged"
|
||||
|
||||
const val COL_ID = "_id"
|
||||
|
||||
const val COL_IS_INFO_MANGA = "info_manga"
|
||||
|
||||
const val COL_GET_CHAPTER_UPDATES = "get_chapter_updates"
|
||||
|
||||
const val COL_CHAPTER_SORT_MODE = "chapter_sort_mode"
|
||||
|
||||
const val COL_CHAPTER_PRIORITY = "chapter_priority"
|
||||
|
||||
const val COL_DOWNLOAD_CHAPTERS = "download_chapters"
|
||||
|
||||
const val COL_MERGE_ID = "merge_id"
|
||||
|
||||
const val COL_MERGE_URL = "merge_url"
|
||||
|
||||
const val COL_MANGA_ID = "manga_id"
|
||||
|
||||
const val COL_MANGA_URL = "manga_url"
|
||||
|
||||
const val COL_MANGA_SOURCE = "manga_source"
|
||||
}
|
||||
@@ -1,9 +1,5 @@
|
||||
package exh.metadata.metadata.base
|
||||
|
||||
import eu.kanade.data.DatabaseHandler
|
||||
import eu.kanade.data.exh.searchMetadataMapper
|
||||
import eu.kanade.data.exh.searchTagMapper
|
||||
import eu.kanade.data.exh.searchTitleMapper
|
||||
import exh.metadata.sql.models.SearchMetadata
|
||||
import exh.metadata.sql.models.SearchTag
|
||||
import exh.metadata.sql.models.SearchTitle
|
||||
@@ -27,35 +23,3 @@ data class FlatMetadata(
|
||||
fillBaseFields(this@FlatMetadata)
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated("Replace with GetFlatMetadataById")
|
||||
suspend fun DatabaseHandler.awaitFlatMetadataForManga(mangaId: Long): FlatMetadata? {
|
||||
return await {
|
||||
val meta = search_metadataQueries.selectByMangaId(mangaId, searchMetadataMapper).executeAsOneOrNull()
|
||||
if (meta != null) {
|
||||
val tags = search_tagsQueries.selectByMangaId(mangaId, searchTagMapper).executeAsList()
|
||||
val titles = search_titlesQueries.selectByMangaId(mangaId, searchTitleMapper).executeAsList()
|
||||
|
||||
FlatMetadata(meta, tags, titles)
|
||||
} else null
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated("Replace with InsertFlatMetadata")
|
||||
suspend fun DatabaseHandler.awaitInsertFlatMetadata(flatMetadata: FlatMetadata) {
|
||||
require(flatMetadata.metadata.mangaId != -1L)
|
||||
|
||||
await(true) {
|
||||
flatMetadata.metadata.run {
|
||||
search_metadataQueries.upsert(mangaId, uploader, extra, indexedExtra, extraVersion)
|
||||
}
|
||||
search_tagsQueries.deleteByManga(flatMetadata.metadata.mangaId)
|
||||
flatMetadata.tags.forEach {
|
||||
search_tagsQueries.insert(it.mangaId, it.namespace, it.name, it.type)
|
||||
}
|
||||
search_titlesQueries.deleteByManga(flatMetadata.metadata.mangaId)
|
||||
flatMetadata.titles.forEach {
|
||||
search_titlesQueries.insert(it.mangaId, it.title, it.type)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
package exh.savedsearches.mappers
|
||||
|
||||
import android.database.Cursor
|
||||
import androidx.core.content.contentValuesOf
|
||||
import androidx.core.database.getLongOrNull
|
||||
import com.pushtorefresh.storio.sqlite.SQLiteTypeMapping
|
||||
import com.pushtorefresh.storio.sqlite.operations.delete.DefaultDeleteResolver
|
||||
import com.pushtorefresh.storio.sqlite.operations.get.DefaultGetResolver
|
||||
import com.pushtorefresh.storio.sqlite.operations.put.DefaultPutResolver
|
||||
import com.pushtorefresh.storio.sqlite.queries.DeleteQuery
|
||||
import com.pushtorefresh.storio.sqlite.queries.InsertQuery
|
||||
import com.pushtorefresh.storio.sqlite.queries.UpdateQuery
|
||||
import exh.savedsearches.mappers.FeedSavedSearchTable.COL_GLOBAL
|
||||
import exh.savedsearches.mappers.FeedSavedSearchTable.COL_ID
|
||||
import exh.savedsearches.mappers.FeedSavedSearchTable.COL_SAVED_SEARCH_ID
|
||||
import exh.savedsearches.mappers.FeedSavedSearchTable.COL_SOURCE
|
||||
import exh.savedsearches.mappers.FeedSavedSearchTable.TABLE
|
||||
import exh.savedsearches.models.FeedSavedSearch
|
||||
|
||||
private object FeedSavedSearchTable {
|
||||
|
||||
const val TABLE = "feed_saved_search"
|
||||
|
||||
const val COL_ID = "_id"
|
||||
|
||||
const val COL_SOURCE = "source"
|
||||
|
||||
const val COL_SAVED_SEARCH_ID = "saved_search"
|
||||
|
||||
const val COL_GLOBAL = "global"
|
||||
}
|
||||
|
||||
class FeedSavedSearchTypeMapping : SQLiteTypeMapping<FeedSavedSearch>(
|
||||
FeedSavedSearchPutResolver(),
|
||||
FeedSavedSearchGetResolver(),
|
||||
FeedSavedSearchDeleteResolver(),
|
||||
)
|
||||
|
||||
class FeedSavedSearchPutResolver : DefaultPutResolver<FeedSavedSearch>() {
|
||||
|
||||
override fun mapToInsertQuery(obj: FeedSavedSearch) = InsertQuery.builder()
|
||||
.table(TABLE)
|
||||
.build()
|
||||
|
||||
override fun mapToUpdateQuery(obj: FeedSavedSearch) = UpdateQuery.builder()
|
||||
.table(TABLE)
|
||||
.where("$COL_ID = ?")
|
||||
.whereArgs(obj.id)
|
||||
.build()
|
||||
|
||||
override fun mapToContentValues(obj: FeedSavedSearch) = contentValuesOf(
|
||||
COL_ID to obj.id,
|
||||
COL_SOURCE to obj.source,
|
||||
COL_SAVED_SEARCH_ID to obj.savedSearch,
|
||||
COL_GLOBAL to obj.global,
|
||||
)
|
||||
}
|
||||
|
||||
class FeedSavedSearchGetResolver : DefaultGetResolver<FeedSavedSearch>() {
|
||||
|
||||
override fun mapFromCursor(cursor: Cursor): FeedSavedSearch = FeedSavedSearch(
|
||||
id = cursor.getLong(cursor.getColumnIndexOrThrow(COL_ID)),
|
||||
source = cursor.getLong(cursor.getColumnIndexOrThrow(COL_SOURCE)),
|
||||
savedSearch = cursor.getLongOrNull(cursor.getColumnIndexOrThrow(COL_SAVED_SEARCH_ID)),
|
||||
global = cursor.getInt(cursor.getColumnIndexOrThrow(COL_GLOBAL)) == 1,
|
||||
)
|
||||
}
|
||||
|
||||
class FeedSavedSearchDeleteResolver : DefaultDeleteResolver<FeedSavedSearch>() {
|
||||
|
||||
override fun mapToDeleteQuery(obj: FeedSavedSearch) = DeleteQuery.builder()
|
||||
.table(TABLE)
|
||||
.where("$COL_ID = ?")
|
||||
.whereArgs(obj.id)
|
||||
.build()
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
package exh.savedsearches.mappers
|
||||
|
||||
import android.database.Cursor
|
||||
import androidx.core.content.contentValuesOf
|
||||
import androidx.core.database.getStringOrNull
|
||||
import com.pushtorefresh.storio.sqlite.SQLiteTypeMapping
|
||||
import com.pushtorefresh.storio.sqlite.operations.delete.DefaultDeleteResolver
|
||||
import com.pushtorefresh.storio.sqlite.operations.get.DefaultGetResolver
|
||||
import com.pushtorefresh.storio.sqlite.operations.put.DefaultPutResolver
|
||||
import com.pushtorefresh.storio.sqlite.queries.DeleteQuery
|
||||
import com.pushtorefresh.storio.sqlite.queries.InsertQuery
|
||||
import com.pushtorefresh.storio.sqlite.queries.UpdateQuery
|
||||
import exh.savedsearches.mappers.SavedSearchTable.COL_FILTERS_JSON
|
||||
import exh.savedsearches.mappers.SavedSearchTable.COL_ID
|
||||
import exh.savedsearches.mappers.SavedSearchTable.COL_NAME
|
||||
import exh.savedsearches.mappers.SavedSearchTable.COL_QUERY
|
||||
import exh.savedsearches.mappers.SavedSearchTable.COL_SOURCE
|
||||
import exh.savedsearches.mappers.SavedSearchTable.TABLE
|
||||
import exh.savedsearches.models.SavedSearch
|
||||
|
||||
private object SavedSearchTable {
|
||||
|
||||
const val TABLE = "saved_search"
|
||||
|
||||
const val COL_ID = "_id"
|
||||
|
||||
const val COL_SOURCE = "source"
|
||||
|
||||
const val COL_NAME = "name"
|
||||
|
||||
const val COL_QUERY = "query"
|
||||
|
||||
const val COL_FILTERS_JSON = "filters_json"
|
||||
}
|
||||
|
||||
class SavedSearchTypeMapping : SQLiteTypeMapping<SavedSearch>(
|
||||
SavedSearchPutResolver(),
|
||||
SavedSearchGetResolver(),
|
||||
SavedSearchDeleteResolver(),
|
||||
)
|
||||
|
||||
class SavedSearchPutResolver : DefaultPutResolver<SavedSearch>() {
|
||||
|
||||
override fun mapToInsertQuery(obj: SavedSearch) = InsertQuery.builder()
|
||||
.table(TABLE)
|
||||
.build()
|
||||
|
||||
override fun mapToUpdateQuery(obj: SavedSearch) = UpdateQuery.builder()
|
||||
.table(TABLE)
|
||||
.where("$COL_ID = ?")
|
||||
.whereArgs(obj.id)
|
||||
.build()
|
||||
|
||||
override fun mapToContentValues(obj: SavedSearch) = contentValuesOf(
|
||||
COL_ID to obj.id,
|
||||
COL_SOURCE to obj.source,
|
||||
COL_NAME to obj.name,
|
||||
COL_QUERY to obj.query,
|
||||
COL_FILTERS_JSON to obj.filtersJson,
|
||||
)
|
||||
}
|
||||
|
||||
class SavedSearchGetResolver : DefaultGetResolver<SavedSearch>() {
|
||||
|
||||
override fun mapFromCursor(cursor: Cursor): SavedSearch = SavedSearch(
|
||||
id = cursor.getLong(cursor.getColumnIndexOrThrow(COL_ID)),
|
||||
source = cursor.getLong(cursor.getColumnIndexOrThrow(COL_SOURCE)),
|
||||
name = cursor.getString(cursor.getColumnIndexOrThrow(COL_NAME)),
|
||||
query = cursor.getStringOrNull(cursor.getColumnIndexOrThrow(COL_QUERY)),
|
||||
filtersJson = cursor.getStringOrNull(cursor.getColumnIndexOrThrow(COL_FILTERS_JSON)),
|
||||
)
|
||||
}
|
||||
|
||||
class SavedSearchDeleteResolver : DefaultDeleteResolver<SavedSearch>() {
|
||||
|
||||
override fun mapToDeleteQuery(obj: SavedSearch) = DeleteQuery.builder()
|
||||
.table(TABLE)
|
||||
.where("$COL_ID = ?")
|
||||
.whereArgs(obj.id)
|
||||
.build()
|
||||
}
|
||||
@@ -1,13 +1,14 @@
|
||||
package exh.smartsearch
|
||||
|
||||
import eu.kanade.data.DatabaseHandler
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
import eu.kanade.domain.manga.interactor.GetManga
|
||||
import eu.kanade.domain.manga.interactor.InsertManga
|
||||
import eu.kanade.domain.manga.model.toDbManga
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.database.models.toDomainManga
|
||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.util.lang.awaitSingle
|
||||
import exh.util.executeOnIO
|
||||
import info.debatty.java.stringsimilarity.NormalizedLevenshtein
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.async
|
||||
@@ -18,8 +19,8 @@ import java.util.Locale
|
||||
class SmartSearchEngine(
|
||||
private val extraSearchParams: String? = null,
|
||||
) {
|
||||
private val db: DatabaseHelper by injectLazy()
|
||||
private val handler: DatabaseHandler by injectLazy()
|
||||
private val getManga: GetManga by injectLazy()
|
||||
private val insertManga: InsertManga by injectLazy()
|
||||
|
||||
private val normalizedLevenshtein = NormalizedLevenshtein()
|
||||
|
||||
@@ -172,15 +173,22 @@ class SmartSearchEngine(
|
||||
* @return a manga from the database.
|
||||
*/
|
||||
suspend fun networkToLocalManga(sManga: SManga, sourceId: Long): Manga {
|
||||
var localManga = db.getManga(sManga.url, sourceId).executeOnIO()
|
||||
var localManga = getManga.await(sManga.url, sourceId)
|
||||
if (localManga == null) {
|
||||
val newManga = Manga.create(sManga.url, sManga.title, sourceId)
|
||||
newManga.copyFrom(sManga)
|
||||
val result = db.insertManga(newManga).executeOnIO()
|
||||
newManga.id = result.insertedId()
|
||||
localManga = newManga
|
||||
newManga.id = -1
|
||||
val result = run {
|
||||
val id = insertManga.await(newManga.toDomainManga()!!)
|
||||
getManga.await(id!!)
|
||||
}
|
||||
localManga = result
|
||||
} else if (!localManga.favorite) {
|
||||
// if the manga isn't a favorite, set its display title from source
|
||||
// if it later becomes a favorite, updated title will go to db
|
||||
localManga = localManga.copy(ogTitle = sManga.title)
|
||||
}
|
||||
return localManga
|
||||
return localManga?.toDbManga()!!
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
package exh.ui.metadata
|
||||
|
||||
import android.os.Bundle
|
||||
import eu.kanade.data.DatabaseHandler
|
||||
import eu.kanade.domain.manga.interactor.GetFlatMetadataById
|
||||
import eu.kanade.domain.manga.model.Manga
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.online.MetadataSource
|
||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||
import exh.metadata.metadata.base.awaitFlatMetadataForManga
|
||||
import exh.source.getMainSource
|
||||
import exh.ui.base.CoroutinePresenter
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
@@ -19,7 +18,7 @@ class MetadataViewPresenter(
|
||||
val manga: Manga,
|
||||
val source: Source,
|
||||
val preferences: PreferencesHelper = Injekt.get(),
|
||||
private val db: DatabaseHandler = Injekt.get(),
|
||||
private val getFlatMetadataById: GetFlatMetadataById = Injekt.get(),
|
||||
) : CoroutinePresenter<MetadataViewController>() {
|
||||
|
||||
val meta = MutableStateFlow<RaisedSearchMetadata?>(null)
|
||||
@@ -28,7 +27,7 @@ class MetadataViewPresenter(
|
||||
super.onCreate(savedState)
|
||||
|
||||
launchIO {
|
||||
val flatMetadata = db.awaitFlatMetadataForManga(manga.id) ?: return@launchIO
|
||||
val flatMetadata = getFlatMetadataById.await(manga.id) ?: return@launchIO
|
||||
val mainSource = source.getMainSource<MetadataSource<*, *>>()
|
||||
if (mainSource != null) {
|
||||
meta.value = flatMetadata.raise(mainSource.metaClass)
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
package exh.util
|
||||
|
||||
import android.database.Cursor
|
||||
import com.pushtorefresh.storio.operations.PreparedOperation
|
||||
import com.pushtorefresh.storio.sqlite.operations.get.PreparedGetCursor
|
||||
import com.pushtorefresh.storio.sqlite.operations.get.PreparedGetListOfObjects
|
||||
import com.pushtorefresh.storio.sqlite.operations.get.PreparedGetObject
|
||||
import com.pushtorefresh.storio.sqlite.operations.put.PreparedPutCollectionOfObjects
|
||||
import com.pushtorefresh.storio.sqlite.operations.put.PreparedPutObject
|
||||
import com.pushtorefresh.storio.sqlite.operations.put.PutResult
|
||||
import com.pushtorefresh.storio.sqlite.operations.put.PutResults
|
||||
import eu.kanade.tachiyomi.util.lang.withIOContext
|
||||
|
||||
suspend fun <T> PreparedGetListOfObjects<T>.executeOnIO(): List<T> = withIOContext { executeAsBlocking() }
|
||||
|
||||
suspend fun <T> PreparedGetObject<T>.executeOnIO(): T? = withIOContext { executeAsBlocking() }
|
||||
|
||||
suspend fun <T> PreparedPutObject<T>.executeOnIO(): PutResult = withIOContext { executeAsBlocking() }
|
||||
|
||||
suspend fun <T> PreparedPutCollectionOfObjects<T>.executeOnIO(): PutResults<T> = withIOContext { executeAsBlocking() }
|
||||
|
||||
suspend fun PreparedGetCursor.executeOnIO(): Cursor = withIOContext { executeAsBlocking() }
|
||||
|
||||
suspend fun <T> PreparedOperation<T>.executeOnIO(): T? = withIOContext { executeAsBlocking() }
|
||||
Reference in New Issue
Block a user