Use SQLDelight for more SY specific things
This commit is contained in:
@@ -5,19 +5,18 @@ package exh
|
||||
import android.content.Context
|
||||
import androidx.core.content.edit
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.pushtorefresh.storio.sqlite.queries.DeleteQuery
|
||||
import com.pushtorefresh.storio.sqlite.queries.Query
|
||||
import com.pushtorefresh.storio.sqlite.queries.RawQuery
|
||||
import eu.kanade.data.DatabaseHandler
|
||||
import eu.kanade.domain.manga.interactor.GetManga
|
||||
import eu.kanade.domain.manga.interactor.GetMangaBySource
|
||||
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.resolvers.MangaUrlPutResolver
|
||||
import eu.kanade.tachiyomi.data.database.tables.ChapterTable
|
||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable
|
||||
import eu.kanade.tachiyomi.data.database.tables.TrackTable
|
||||
import eu.kanade.tachiyomi.data.library.LibraryUpdateJob
|
||||
import eu.kanade.tachiyomi.data.preference.MANGA_NON_COMPLETED
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceKeys
|
||||
@@ -29,7 +28,6 @@ import eu.kanade.tachiyomi.extension.ExtensionUpdateJob
|
||||
import eu.kanade.tachiyomi.network.PREF_DOH_CLOUDFLARE
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.source.online.all.Hitomi
|
||||
import eu.kanade.tachiyomi.source.online.all.NHentai
|
||||
import eu.kanade.tachiyomi.ui.library.LibrarySort
|
||||
@@ -68,11 +66,15 @@ import uy.kohesive.injekt.injectLazy
|
||||
import java.io.File
|
||||
import java.net.URI
|
||||
import java.net.URISyntaxException
|
||||
import eu.kanade.domain.manga.model.Manga as DomainManga
|
||||
|
||||
object EXHMigrations {
|
||||
private val db: DatabaseHelper by injectLazy()
|
||||
private val database: DatabaseHandler 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()
|
||||
|
||||
/**
|
||||
* Performs a migration when the application is updated.
|
||||
@@ -102,68 +104,41 @@ object EXHMigrations {
|
||||
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
if (oldVersion under 4) {
|
||||
db.inTransaction {
|
||||
updateSourceId(HBROWSE_SOURCE_ID, 6912)
|
||||
// Migrate BHrowse URLs
|
||||
val hBrowseManga = db.db.get()
|
||||
.listOfObjects(Manga::class.java)
|
||||
.withQuery(
|
||||
Query.builder()
|
||||
.table(MangaTable.TABLE)
|
||||
.where("${MangaTable.COL_SOURCE} = $HBROWSE_SOURCE_ID")
|
||||
.build(),
|
||||
)
|
||||
.prepare()
|
||||
.executeAsBlocking()
|
||||
hBrowseManga.forEach {
|
||||
it.url = it.url + "/c00001/"
|
||||
}
|
||||
updateSourceId(HBROWSE_SOURCE_ID, 6912)
|
||||
// Migrate BHrowse URLs
|
||||
val hBrowseManga = runBlocking { getMangaBySource.await(HBROWSE_SOURCE_ID) }
|
||||
val mangaUpdates = hBrowseManga.map {
|
||||
MangaUpdate(it.id, url = it.url + "/c00001/")
|
||||
}
|
||||
|
||||
db.db.put()
|
||||
.objects(hBrowseManga)
|
||||
// Extremely slow without the resolver :/
|
||||
.withPutResolver(MangaUrlPutResolver())
|
||||
.prepare()
|
||||
.executeAsBlocking()
|
||||
runBlocking {
|
||||
updateManga.awaitAll(mangaUpdates)
|
||||
}
|
||||
}
|
||||
if (oldVersion under 5) {
|
||||
db.inTransaction {
|
||||
// Migrate Hitomi source IDs
|
||||
updateSourceId(Hitomi.otherId, 6910)
|
||||
}
|
||||
// Migrate Hitomi source IDs
|
||||
updateSourceId(Hitomi.otherId, 6910)
|
||||
}
|
||||
if (oldVersion under 6) {
|
||||
db.inTransaction {
|
||||
updateSourceId(PERV_EDEN_EN_SOURCE_ID, 6905)
|
||||
updateSourceId(PERV_EDEN_IT_SOURCE_ID, 6906)
|
||||
updateSourceId(NHentai.otherId, 6907)
|
||||
}
|
||||
updateSourceId(PERV_EDEN_EN_SOURCE_ID, 6905)
|
||||
updateSourceId(PERV_EDEN_IT_SOURCE_ID, 6906)
|
||||
updateSourceId(NHentai.otherId, 6907)
|
||||
}
|
||||
if (oldVersion under 7) {
|
||||
db.inTransaction {
|
||||
val mergedMangas = db.db.get()
|
||||
.listOfObjects(Manga::class.java)
|
||||
.withQuery(
|
||||
Query.builder()
|
||||
.table(MangaTable.TABLE)
|
||||
.where("${MangaTable.COL_SOURCE} = $MERGED_SOURCE_ID")
|
||||
.build(),
|
||||
)
|
||||
.prepare()
|
||||
.executeAsBlocking()
|
||||
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<Manga>()
|
||||
val mangaToUpdate = mutableListOf<MangaUpdate>()
|
||||
val mergedMangaReferences = mutableListOf<MergedMangaReference>()
|
||||
mangaConfigs.onEach { mergedManga ->
|
||||
mergedManga.second.children.firstOrNull()?.url?.let {
|
||||
if (db.getManga(it, MERGED_SOURCE_ID).executeAsBlocking() != null) return@onEach
|
||||
mergedManga.first.url = it
|
||||
}
|
||||
mangaToUpdate += mergedManga.first
|
||||
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,
|
||||
@@ -171,9 +146,9 @@ object EXHMigrations {
|
||||
chapterSortMode = 0,
|
||||
chapterPriority = 0,
|
||||
downloadChapters = false,
|
||||
mergeId = mergedManga.first.id!!,
|
||||
mergeId = mergedManga.first.id,
|
||||
mergeUrl = mergedManga.first.url,
|
||||
mangaId = mergedManga.first.id!!,
|
||||
mangaId = mergedManga.first.id,
|
||||
mangaUrl = mergedManga.first.url,
|
||||
mangaSourceId = MERGED_SOURCE_ID,
|
||||
)
|
||||
@@ -186,7 +161,7 @@ object EXHMigrations {
|
||||
chapterSortMode = 0,
|
||||
chapterPriority = 0,
|
||||
downloadChapters = true,
|
||||
mergeId = mergedManga.first.id!!,
|
||||
mergeId = mergedManga.first.id,
|
||||
mergeUrl = mergedManga.first.url,
|
||||
mangaId = load.manga.id!!,
|
||||
mangaUrl = load.manga.url,
|
||||
@@ -194,12 +169,9 @@ object EXHMigrations {
|
||||
)
|
||||
}
|
||||
}
|
||||
db.db.put()
|
||||
.objects(mangaToUpdate)
|
||||
// Extremely slow without the resolver :/
|
||||
.withPutResolver(MangaUrlPutResolver())
|
||||
.prepare()
|
||||
.executeAsBlocking()
|
||||
runBlocking {
|
||||
updateManga.awaitAll(mangaToUpdate)
|
||||
}
|
||||
db.insertMergedMangas(mergedMangaReferences).executeAsBlocking()
|
||||
|
||||
val loadedMangaList = mangaConfigs.map { it.second.children }.flatten().mapNotNull { it.load(db, sourceManager) }.distinct()
|
||||
@@ -208,7 +180,7 @@ object EXHMigrations {
|
||||
.withQuery(
|
||||
Query.builder()
|
||||
.table(ChapterTable.TABLE)
|
||||
.where("${ChapterTable.COL_MANGA_ID} IN (${mergedMangas.filter { it.id != null }.joinToString { it.id.toString() }})")
|
||||
.where("${ChapterTable.COL_MANGA_ID} IN (${mergedMangas.joinToString { it.id.toString() }})")
|
||||
.build(),
|
||||
)
|
||||
.prepare()
|
||||
@@ -289,13 +261,9 @@ object EXHMigrations {
|
||||
}
|
||||
|
||||
// Delete old mangadex trackers
|
||||
db.db.lowLevel().delete(
|
||||
DeleteQuery.builder()
|
||||
.table(TrackTable.TABLE)
|
||||
.where("${TrackTable.COL_SYNC_ID} = ?")
|
||||
.whereArgs(6)
|
||||
.build(),
|
||||
)
|
||||
runBlocking {
|
||||
handler.await { ehQueries.deleteBySyncId(6) }
|
||||
}
|
||||
}
|
||||
if (oldVersion under 18) {
|
||||
val readerTheme = preferences.readerTheme().get()
|
||||
@@ -407,7 +375,7 @@ object EXHMigrations {
|
||||
}
|
||||
if (oldVersion under 31) {
|
||||
runBlocking {
|
||||
database.await(true) {
|
||||
handler.await(true) {
|
||||
prefs.getStringSet("eh_saved_searches", emptySet())?.forEach {
|
||||
kotlin.runCatching {
|
||||
val content = Json.decodeFromString<JsonObject>(it.substringAfter(':'))
|
||||
@@ -421,7 +389,7 @@ object EXHMigrations {
|
||||
}
|
||||
}
|
||||
}
|
||||
database.await(true) {
|
||||
handler.await(true) {
|
||||
prefs.getStringSet("latest_tab_sources", emptySet())?.forEach {
|
||||
feed_saved_searchQueries.insertFeedSavedSearch(
|
||||
_id = null,
|
||||
@@ -557,7 +525,7 @@ object EXHMigrations {
|
||||
}
|
||||
}
|
||||
|
||||
private fun readMangaConfig(manga: SManga): MangaConfig? {
|
||||
private fun readMangaConfig(manga: DomainManga): MangaConfig? {
|
||||
return MangaConfig.readFromUrl(manga.url)
|
||||
}
|
||||
|
||||
@@ -586,17 +554,8 @@ object EXHMigrations {
|
||||
private data class LoadedMangaSource(val source: Source, val manga: Manga)
|
||||
|
||||
private fun updateSourceId(newId: Long, oldId: Long) {
|
||||
db.lowLevel().executeSQL(
|
||||
RawQuery.builder()
|
||||
.query(
|
||||
"""
|
||||
UPDATE ${MangaTable.TABLE}
|
||||
SET ${MangaTable.COL_SOURCE} = $newId
|
||||
WHERE ${MangaTable.COL_SOURCE} = $oldId
|
||||
""".trimIndent(),
|
||||
)
|
||||
.affectsTables(MangaTable.TABLE)
|
||||
.build(),
|
||||
)
|
||||
runBlocking {
|
||||
handler.await { ehQueries.migrateSource(newId, oldId) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,8 +7,7 @@ import eu.kanade.data.chapter.chapterMapper
|
||||
import eu.kanade.data.manga.mangaMapper
|
||||
import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource
|
||||
import eu.kanade.domain.chapter.model.Chapter
|
||||
import eu.kanade.domain.manga.interactor.GetMangaById
|
||||
import eu.kanade.domain.manga.interactor.GetMangaByUrlAndSource
|
||||
import eu.kanade.domain.manga.interactor.GetManga
|
||||
import eu.kanade.domain.manga.interactor.UpdateManga
|
||||
import eu.kanade.domain.manga.model.Manga
|
||||
import eu.kanade.domain.manga.model.toMangaInfo
|
||||
@@ -25,8 +24,7 @@ import uy.kohesive.injekt.api.get
|
||||
|
||||
class GalleryAdder(
|
||||
private val handler: DatabaseHandler = Injekt.get(),
|
||||
private val getMangaByUrlAndSource: GetMangaByUrlAndSource = Injekt.get(),
|
||||
private val getMangaById: GetMangaById = Injekt.get(),
|
||||
private val getManga: GetManga = Injekt.get(),
|
||||
private val updateManga: UpdateManga = Injekt.get(),
|
||||
private val syncChaptersWithSource: SyncChaptersWithSource = Injekt.get(),
|
||||
private val sourceManager: SourceManager = Injekt.get(),
|
||||
@@ -120,7 +118,7 @@ class GalleryAdder(
|
||||
} ?: return GalleryAddEvent.Fail.UnknownType(url, context)
|
||||
|
||||
// Use manga in DB if possible, otherwise, make a new manga
|
||||
var manga = getMangaByUrlAndSource.await(cleanedMangaUrl, source.id)
|
||||
var manga = getManga.await(cleanedMangaUrl, source.id)
|
||||
?: handler.awaitOne(true) {
|
||||
// Insert created manga if not in DB before fetching details
|
||||
// This allows us to keep the metadata when fetching details
|
||||
@@ -135,7 +133,7 @@ class GalleryAdder(
|
||||
// Fetch and copy details
|
||||
val newManga = source.getMangaDetails(manga.toMangaInfo())
|
||||
updateManga.awaitUpdateFromSource(manga, newManga, false, Injekt.get())
|
||||
manga = getMangaById.await(manga.id)!!
|
||||
manga = getManga.await(manga.id)!!
|
||||
|
||||
if (fav) {
|
||||
updateManga.awaitUpdateFavorite(manga.id, true)
|
||||
|
||||
@@ -2,13 +2,16 @@ package exh.debug
|
||||
|
||||
import android.app.Application
|
||||
import androidx.work.WorkManager
|
||||
import com.pushtorefresh.storio.sqlite.queries.RawQuery
|
||||
import eu.kanade.data.AndroidDatabaseHandler
|
||||
import eu.kanade.data.DatabaseHandler
|
||||
import eu.kanade.data.manga.mangaMapper
|
||||
import eu.kanade.domain.manga.interactor.GetAllManga
|
||||
import eu.kanade.domain.manga.interactor.GetExhFavoriteMangaWithMetadata
|
||||
import eu.kanade.domain.manga.interactor.GetFavorites
|
||||
import eu.kanade.domain.manga.interactor.GetFlatMetadataById
|
||||
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.DatabaseHelper
|
||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
@@ -17,18 +20,10 @@ import exh.EXHMigrations
|
||||
import exh.eh.EHentaiThrottleManager
|
||||
import exh.eh.EHentaiUpdateWorker
|
||||
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.source.nHentaiSourceIds
|
||||
import exh.util.cancellable
|
||||
import exh.util.executeOnIO
|
||||
import exh.util.jobScheduler
|
||||
import kotlinx.coroutines.flow.asFlow
|
||||
import kotlinx.coroutines.flow.mapNotNull
|
||||
import kotlinx.coroutines.flow.toList
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.util.UUID
|
||||
@@ -36,12 +31,16 @@ import java.util.UUID
|
||||
@Suppress("unused")
|
||||
object DebugFunctions {
|
||||
val app: Application by injectLazy()
|
||||
val db: DatabaseHelper by injectLazy()
|
||||
val handler: DatabaseHandler by injectLazy()
|
||||
val prefs: PreferencesHelper by injectLazy()
|
||||
val sourceManager: SourceManager by injectLazy()
|
||||
val updateManga: UpdateManga by injectLazy()
|
||||
val getFavorites: GetFavorites by injectLazy()
|
||||
val getFlatMetadataById: GetFlatMetadataById by injectLazy()
|
||||
val insertFlatMetadata: InsertFlatMetadata by injectLazy()
|
||||
val getExhFavoriteMangaWithMetadata: GetExhFavoriteMangaWithMetadata by injectLazy()
|
||||
val getSearchMetadata: GetSearchMetadata by injectLazy()
|
||||
val getAllManga: GetAllManga by injectLazy()
|
||||
|
||||
fun forceUpgradeMigration() {
|
||||
prefs.ehLastVersionCode().set(1)
|
||||
@@ -55,18 +54,11 @@ object DebugFunctions {
|
||||
|
||||
fun resetAgedFlagInEXHManga() {
|
||||
runBlocking {
|
||||
val metadataManga = db.getFavoriteMangaWithMetadata().executeOnIO()
|
||||
|
||||
val allManga = metadataManga.asFlow().cancellable().mapNotNull { manga ->
|
||||
if (manga.isEhBasedManga()) manga
|
||||
else null
|
||||
}.toList()
|
||||
|
||||
allManga.forEach { manga ->
|
||||
val meta = handler.awaitFlatMetadataForManga(manga.id!!)?.raise<EHentaiSearchMetadata>() ?: return@forEach
|
||||
getExhFavoriteMangaWithMetadata.await().forEach { manga ->
|
||||
val meta = getFlatMetadataById.await(manga.id)?.raise<EHentaiSearchMetadata>() ?: return@forEach
|
||||
// remove age flag
|
||||
meta.aged = false
|
||||
handler.awaitInsertFlatMetadata(meta.flatten())
|
||||
insertFlatMetadata.await(meta)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -77,8 +69,7 @@ object DebugFunctions {
|
||||
fun resetEHGalleriesForUpdater() {
|
||||
throttleManager.resetThrottle()
|
||||
runBlocking {
|
||||
val allManga = handler
|
||||
.awaitList { mangasQueries.getEhMangaWithMetadata(EH_SOURCE_ID, EXH_SOURCE_ID, mangaMapper) }
|
||||
val allManga = getExhFavoriteMangaWithMetadata.await()
|
||||
|
||||
val eh = sourceManager.get(EH_SOURCE_ID)
|
||||
val ex = sourceManager.get(EXH_SOURCE_ID)
|
||||
@@ -99,11 +90,8 @@ object DebugFunctions {
|
||||
|
||||
fun getEHMangaListWithAgedFlagInfo(): String {
|
||||
return runBlocking {
|
||||
val allManga = handler
|
||||
.awaitList { mangasQueries.getEhMangaWithMetadata(EH_SOURCE_ID, EXH_SOURCE_ID, mangaMapper) }
|
||||
|
||||
allManga.map { manga ->
|
||||
val meta = handler.awaitFlatMetadataForManga(manga.id)?.raise<EHentaiSearchMetadata>() ?: return@map
|
||||
getExhFavoriteMangaWithMetadata.await().map { manga ->
|
||||
val meta = getFlatMetadataById.await(manga.id)?.raise<EHentaiSearchMetadata>() ?: return@map
|
||||
"Aged: ${meta.aged}\t Title: ${manga.title}"
|
||||
}
|
||||
}.joinToString(",\n")
|
||||
@@ -111,10 +99,9 @@ object DebugFunctions {
|
||||
|
||||
fun countAgedFlagInEXHManga(): Int {
|
||||
return runBlocking {
|
||||
handler
|
||||
.awaitList { mangasQueries.getEhMangaWithMetadata(EH_SOURCE_ID, EXH_SOURCE_ID, mangaMapper) }
|
||||
getExhFavoriteMangaWithMetadata.await()
|
||||
.count { manga ->
|
||||
val meta = handler.awaitFlatMetadataForManga(manga.id)
|
||||
val meta = getFlatMetadataById.await(manga.id)
|
||||
?.raise<EHentaiSearchMetadata>()
|
||||
?: return@count false
|
||||
meta.aged
|
||||
@@ -123,31 +110,30 @@ object DebugFunctions {
|
||||
}
|
||||
|
||||
fun addAllMangaInDatabaseToLibrary() {
|
||||
db.inTransaction {
|
||||
db.lowLevel().executeSQL(
|
||||
RawQuery.builder()
|
||||
.query(
|
||||
"""
|
||||
UPDATE ${MangaTable.TABLE}
|
||||
SET ${MangaTable.COL_FAVORITE} = 1
|
||||
""".trimIndent(),
|
||||
)
|
||||
.affectsTables(MangaTable.TABLE)
|
||||
.build(),
|
||||
(handler as AndroidDatabaseHandler).rawQuery {
|
||||
it.execute(
|
||||
null,
|
||||
"""
|
||||
UPDATE ${MangaTable.TABLE}
|
||||
SET ${MangaTable.COL_FAVORITE} = 1
|
||||
""".trimIndent(),
|
||||
0,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun countMangaInDatabaseInLibrary() = runBlocking { getFavorites.await().size }
|
||||
|
||||
fun countMangaInDatabaseNotInLibrary() = db.getMangas().executeAsBlocking().count { !it.favorite }
|
||||
fun countMangaInDatabaseNotInLibrary() = runBlocking { getAllManga.await() }.count { !it.favorite }
|
||||
|
||||
fun countMangaInDatabase() = db.getMangas().executeAsBlocking().size
|
||||
fun countMangaInDatabase() = runBlocking { getAllManga.await() }.size
|
||||
|
||||
fun countMetadataInDatabase() = db.getSearchMetadata().executeAsBlocking().size
|
||||
fun countMetadataInDatabase() = runBlocking { getSearchMetadata.await().size }
|
||||
|
||||
fun countMangaInLibraryWithMissingMetadata() = db.getMangas().executeAsBlocking().count {
|
||||
it.favorite && db.getSearchMetadataForManga(it.id!!).executeAsBlocking() == null
|
||||
fun countMangaInLibraryWithMissingMetadata() = runBlocking {
|
||||
runBlocking { getAllManga.await() }.count {
|
||||
it.favorite && getSearchMetadata.await(it.id) == null
|
||||
}
|
||||
}
|
||||
|
||||
fun clearSavedSearches() = runBlocking { handler.await { saved_searchQueries.deleteAll() } }
|
||||
@@ -214,18 +200,17 @@ object DebugFunctions {
|
||||
fun cancelAllScheduledJobs() = app.jobScheduler.cancelAll()
|
||||
|
||||
private fun convertSources(from: Long, to: Long) {
|
||||
db.lowLevel().executeSQL(
|
||||
RawQuery.builder()
|
||||
.query(
|
||||
"""
|
||||
UPDATE ${MangaTable.TABLE}
|
||||
SET ${MangaTable.COL_SOURCE} = $to
|
||||
WHERE ${MangaTable.COL_SOURCE} = $from
|
||||
""".trimIndent(),
|
||||
)
|
||||
.affectsTables(MangaTable.TABLE)
|
||||
.build(),
|
||||
)
|
||||
(handler as AndroidDatabaseHandler).rawQuery {
|
||||
it.execute(
|
||||
null,
|
||||
"""
|
||||
UPDATE ${MangaTable.TABLE}
|
||||
SET ${MangaTable.COL_SOURCE} = $to
|
||||
WHERE ${MangaTable.COL_SOURCE} = $from
|
||||
""".trimIndent(),
|
||||
0,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/*fun copyEHentaiSavedSearchesToExhentai() {
|
||||
@@ -307,34 +292,28 @@ object DebugFunctions {
|
||||
}*/
|
||||
|
||||
fun fixReaderViewerBackupBug() {
|
||||
db.inTransaction {
|
||||
db.lowLevel().executeSQL(
|
||||
RawQuery.builder()
|
||||
.query(
|
||||
"""
|
||||
UPDATE ${MangaTable.TABLE}
|
||||
SET ${MangaTable.COL_VIEWER} = 0
|
||||
WHERE ${MangaTable.COL_VIEWER} = -1
|
||||
""".trimIndent(),
|
||||
)
|
||||
.affectsTables(MangaTable.TABLE)
|
||||
.build(),
|
||||
(handler as AndroidDatabaseHandler).rawQuery {
|
||||
it.execute(
|
||||
null,
|
||||
"""
|
||||
UPDATE ${MangaTable.TABLE}
|
||||
SET ${MangaTable.COL_VIEWER} = 0
|
||||
WHERE ${MangaTable.COL_VIEWER} = -1
|
||||
""".trimIndent(),
|
||||
0,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun resetReaderViewerForAllManga() {
|
||||
db.inTransaction {
|
||||
db.lowLevel().executeSQL(
|
||||
RawQuery.builder()
|
||||
.query(
|
||||
"""
|
||||
UPDATE ${MangaTable.TABLE}
|
||||
SET ${MangaTable.COL_VIEWER} = 0
|
||||
""".trimIndent(),
|
||||
)
|
||||
.affectsTables(MangaTable.TABLE)
|
||||
.build(),
|
||||
(handler as AndroidDatabaseHandler).rawQuery {
|
||||
it.execute(
|
||||
null,
|
||||
"""
|
||||
UPDATE ${MangaTable.TABLE}
|
||||
SET ${MangaTable.COL_VIEWER} = 0
|
||||
""".trimIndent(),
|
||||
0,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -344,34 +323,28 @@ object DebugFunctions {
|
||||
.also { it.remove(NHentai.otherId) }
|
||||
.joinToString(separator = ",")
|
||||
|
||||
db.inTransaction {
|
||||
db.lowLevel().executeSQL(
|
||||
RawQuery.builder()
|
||||
.query(
|
||||
"""
|
||||
UPDATE ${MangaTable.TABLE}
|
||||
SET ${MangaTable.COL_SOURCE} = ${NHentai.otherId}
|
||||
WHERE ${MangaTable.COL_FAVORITE} = 1 AND ${MangaTable.COL_SOURCE} in ($sources)
|
||||
""".trimIndent(),
|
||||
)
|
||||
.affectsTables(MangaTable.TABLE)
|
||||
.build(),
|
||||
(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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun resetFilteredScanlatorsForAllManga() {
|
||||
db.inTransaction {
|
||||
db.lowLevel().executeSQL(
|
||||
RawQuery.builder()
|
||||
.query(
|
||||
"""
|
||||
UPDATE ${MangaTable.TABLE}
|
||||
SET ${MangaTable.COL_FILTERED_SCANLATORS} = NULL
|
||||
""".trimIndent(),
|
||||
)
|
||||
.affectsTables(MangaTable.TABLE)
|
||||
.build(),
|
||||
(handler as AndroidDatabaseHandler).rawQuery {
|
||||
it.execute(
|
||||
null,
|
||||
"""
|
||||
UPDATE ${MangaTable.TABLE}
|
||||
SET ${MangaTable.COL_FILTERED_SCANLATORS} = NULL
|
||||
""".trimIndent(),
|
||||
0,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import eu.kanade.domain.history.interactor.RemoveHistoryById
|
||||
import eu.kanade.domain.history.interactor.UpsertHistory
|
||||
import eu.kanade.domain.history.model.History
|
||||
import eu.kanade.domain.history.model.HistoryUpdate
|
||||
import eu.kanade.domain.manga.interactor.GetMangaById
|
||||
import eu.kanade.domain.manga.interactor.GetManga
|
||||
import eu.kanade.domain.manga.interactor.UpdateManga
|
||||
import eu.kanade.domain.manga.model.Manga
|
||||
import eu.kanade.domain.manga.model.MangaUpdate
|
||||
@@ -37,7 +37,7 @@ class EHentaiUpdateHelper(context: Context) {
|
||||
)
|
||||
private val handler: DatabaseHandler by injectLazy()
|
||||
private val getChapterByMangaId: GetChapterByMangaId by injectLazy()
|
||||
private val getMangaById: GetMangaById by injectLazy()
|
||||
private val getManga: GetManga by injectLazy()
|
||||
private val updateManga: UpdateManga by injectLazy()
|
||||
private val setMangaCategories: SetMangaCategories by injectLazy()
|
||||
private val getCategories: GetCategories by injectLazy()
|
||||
@@ -64,7 +64,7 @@ class EHentaiUpdateHelper(context: Context) {
|
||||
.mapNotNull { mangaId ->
|
||||
coroutineScope {
|
||||
val manga = async(Dispatchers.IO) {
|
||||
getMangaById.await(mangaId)
|
||||
getManga.await(mangaId)
|
||||
}
|
||||
val chapterList = async(Dispatchers.IO) {
|
||||
getChapterByMangaId.await(mangaId)
|
||||
|
||||
@@ -21,7 +21,6 @@ import eu.kanade.domain.manga.interactor.UpdateManga
|
||||
import eu.kanade.domain.manga.model.Manga
|
||||
import eu.kanade.domain.manga.model.toDbManga
|
||||
import eu.kanade.domain.manga.model.toMangaInfo
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
import eu.kanade.tachiyomi.data.library.LibraryUpdateNotifier
|
||||
import eu.kanade.tachiyomi.data.preference.DEVICE_CHARGING
|
||||
import eu.kanade.tachiyomi.data.preference.DEVICE_ONLY_ON_WIFI
|
||||
@@ -35,7 +34,7 @@ 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.insertFlatMetadataAsync
|
||||
import exh.metadata.metadata.base.awaitInsertFlatMetadata
|
||||
import exh.source.EH_SOURCE_ID
|
||||
import exh.source.EXH_SOURCE_ID
|
||||
import exh.source.isEhBasedManga
|
||||
@@ -54,7 +53,6 @@ import kotlin.time.Duration.Companion.days
|
||||
|
||||
class EHentaiUpdateWorker(private val context: Context, workerParams: WorkerParameters) :
|
||||
CoroutineWorker(context, workerParams) {
|
||||
private val db: DatabaseHelper by injectLazy()
|
||||
private val handler: DatabaseHandler by injectLazy()
|
||||
private val prefs: PreferencesHelper by injectLazy()
|
||||
private val sourceManager: SourceManager by injectLazy()
|
||||
@@ -228,7 +226,7 @@ class EHentaiUpdateWorker(private val context: Context, workerParams: WorkerPara
|
||||
// Age dead galleries
|
||||
logger.d("Aged %s - notfound", manga.id)
|
||||
meta.aged = true
|
||||
db.insertFlatMetadataAsync(meta.flatten()).await()
|
||||
handler.awaitInsertFlatMetadata(meta.flatten())
|
||||
}
|
||||
throw GalleryNotUpdatedException(false, t)
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import eu.kanade.data.DatabaseHandler
|
||||
import eu.kanade.domain.category.interactor.GetCategories
|
||||
import eu.kanade.domain.category.interactor.SetMangaCategories
|
||||
import eu.kanade.domain.category.model.Category
|
||||
import eu.kanade.domain.manga.interactor.GetMangaByUrlAndSource
|
||||
import eu.kanade.domain.manga.interactor.GetManga
|
||||
import eu.kanade.domain.manga.interactor.UpdateManga
|
||||
import eu.kanade.domain.manga.model.Manga
|
||||
import eu.kanade.tachiyomi.R
|
||||
@@ -50,7 +50,7 @@ import kotlin.time.Duration.Companion.seconds
|
||||
class FavoritesSyncHelper(val context: Context) {
|
||||
private val handler: DatabaseHandler by injectLazy()
|
||||
private val getCategories: GetCategories by injectLazy()
|
||||
private val getMangaByUrlAndSource: GetMangaByUrlAndSource by injectLazy()
|
||||
private val getManga: GetManga by injectLazy()
|
||||
private val updateManga: UpdateManga by injectLazy()
|
||||
private val setMangaCategories: SetMangaCategories by injectLazy()
|
||||
|
||||
@@ -332,7 +332,7 @@ class FavoritesSyncHelper(val context: Context) {
|
||||
EXH_SOURCE_ID,
|
||||
EH_SOURCE_ID,
|
||||
).forEach {
|
||||
val manga = getMangaByUrlAndSource.await(url, it)
|
||||
val manga = getManga.await(url, it)
|
||||
|
||||
if (manga?.favorite == true) {
|
||||
updateManga.awaitUpdateFavorite(manga.id, false)
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
package exh.favorites
|
||||
|
||||
import eu.kanade.data.DatabaseHandler
|
||||
import eu.kanade.data.exh.favoriteEntryMapper
|
||||
import eu.kanade.domain.category.interactor.GetCategories
|
||||
import eu.kanade.domain.manga.interactor.DeleteFavoriteEntries
|
||||
import eu.kanade.domain.manga.interactor.GetFavoriteEntries
|
||||
import eu.kanade.domain.manga.interactor.GetFavorites
|
||||
import eu.kanade.domain.manga.interactor.InsertFavoriteEntries
|
||||
import eu.kanade.domain.manga.model.Manga
|
||||
import eu.kanade.tachiyomi.data.database.models.toDomainManga
|
||||
import eu.kanade.tachiyomi.source.online.all.EHentai
|
||||
@@ -19,9 +20,11 @@ import kotlinx.coroutines.flow.toList
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
class LocalFavoritesStorage {
|
||||
private val handler: DatabaseHandler by injectLazy()
|
||||
private val getFavorites: GetFavorites by injectLazy()
|
||||
private val getCategories: GetCategories by injectLazy()
|
||||
private val deleteFavoriteEntries: DeleteFavoriteEntries by injectLazy()
|
||||
private val getFavoriteEntries: GetFavoriteEntries by injectLazy()
|
||||
private val insertFavoriteEntries: InsertFavoriteEntries by injectLazy()
|
||||
|
||||
suspend fun getChangedDbEntries() = getFavorites.await()
|
||||
.asFlow()
|
||||
@@ -48,30 +51,20 @@ class LocalFavoritesStorage {
|
||||
.parseToFavoriteEntries()
|
||||
|
||||
// Delete old snapshot
|
||||
handler.await { eh_favoritesQueries.deleteAll() }
|
||||
deleteFavoriteEntries.await()
|
||||
|
||||
// Insert new snapshots
|
||||
handler.await(true) {
|
||||
dbMangas.toList().forEach {
|
||||
eh_favoritesQueries.insertEhFavorites(
|
||||
it.id,
|
||||
it.title,
|
||||
it.gid,
|
||||
it.token,
|
||||
it.category.toLong(),
|
||||
)
|
||||
}
|
||||
}
|
||||
insertFavoriteEntries.await(dbMangas.toList())
|
||||
}
|
||||
|
||||
suspend fun clearSnapshots() {
|
||||
handler.await { eh_favoritesQueries.deleteAll() }
|
||||
deleteFavoriteEntries.await()
|
||||
}
|
||||
|
||||
private suspend fun Flow<FavoriteEntry>.getChangedEntries(): ChangeSet {
|
||||
val terminated = toList()
|
||||
|
||||
val databaseEntries = handler.awaitList { eh_favoritesQueries.selectAll(favoriteEntryMapper) }
|
||||
val databaseEntries = getFavoriteEntries.await()
|
||||
|
||||
val added = terminated.filter {
|
||||
queryListForEntry(databaseEntries, it) == null
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
package exh.favorites.sql.mappers
|
||||
|
||||
import android.database.Cursor
|
||||
import androidx.core.content.contentValuesOf
|
||||
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.favorites.sql.models.FavoriteEntry
|
||||
import exh.favorites.sql.tables.FavoriteEntryTable.COL_CATEGORY
|
||||
import exh.favorites.sql.tables.FavoriteEntryTable.COL_GID
|
||||
import exh.favorites.sql.tables.FavoriteEntryTable.COL_ID
|
||||
import exh.favorites.sql.tables.FavoriteEntryTable.COL_TITLE
|
||||
import exh.favorites.sql.tables.FavoriteEntryTable.COL_TOKEN
|
||||
import exh.favorites.sql.tables.FavoriteEntryTable.TABLE
|
||||
|
||||
class FavoriteEntryTypeMapping : SQLiteTypeMapping<FavoriteEntry>(
|
||||
FavoriteEntryPutResolver(),
|
||||
FavoriteEntryGetResolver(),
|
||||
FavoriteEntryDeleteResolver(),
|
||||
)
|
||||
|
||||
class FavoriteEntryPutResolver : DefaultPutResolver<FavoriteEntry>() {
|
||||
|
||||
override fun mapToInsertQuery(obj: FavoriteEntry) = InsertQuery.builder()
|
||||
.table(TABLE)
|
||||
.build()
|
||||
|
||||
override fun mapToUpdateQuery(obj: FavoriteEntry) = UpdateQuery.builder()
|
||||
.table(TABLE)
|
||||
.where("$COL_ID = ?")
|
||||
.whereArgs(obj.id)
|
||||
.build()
|
||||
|
||||
override fun mapToContentValues(obj: FavoriteEntry) = contentValuesOf(
|
||||
COL_ID to obj.id,
|
||||
COL_TITLE to obj.title,
|
||||
COL_GID to obj.gid,
|
||||
COL_TOKEN to obj.token,
|
||||
COL_CATEGORY to obj.category,
|
||||
)
|
||||
}
|
||||
|
||||
class FavoriteEntryGetResolver : DefaultGetResolver<FavoriteEntry>() {
|
||||
|
||||
override fun mapFromCursor(cursor: Cursor): FavoriteEntry = FavoriteEntry(
|
||||
id = cursor.getLong(cursor.getColumnIndexOrThrow(COL_ID)),
|
||||
title = cursor.getString(cursor.getColumnIndexOrThrow(COL_TITLE)),
|
||||
gid = cursor.getString(cursor.getColumnIndexOrThrow(COL_GID)),
|
||||
token = cursor.getString(cursor.getColumnIndexOrThrow(COL_TOKEN)),
|
||||
category = cursor.getInt(cursor.getColumnIndexOrThrow(COL_CATEGORY)),
|
||||
)
|
||||
}
|
||||
|
||||
class FavoriteEntryDeleteResolver : DefaultDeleteResolver<FavoriteEntry>() {
|
||||
|
||||
override fun mapToDeleteQuery(obj: FavoriteEntry) = DeleteQuery.builder()
|
||||
.table(TABLE)
|
||||
.where("$COL_ID = ?")
|
||||
.whereArgs(obj.id)
|
||||
.build()
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package exh.favorites.sql.queries
|
||||
|
||||
import com.pushtorefresh.storio.sqlite.queries.DeleteQuery
|
||||
import com.pushtorefresh.storio.sqlite.queries.Query
|
||||
import eu.kanade.tachiyomi.data.database.DbProvider
|
||||
import exh.favorites.sql.models.FavoriteEntry
|
||||
import exh.favorites.sql.tables.FavoriteEntryTable
|
||||
|
||||
interface FavoriteEntryQueries : DbProvider {
|
||||
fun getFavoriteEntries() = db.get()
|
||||
.listOfObjects(FavoriteEntry::class.java)
|
||||
.withQuery(
|
||||
Query.builder()
|
||||
.table(FavoriteEntryTable.TABLE)
|
||||
.build(),
|
||||
)
|
||||
.prepare()
|
||||
|
||||
fun insertFavoriteEntries(favoriteEntries: List<FavoriteEntry>) = db.put()
|
||||
.objects(favoriteEntries)
|
||||
.prepare()
|
||||
|
||||
fun deleteAllFavoriteEntries() = db.delete()
|
||||
.byQuery(
|
||||
DeleteQuery.builder()
|
||||
.table(FavoriteEntryTable.TABLE)
|
||||
.build(),
|
||||
)
|
||||
.prepare()
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package exh.favorites.sql.tables
|
||||
|
||||
object FavoriteEntryTable {
|
||||
|
||||
const val TABLE = "eh_favorites"
|
||||
|
||||
const val COL_ID = "_id"
|
||||
|
||||
const val COL_TITLE = "title"
|
||||
|
||||
const val COL_GID = "gid"
|
||||
|
||||
const val COL_TOKEN = "token"
|
||||
|
||||
const val COL_CATEGORY = "category"
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
package exh.md.handlers
|
||||
|
||||
import eu.kanade.data.DatabaseHandler
|
||||
import eu.kanade.domain.manga.interactor.GetMangaByUrlAndSource
|
||||
import eu.kanade.domain.manga.interactor.GetFlatMetadataById
|
||||
import eu.kanade.domain.manga.interactor.GetManga
|
||||
import eu.kanade.domain.manga.interactor.InsertFlatMetadata
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import exh.log.xLogE
|
||||
import exh.md.dto.ChapterDataDto
|
||||
@@ -13,8 +14,6 @@ import exh.md.utils.MdUtil
|
||||
import exh.md.utils.asMdMap
|
||||
import exh.metadata.metadata.MangaDexSearchMetadata
|
||||
import exh.metadata.metadata.base.RaisedTag
|
||||
import exh.metadata.metadata.base.awaitFlatMetadataForManga
|
||||
import exh.metadata.metadata.base.awaitInsertFlatMetadata
|
||||
import exh.util.capitalize
|
||||
import exh.util.floor
|
||||
import exh.util.nullIfEmpty
|
||||
@@ -26,8 +25,9 @@ import java.util.Locale
|
||||
class ApiMangaParser(
|
||||
private val lang: String,
|
||||
) {
|
||||
private val handler: DatabaseHandler by injectLazy()
|
||||
private val getMangaByUrlAndSource: GetMangaByUrlAndSource by injectLazy()
|
||||
private val getManga: GetManga by injectLazy()
|
||||
private val insertFlatMetadata: InsertFlatMetadata by injectLazy()
|
||||
private val getFlatMetadataById: GetFlatMetadataById by injectLazy()
|
||||
|
||||
val metaClass = MangaDexSearchMetadata::class
|
||||
|
||||
@@ -46,16 +46,16 @@ class ApiMangaParser(
|
||||
simpleChapters: List<String>,
|
||||
statistics: StatisticsMangaDto?,
|
||||
): MangaInfo {
|
||||
val mangaId = getMangaByUrlAndSource.await(manga.key, sourceId)?.id
|
||||
val mangaId = getManga.await(manga.key, sourceId)?.id
|
||||
val metadata = if (mangaId != null) {
|
||||
val flatMetadata = handler.awaitFlatMetadataForManga(mangaId)
|
||||
val flatMetadata = getFlatMetadataById.await(mangaId)
|
||||
flatMetadata?.raise(metaClass) ?: newMetaInstance()
|
||||
} else newMetaInstance()
|
||||
|
||||
parseIntoMetadata(metadata, input, simpleChapters, statistics)
|
||||
if (mangaId != null) {
|
||||
metadata.mangaId = mangaId
|
||||
handler.awaitInsertFlatMetadata(metadata.flatten())
|
||||
insertFlatMetadata.await(metadata.flatten())
|
||||
}
|
||||
|
||||
return metadata.createMangaInfo(manga)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package exh.md.similar
|
||||
|
||||
import eu.kanade.domain.manga.interactor.GetMangaById
|
||||
import eu.kanade.domain.manga.interactor.GetManga
|
||||
import eu.kanade.domain.manga.model.Manga
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
import eu.kanade.tachiyomi.source.online.all.MangaDex
|
||||
@@ -17,14 +17,14 @@ import uy.kohesive.injekt.api.get
|
||||
class MangaDexSimilarPresenter(
|
||||
val mangaId: Long,
|
||||
sourceId: Long,
|
||||
private val getMangaById: GetMangaById = Injekt.get(),
|
||||
private val getManga: GetManga = Injekt.get(),
|
||||
) : BrowseSourcePresenter(sourceId) {
|
||||
|
||||
var manga: Manga? = null
|
||||
|
||||
override fun createPager(query: String, filters: FilterList): Pager {
|
||||
val sourceAsMangaDex = source.getMainSource() as MangaDex
|
||||
this.manga = runBlocking { getMangaById.await(mangaId) }
|
||||
this.manga = runBlocking { getManga.await(mangaId) }
|
||||
return MangaDexSimilarPager(manga!!, sourceAsMangaDex)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,15 +4,9 @@ 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.inTransaction
|
||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.database.queries.getAllMergedMangaQuery
|
||||
import eu.kanade.tachiyomi.data.database.queries.getMergedChaptersQuery
|
||||
import eu.kanade.tachiyomi.data.database.queries.getMergedMangaForDownloadingQuery
|
||||
import eu.kanade.tachiyomi.data.database.queries.getMergedMangaFromUrlQuery
|
||||
import eu.kanade.tachiyomi.data.database.queries.getMergedMangaQuery
|
||||
import eu.kanade.tachiyomi.data.database.tables.ChapterTable
|
||||
import exh.merged.sql.models.MergedMangaReference
|
||||
import exh.merged.sql.resolvers.MergeMangaSettingsPutResolver
|
||||
import exh.merged.sql.resolvers.MergedMangaIdPutResolver
|
||||
@@ -31,17 +25,6 @@ interface MergedQueries : DbProvider {
|
||||
)
|
||||
.prepare()
|
||||
|
||||
fun getMergedMangaReferences(mergedMangaUrl: String) = db.get()
|
||||
.listOfObjects(MergedMangaReference::class.java)
|
||||
.withQuery(
|
||||
Query.builder()
|
||||
.table(MergedTable.TABLE)
|
||||
.where("${MergedTable.COL_MERGE_URL} = ?")
|
||||
.whereArgs(mergedMangaUrl)
|
||||
.build(),
|
||||
)
|
||||
.prepare()
|
||||
|
||||
fun deleteMangaForMergedManga(mergedMangaId: Long) = db.delete()
|
||||
.byQuery(
|
||||
DeleteQuery.builder()
|
||||
@@ -72,56 +55,6 @@ interface MergedQueries : DbProvider {
|
||||
)
|
||||
.prepare()
|
||||
|
||||
fun getMergedMangas(mergedMangaUrl: String) = db.get()
|
||||
.listOfObjects(Manga::class.java)
|
||||
.withQuery(
|
||||
RawQuery.builder()
|
||||
.query(getMergedMangaFromUrlQuery())
|
||||
.args(mergedMangaUrl)
|
||||
.build(),
|
||||
)
|
||||
.prepare()
|
||||
|
||||
fun getMergedMangas() = db.get()
|
||||
.listOfObjects(Manga::class.java)
|
||||
.withQuery(
|
||||
RawQuery.builder()
|
||||
.query(getAllMergedMangaQuery())
|
||||
.build(),
|
||||
)
|
||||
.prepare()
|
||||
|
||||
fun deleteMangaForMergedManga(mergedMangaUrl: String) = db.delete()
|
||||
.byQuery(
|
||||
DeleteQuery.builder()
|
||||
.table(MergedTable.TABLE)
|
||||
.where("${MergedTable.COL_MERGE_URL} = ?")
|
||||
.whereArgs(mergedMangaUrl)
|
||||
.build(),
|
||||
)
|
||||
.prepare()
|
||||
|
||||
fun getMergedMangaReferences() = db.get()
|
||||
.listOfObjects(MergedMangaReference::class.java)
|
||||
.withQuery(
|
||||
Query.builder()
|
||||
.table(MergedTable.TABLE)
|
||||
.orderBy(MergedTable.COL_ID)
|
||||
.build(),
|
||||
)
|
||||
.prepare()
|
||||
|
||||
fun getChaptersByMergedMangaId(mergedMangaId: Long) = db.get()
|
||||
.listOfObjects(Chapter::class.java)
|
||||
.withQuery(
|
||||
RawQuery.builder()
|
||||
.query(getMergedChaptersQuery())
|
||||
.args(mergedMangaId)
|
||||
.observesTables(ChapterTable.TABLE, MergedTable.TABLE)
|
||||
.build(),
|
||||
)
|
||||
.prepare()
|
||||
|
||||
fun insertMergedManga(mergedManga: MergedMangaReference) = db.put().`object`(mergedManga).prepare()
|
||||
|
||||
fun insertNewMergedMangaId(mergedManga: MergedMangaReference) = db.put().`object`(mergedManga).withPutResolver(MergedMangaIdPutResolver()).prepare()
|
||||
@@ -133,20 +66,4 @@ interface MergedQueries : DbProvider {
|
||||
fun updateMergeMangaSettings(mergeManga: MergedMangaReference) = db.put().`object`(mergeManga).withPutResolver(MergeMangaSettingsPutResolver()).prepare()
|
||||
|
||||
fun deleteMergedManga(mergedManga: MergedMangaReference) = db.delete().`object`(mergedManga).prepare()
|
||||
|
||||
fun deleteAllMergedManga() = db.delete().byQuery(
|
||||
DeleteQuery.builder()
|
||||
.table(MergedTable.TABLE)
|
||||
.build(),
|
||||
)
|
||||
.prepare()
|
||||
|
||||
fun setMangasForMergedManga(mergedMangaId: Long, mergedMangas: List<MergedMangaReference>) {
|
||||
db.inTransaction {
|
||||
deleteMangaForMergedManga(mergedMangaId).executeAsBlocking()
|
||||
mergedMangas.chunked(100) { chunk ->
|
||||
insertMergedMangas(chunk).executeAsBlocking()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,23 +1,15 @@
|
||||
package exh.metadata.metadata.base
|
||||
|
||||
import com.pushtorefresh.storio.operations.PreparedOperation
|
||||
import eu.kanade.data.AndroidDatabaseHandler
|
||||
import eu.kanade.data.DatabaseHandler
|
||||
import eu.kanade.data.exh.searchMetadataMapper
|
||||
import eu.kanade.data.exh.searchTagMapper
|
||||
import eu.kanade.data.exh.searchTitleMapper
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
import exh.metadata.sql.models.SearchMetadata
|
||||
import exh.metadata.sql.models.SearchTag
|
||||
import exh.metadata.sql.models.SearchTitle
|
||||
import kotlinx.coroutines.Deferred
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.serialization.InternalSerializationApi
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.serializer
|
||||
import rx.Completable
|
||||
import rx.Single
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
@Serializable
|
||||
@@ -36,17 +28,7 @@ data class FlatMetadata(
|
||||
}
|
||||
}
|
||||
|
||||
fun DatabaseHandler.getFlatMetadataForManga(mangaId: Long): FlatMetadata? {
|
||||
this as AndroidDatabaseHandler
|
||||
val meta = db.search_metadataQueries.selectByMangaId(mangaId, searchMetadataMapper).executeAsOneOrNull()
|
||||
return if (meta != null) {
|
||||
val tags = db.search_tagsQueries.selectByMangaId(mangaId, searchTagMapper).executeAsList()
|
||||
val titles = db.search_titlesQueries.selectByMangaId(mangaId, searchTitleMapper).executeAsList()
|
||||
|
||||
FlatMetadata(meta, tags, titles)
|
||||
} else null
|
||||
}
|
||||
|
||||
@Deprecated("Replace with GetFlatMetadataById")
|
||||
suspend fun DatabaseHandler.awaitFlatMetadataForManga(mangaId: Long): FlatMetadata? {
|
||||
return await {
|
||||
val meta = search_metadataQueries.selectByMangaId(mangaId, searchMetadataMapper).executeAsOneOrNull()
|
||||
@@ -59,86 +41,7 @@ suspend fun DatabaseHandler.awaitFlatMetadataForManga(mangaId: Long): FlatMetada
|
||||
}
|
||||
}
|
||||
|
||||
fun DatabaseHelper.getFlatMetadataForManga(mangaId: Long): PreparedOperation<FlatMetadata?> {
|
||||
// We have to use fromCallable because StorIO messes up the thread scheduling if we use their rx functions
|
||||
val single = Single.fromCallable {
|
||||
val meta = getSearchMetadataForManga(mangaId).executeAsBlocking()
|
||||
if (meta != null) {
|
||||
val tags = getSearchTagsForManga(mangaId).executeAsBlocking()
|
||||
val titles = getSearchTitlesForManga(mangaId).executeAsBlocking()
|
||||
|
||||
FlatMetadata(meta, tags, titles)
|
||||
} else null
|
||||
}
|
||||
|
||||
return preparedOperationFromSingle(single)
|
||||
}
|
||||
|
||||
private fun <T> preparedOperationFromSingle(single: Single<T>): PreparedOperation<T> {
|
||||
return object : PreparedOperation<T> {
|
||||
/**
|
||||
* Creates [rx.Observable] that emits result of Operation.
|
||||
*
|
||||
*
|
||||
* Observable may be "Hot" or "Cold", please read documentation of the concrete implementation.
|
||||
*
|
||||
* @return observable result of operation with only one [rx.Observer.onNext] call.
|
||||
*/
|
||||
override fun createObservable() = single.toObservable()
|
||||
|
||||
/**
|
||||
* Executes operation synchronously in current thread.
|
||||
*
|
||||
*
|
||||
* Notice: Blocking I/O operation should not be executed on the Main Thread,
|
||||
* it can cause ANR (Activity Not Responding dialog), block the UI and drop animations frames.
|
||||
* So please, execute blocking I/O operation only from background thread.
|
||||
* See [androidx.annotation.WorkerThread].
|
||||
*
|
||||
* @return nullable result of operation.
|
||||
*/
|
||||
override fun executeAsBlocking() = single.toBlocking().value()
|
||||
|
||||
/**
|
||||
* Creates [rx.Observable] that emits result of Operation.
|
||||
*
|
||||
*
|
||||
* Observable may be "Hot" (usually "Warm") or "Cold", please read documentation of the concrete implementation.
|
||||
*
|
||||
* @return observable result of operation with only one [rx.Observer.onNext] call.
|
||||
*/
|
||||
override fun asRxObservable() = single.toObservable()
|
||||
|
||||
/**
|
||||
* Creates [rx.Single] that emits result of Operation lazily when somebody subscribes to it.
|
||||
*
|
||||
*
|
||||
*
|
||||
* @return single result of operation.
|
||||
*/
|
||||
override fun asRxSingle() = single
|
||||
}
|
||||
}
|
||||
|
||||
fun DatabaseHandler.insertFlatMetadata(flatMetadata: FlatMetadata) {
|
||||
require(flatMetadata.metadata.mangaId != -1L)
|
||||
|
||||
this as AndroidDatabaseHandler // todo remove when legacy backup is dead
|
||||
db.transaction {
|
||||
flatMetadata.metadata.let {
|
||||
db.search_metadataQueries.upsert(it.mangaId, it.uploader, it.extra, it.indexedExtra, it.extraVersion)
|
||||
}
|
||||
db.search_tagsQueries.deleteByManga(flatMetadata.metadata.mangaId)
|
||||
flatMetadata.tags.forEach {
|
||||
db.search_tagsQueries.insert(it.mangaId, it.namespace, it.name, it.type)
|
||||
}
|
||||
db.search_titlesQueries.deleteByManga(flatMetadata.metadata.mangaId)
|
||||
flatMetadata.titles.forEach {
|
||||
db.search_titlesQueries.insert(it.mangaId, it.title, it.type)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated("Replace with InsertFlatMetadata")
|
||||
suspend fun DatabaseHandler.awaitInsertFlatMetadata(flatMetadata: FlatMetadata) {
|
||||
require(flatMetadata.metadata.mangaId != -1L)
|
||||
|
||||
@@ -156,29 +59,3 @@ suspend fun DatabaseHandler.awaitInsertFlatMetadata(flatMetadata: FlatMetadata)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun DatabaseHelper.insertFlatMetadata(flatMetadata: FlatMetadata) {
|
||||
require(flatMetadata.metadata.mangaId != -1L)
|
||||
|
||||
inTransaction {
|
||||
insertSearchMetadata(flatMetadata.metadata).executeAsBlocking()
|
||||
setSearchTagsForManga(flatMetadata.metadata.mangaId, flatMetadata.tags)
|
||||
setSearchTitlesForManga(flatMetadata.metadata.mangaId, flatMetadata.titles)
|
||||
}
|
||||
}
|
||||
|
||||
fun DatabaseHelper.insertFlatMetadataCompletable(flatMetadata: FlatMetadata): Completable = Completable.fromCallable {
|
||||
insertFlatMetadata(flatMetadata)
|
||||
}
|
||||
|
||||
suspend fun DatabaseHelper.insertFlatMetadataAsync(flatMetadata: FlatMetadata): Deferred<Unit> = coroutineScope {
|
||||
async {
|
||||
require(flatMetadata.metadata.mangaId != -1L)
|
||||
|
||||
inTransaction {
|
||||
insertSearchMetadata(flatMetadata.metadata).executeAsBlocking()
|
||||
setSearchTagsForManga(flatMetadata.metadata.mangaId, flatMetadata.tags)
|
||||
setSearchTitlesForManga(flatMetadata.metadata.mangaId, flatMetadata.titles)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
package exh.metadata.sql.mappers
|
||||
|
||||
import android.database.Cursor
|
||||
import androidx.core.content.contentValuesOf
|
||||
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.metadata.sql.models.SearchMetadata
|
||||
import exh.metadata.sql.tables.SearchMetadataTable.COL_EXTRA
|
||||
import exh.metadata.sql.tables.SearchMetadataTable.COL_EXTRA_VERSION
|
||||
import exh.metadata.sql.tables.SearchMetadataTable.COL_INDEXED_EXTRA
|
||||
import exh.metadata.sql.tables.SearchMetadataTable.COL_MANGA_ID
|
||||
import exh.metadata.sql.tables.SearchMetadataTable.COL_UPLOADER
|
||||
import exh.metadata.sql.tables.SearchMetadataTable.TABLE
|
||||
|
||||
class SearchMetadataTypeMapping : SQLiteTypeMapping<SearchMetadata>(
|
||||
SearchMetadataPutResolver(),
|
||||
SearchMetadataGetResolver(),
|
||||
SearchMetadataDeleteResolver(),
|
||||
)
|
||||
|
||||
class SearchMetadataPutResolver : DefaultPutResolver<SearchMetadata>() {
|
||||
|
||||
override fun mapToInsertQuery(obj: SearchMetadata) = InsertQuery.builder()
|
||||
.table(TABLE)
|
||||
.build()
|
||||
|
||||
override fun mapToUpdateQuery(obj: SearchMetadata) = UpdateQuery.builder()
|
||||
.table(TABLE)
|
||||
.where("$COL_MANGA_ID = ?")
|
||||
.whereArgs(obj.mangaId)
|
||||
.build()
|
||||
|
||||
override fun mapToContentValues(obj: SearchMetadata) = contentValuesOf(
|
||||
COL_MANGA_ID to obj.mangaId,
|
||||
COL_UPLOADER to obj.uploader,
|
||||
COL_EXTRA to obj.extra,
|
||||
COL_INDEXED_EXTRA to obj.indexedExtra,
|
||||
COL_EXTRA_VERSION to obj.extraVersion,
|
||||
)
|
||||
}
|
||||
|
||||
class SearchMetadataGetResolver : DefaultGetResolver<SearchMetadata>() {
|
||||
|
||||
override fun mapFromCursor(cursor: Cursor): SearchMetadata =
|
||||
SearchMetadata(
|
||||
mangaId = cursor.getLong(cursor.getColumnIndexOrThrow(COL_MANGA_ID)),
|
||||
uploader = cursor.getString(cursor.getColumnIndexOrThrow(COL_UPLOADER)),
|
||||
extra = cursor.getString(cursor.getColumnIndexOrThrow(COL_EXTRA)),
|
||||
indexedExtra = cursor.getString(cursor.getColumnIndexOrThrow(COL_INDEXED_EXTRA)),
|
||||
extraVersion = cursor.getInt(cursor.getColumnIndexOrThrow(COL_EXTRA_VERSION)),
|
||||
)
|
||||
}
|
||||
|
||||
class SearchMetadataDeleteResolver : DefaultDeleteResolver<SearchMetadata>() {
|
||||
|
||||
override fun mapToDeleteQuery(obj: SearchMetadata) = DeleteQuery.builder()
|
||||
.table(TABLE)
|
||||
.where("$COL_MANGA_ID = ?")
|
||||
.whereArgs(obj.mangaId)
|
||||
.build()
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
package exh.metadata.sql.mappers
|
||||
|
||||
import android.database.Cursor
|
||||
import androidx.core.content.contentValuesOf
|
||||
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.metadata.sql.models.SearchTag
|
||||
import exh.metadata.sql.tables.SearchTagTable.COL_ID
|
||||
import exh.metadata.sql.tables.SearchTagTable.COL_MANGA_ID
|
||||
import exh.metadata.sql.tables.SearchTagTable.COL_NAME
|
||||
import exh.metadata.sql.tables.SearchTagTable.COL_NAMESPACE
|
||||
import exh.metadata.sql.tables.SearchTagTable.COL_TYPE
|
||||
import exh.metadata.sql.tables.SearchTagTable.TABLE
|
||||
|
||||
class SearchTagTypeMapping : SQLiteTypeMapping<SearchTag>(
|
||||
SearchTagPutResolver(),
|
||||
SearchTagGetResolver(),
|
||||
SearchTagDeleteResolver(),
|
||||
)
|
||||
|
||||
class SearchTagPutResolver : DefaultPutResolver<SearchTag>() {
|
||||
|
||||
override fun mapToInsertQuery(obj: SearchTag) = InsertQuery.builder()
|
||||
.table(TABLE)
|
||||
.build()
|
||||
|
||||
override fun mapToUpdateQuery(obj: SearchTag) = UpdateQuery.builder()
|
||||
.table(TABLE)
|
||||
.where("$COL_ID = ?")
|
||||
.whereArgs(obj.id)
|
||||
.build()
|
||||
|
||||
override fun mapToContentValues(obj: SearchTag) = contentValuesOf(
|
||||
COL_ID to obj.id,
|
||||
COL_MANGA_ID to obj.mangaId,
|
||||
COL_NAMESPACE to obj.namespace,
|
||||
COL_NAME to obj.name,
|
||||
COL_TYPE to obj.type,
|
||||
)
|
||||
}
|
||||
|
||||
class SearchTagGetResolver : DefaultGetResolver<SearchTag>() {
|
||||
|
||||
override fun mapFromCursor(cursor: Cursor): SearchTag = SearchTag(
|
||||
id = cursor.getLong(cursor.getColumnIndexOrThrow(COL_ID)),
|
||||
mangaId = cursor.getLong(cursor.getColumnIndexOrThrow(COL_MANGA_ID)),
|
||||
namespace = cursor.getString(cursor.getColumnIndexOrThrow(COL_NAMESPACE)),
|
||||
name = cursor.getString(cursor.getColumnIndexOrThrow(COL_NAME)),
|
||||
type = cursor.getInt(cursor.getColumnIndexOrThrow(COL_TYPE)),
|
||||
)
|
||||
}
|
||||
|
||||
class SearchTagDeleteResolver : DefaultDeleteResolver<SearchTag>() {
|
||||
|
||||
override fun mapToDeleteQuery(obj: SearchTag) = DeleteQuery.builder()
|
||||
.table(TABLE)
|
||||
.where("$COL_ID = ?")
|
||||
.whereArgs(obj.id)
|
||||
.build()
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
package exh.metadata.sql.mappers
|
||||
|
||||
import android.database.Cursor
|
||||
import androidx.core.content.contentValuesOf
|
||||
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.metadata.sql.models.SearchTitle
|
||||
import exh.metadata.sql.tables.SearchTitleTable.COL_ID
|
||||
import exh.metadata.sql.tables.SearchTitleTable.COL_MANGA_ID
|
||||
import exh.metadata.sql.tables.SearchTitleTable.COL_TITLE
|
||||
import exh.metadata.sql.tables.SearchTitleTable.COL_TYPE
|
||||
import exh.metadata.sql.tables.SearchTitleTable.TABLE
|
||||
|
||||
class SearchTitleTypeMapping : SQLiteTypeMapping<SearchTitle>(
|
||||
SearchTitlePutResolver(),
|
||||
SearchTitleGetResolver(),
|
||||
SearchTitleDeleteResolver(),
|
||||
)
|
||||
|
||||
class SearchTitlePutResolver : DefaultPutResolver<SearchTitle>() {
|
||||
|
||||
override fun mapToInsertQuery(obj: SearchTitle) = InsertQuery.builder()
|
||||
.table(TABLE)
|
||||
.build()
|
||||
|
||||
override fun mapToUpdateQuery(obj: SearchTitle) = UpdateQuery.builder()
|
||||
.table(TABLE)
|
||||
.where("$COL_ID = ?")
|
||||
.whereArgs(obj.id)
|
||||
.build()
|
||||
|
||||
override fun mapToContentValues(obj: SearchTitle) = contentValuesOf(
|
||||
COL_ID to obj.id,
|
||||
COL_MANGA_ID to obj.mangaId,
|
||||
COL_TITLE to obj.title,
|
||||
COL_TYPE to obj.type,
|
||||
)
|
||||
}
|
||||
|
||||
class SearchTitleGetResolver : DefaultGetResolver<SearchTitle>() {
|
||||
|
||||
override fun mapFromCursor(cursor: Cursor): SearchTitle = SearchTitle(
|
||||
id = cursor.getLong(cursor.getColumnIndexOrThrow(COL_ID)),
|
||||
mangaId = cursor.getLong(cursor.getColumnIndexOrThrow(COL_MANGA_ID)),
|
||||
title = cursor.getString(cursor.getColumnIndexOrThrow(COL_TITLE)),
|
||||
type = cursor.getInt(cursor.getColumnIndexOrThrow(COL_TYPE)),
|
||||
)
|
||||
}
|
||||
|
||||
class SearchTitleDeleteResolver : DefaultDeleteResolver<SearchTitle>() {
|
||||
|
||||
override fun mapToDeleteQuery(obj: SearchTitle) = DeleteQuery.builder()
|
||||
.table(TABLE)
|
||||
.where("$COL_ID = ?")
|
||||
.whereArgs(obj.id)
|
||||
.build()
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
package exh.metadata.sql.queries
|
||||
|
||||
import com.pushtorefresh.storio.sqlite.queries.DeleteQuery
|
||||
import com.pushtorefresh.storio.sqlite.queries.Query
|
||||
import eu.kanade.tachiyomi.data.database.DbProvider
|
||||
import exh.metadata.sql.models.SearchMetadata
|
||||
import exh.metadata.sql.tables.SearchMetadataTable
|
||||
|
||||
interface SearchMetadataQueries : DbProvider {
|
||||
|
||||
fun getSearchMetadataForManga(mangaId: Long) = db.get()
|
||||
.`object`(SearchMetadata::class.java)
|
||||
.withQuery(
|
||||
Query.builder()
|
||||
.table(SearchMetadataTable.TABLE)
|
||||
.where("${SearchMetadataTable.COL_MANGA_ID} = ?")
|
||||
.whereArgs(mangaId)
|
||||
.build(),
|
||||
)
|
||||
.prepare()
|
||||
|
||||
fun getSearchMetadata() = db.get()
|
||||
.listOfObjects(SearchMetadata::class.java)
|
||||
.withQuery(
|
||||
Query.builder()
|
||||
.table(SearchMetadataTable.TABLE)
|
||||
.build(),
|
||||
)
|
||||
.prepare()
|
||||
|
||||
fun getSearchMetadataByIndexedExtra(extra: String) = db.get()
|
||||
.listOfObjects(SearchMetadata::class.java)
|
||||
.withQuery(
|
||||
Query.builder()
|
||||
.table(SearchMetadataTable.TABLE)
|
||||
.where("${SearchMetadataTable.COL_INDEXED_EXTRA} = ?")
|
||||
.whereArgs(extra)
|
||||
.build(),
|
||||
)
|
||||
.prepare()
|
||||
|
||||
fun insertSearchMetadata(metadata: SearchMetadata) = db.put().`object`(metadata).prepare()
|
||||
|
||||
fun deleteSearchMetadata(metadata: SearchMetadata) = db.delete().`object`(metadata).prepare()
|
||||
|
||||
fun deleteAllSearchMetadata() = db.delete().byQuery(
|
||||
DeleteQuery.builder()
|
||||
.table(SearchMetadataTable.TABLE)
|
||||
.build(),
|
||||
)
|
||||
.prepare()
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
package exh.metadata.sql.queries
|
||||
|
||||
import com.pushtorefresh.storio.sqlite.queries.DeleteQuery
|
||||
import com.pushtorefresh.storio.sqlite.queries.Query
|
||||
import eu.kanade.tachiyomi.data.database.DbProvider
|
||||
import eu.kanade.tachiyomi.data.database.inTransaction
|
||||
import exh.metadata.sql.models.SearchTag
|
||||
import exh.metadata.sql.tables.SearchTagTable
|
||||
|
||||
interface SearchTagQueries : DbProvider {
|
||||
fun getSearchTagsForManga(mangaId: Long) = db.get()
|
||||
.listOfObjects(SearchTag::class.java)
|
||||
.withQuery(
|
||||
Query.builder()
|
||||
.table(SearchTagTable.TABLE)
|
||||
.where("${SearchTagTable.COL_MANGA_ID} = ?")
|
||||
.whereArgs(mangaId)
|
||||
.build(),
|
||||
)
|
||||
.prepare()
|
||||
|
||||
fun deleteSearchTagsForManga(mangaId: Long) = db.delete()
|
||||
.byQuery(
|
||||
DeleteQuery.builder()
|
||||
.table(SearchTagTable.TABLE)
|
||||
.where("${SearchTagTable.COL_MANGA_ID} = ?")
|
||||
.whereArgs(mangaId)
|
||||
.build(),
|
||||
)
|
||||
.prepare()
|
||||
|
||||
fun insertSearchTag(searchTag: SearchTag) = db.put().`object`(searchTag).prepare()
|
||||
|
||||
fun insertSearchTags(searchTags: List<SearchTag>) = db.put().objects(searchTags).prepare()
|
||||
|
||||
fun deleteSearchTag(searchTag: SearchTag) = db.delete().`object`(searchTag).prepare()
|
||||
|
||||
fun deleteAllSearchTags() = db.delete().byQuery(
|
||||
DeleteQuery.builder()
|
||||
.table(SearchTagTable.TABLE)
|
||||
.build(),
|
||||
)
|
||||
.prepare()
|
||||
|
||||
fun setSearchTagsForManga(mangaId: Long, tags: List<SearchTag>) {
|
||||
db.inTransaction {
|
||||
deleteSearchTagsForManga(mangaId).executeAsBlocking()
|
||||
tags.chunked(100) { chunk ->
|
||||
insertSearchTags(chunk).executeAsBlocking()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
package exh.metadata.sql.queries
|
||||
|
||||
import com.pushtorefresh.storio.sqlite.queries.DeleteQuery
|
||||
import com.pushtorefresh.storio.sqlite.queries.Query
|
||||
import eu.kanade.tachiyomi.data.database.DbProvider
|
||||
import eu.kanade.tachiyomi.data.database.inTransaction
|
||||
import exh.metadata.sql.models.SearchTitle
|
||||
import exh.metadata.sql.tables.SearchTitleTable
|
||||
|
||||
interface SearchTitleQueries : DbProvider {
|
||||
fun getSearchTitlesForManga(mangaId: Long) = db.get()
|
||||
.listOfObjects(SearchTitle::class.java)
|
||||
.withQuery(
|
||||
Query.builder()
|
||||
.table(SearchTitleTable.TABLE)
|
||||
.where("${SearchTitleTable.COL_MANGA_ID} = ?")
|
||||
.whereArgs(mangaId)
|
||||
.build(),
|
||||
)
|
||||
.prepare()
|
||||
|
||||
fun deleteSearchTitlesForManga(mangaId: Long) = db.delete()
|
||||
.byQuery(
|
||||
DeleteQuery.builder()
|
||||
.table(SearchTitleTable.TABLE)
|
||||
.where("${SearchTitleTable.COL_MANGA_ID} = ?")
|
||||
.whereArgs(mangaId)
|
||||
.build(),
|
||||
)
|
||||
.prepare()
|
||||
|
||||
fun insertSearchTitle(searchTitle: SearchTitle) = db.put().`object`(searchTitle).prepare()
|
||||
|
||||
fun insertSearchTitles(searchTitles: List<SearchTitle>) = db.put().objects(searchTitles).prepare()
|
||||
|
||||
fun deleteSearchTitle(searchTitle: SearchTitle) = db.delete().`object`(searchTitle).prepare()
|
||||
|
||||
fun deleteAllSearchTitle() = db.delete().byQuery(
|
||||
DeleteQuery.builder()
|
||||
.table(SearchTitleTable.TABLE)
|
||||
.build(),
|
||||
)
|
||||
.prepare()
|
||||
|
||||
fun setSearchTitlesForManga(mangaId: Long, titles: List<SearchTitle>) {
|
||||
db.inTransaction {
|
||||
deleteSearchTitlesForManga(mangaId).executeAsBlocking()
|
||||
titles.chunked(100) { chunk ->
|
||||
insertSearchTitles(chunk).executeAsBlocking()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package exh.metadata.sql.tables
|
||||
|
||||
object SearchMetadataTable {
|
||||
const val TABLE = "search_metadata"
|
||||
|
||||
const val COL_MANGA_ID = "manga_id"
|
||||
|
||||
const val COL_UPLOADER = "uploader"
|
||||
|
||||
const val COL_EXTRA = "extra"
|
||||
|
||||
const val COL_INDEXED_EXTRA = "indexed_extra"
|
||||
|
||||
const val COL_EXTRA_VERSION = "extra_version"
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package exh.metadata.sql.tables
|
||||
|
||||
object SearchTagTable {
|
||||
const val TABLE = "search_tags"
|
||||
|
||||
const val COL_ID = "_id"
|
||||
|
||||
const val COL_MANGA_ID = "manga_id"
|
||||
|
||||
const val COL_NAMESPACE = "namespace"
|
||||
|
||||
const val COL_NAME = "name"
|
||||
|
||||
const val COL_TYPE = "type"
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package exh.metadata.sql.tables
|
||||
|
||||
object SearchTitleTable {
|
||||
const val TABLE = "search_titles"
|
||||
|
||||
const val COL_ID = "_id"
|
||||
|
||||
const val COL_MANGA_ID = "manga_id"
|
||||
|
||||
const val COL_TITLE = "title"
|
||||
|
||||
const val COL_TYPE = "type"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package exh.recs
|
||||
|
||||
import eu.kanade.domain.manga.interactor.GetMangaById
|
||||
import eu.kanade.domain.manga.interactor.GetManga
|
||||
import eu.kanade.domain.manga.model.Manga
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourcePresenter
|
||||
@@ -15,13 +15,13 @@ import uy.kohesive.injekt.api.get
|
||||
class RecommendsPresenter(
|
||||
val mangaId: Long,
|
||||
sourceId: Long,
|
||||
private val getMangaById: GetMangaById = Injekt.get(),
|
||||
private val getManga: GetManga = Injekt.get(),
|
||||
) : BrowseSourcePresenter(sourceId) {
|
||||
|
||||
var manga: Manga? = null
|
||||
|
||||
override fun createPager(query: String, filters: FilterList): Pager {
|
||||
this.manga = runBlocking { getMangaById.await(mangaId) }
|
||||
this.manga = runBlocking { getManga.await(mangaId) }
|
||||
return RecommendsPager(manga!!)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
package exh.search
|
||||
|
||||
import exh.metadata.sql.tables.SearchMetadataTable
|
||||
import exh.metadata.sql.tables.SearchTagTable
|
||||
import exh.metadata.sql.tables.SearchTitleTable
|
||||
import java.util.Locale
|
||||
|
||||
class SearchEngine {
|
||||
@@ -23,16 +20,16 @@ class SearchEngine {
|
||||
val params = mutableListOf<String>()
|
||||
it.joinToString(separator = " OR ", prefix = "(", postfix = ")") { q ->
|
||||
params += q
|
||||
"${SearchTagTable.TABLE}.${SearchTagTable.COL_NAME} LIKE ?"
|
||||
"search_tags.name LIKE ?"
|
||||
} to params
|
||||
}
|
||||
return when {
|
||||
namespace != null -> {
|
||||
var query =
|
||||
"""
|
||||
(SELECT ${SearchTagTable.COL_MANGA_ID} AS $COL_MANGA_ID FROM ${SearchTagTable.TABLE}
|
||||
WHERE ${SearchTagTable.COL_NAMESPACE} IS NOT NULL
|
||||
AND ${SearchTagTable.COL_NAMESPACE} LIKE ?
|
||||
(SELECT ${"manga_id"} AS $COL_MANGA_ID FROM ${"search_tags"}
|
||||
WHERE ${"namespace"} IS NOT NULL
|
||||
AND ${"namespace"} LIKE ?
|
||||
""".trimIndent()
|
||||
val params = mutableListOf(escapeLike(namespace))
|
||||
if (componentTagQuery != null) {
|
||||
@@ -46,14 +43,14 @@ class SearchEngine {
|
||||
// Match title + tags
|
||||
val tagQuery =
|
||||
"""
|
||||
SELECT ${SearchTagTable.COL_MANGA_ID} AS $COL_MANGA_ID FROM ${SearchTagTable.TABLE}
|
||||
SELECT ${"manga_id"} AS $COL_MANGA_ID FROM ${"search_tags"}
|
||||
WHERE ${componentTagQuery!!.first}
|
||||
""".trimIndent() to componentTagQuery.second
|
||||
|
||||
val titleQuery =
|
||||
"""
|
||||
SELECT ${SearchTitleTable.COL_MANGA_ID} AS $COL_MANGA_ID FROM ${SearchTitleTable.TABLE}
|
||||
WHERE ${SearchTitleTable.COL_TITLE} LIKE ?
|
||||
SELECT ${"manga_id"} AS $COL_MANGA_ID FROM ${"search_titles"}
|
||||
WHERE ${"title"} LIKE ?
|
||||
""".trimIndent() to listOf(component.asLenientTitleQuery())
|
||||
|
||||
"(${tagQuery.first} UNION ${titleQuery.first})".trimIndent() to
|
||||
@@ -75,7 +72,7 @@ class SearchEngine {
|
||||
textToSubQueries(null, component)
|
||||
} else if (component is Namespace) {
|
||||
if (component.namespace == "uploader") {
|
||||
wheres += "meta.${SearchMetadataTable.COL_UPLOADER} LIKE ?"
|
||||
wheres += "meta.uploader LIKE ?"
|
||||
whereParams += component.tag!!.rawTextEscapedForLike()
|
||||
null
|
||||
} else {
|
||||
@@ -97,15 +94,15 @@ class SearchEngine {
|
||||
val completeParams = mutableListOf<String>()
|
||||
var baseQuery =
|
||||
"""
|
||||
SELECT ${SearchMetadataTable.COL_MANGA_ID}
|
||||
FROM ${SearchMetadataTable.TABLE} meta
|
||||
SELECT ${"manga_id"}
|
||||
FROM ${"search_metadata"} meta
|
||||
""".trimIndent()
|
||||
|
||||
include.forEachIndexed { index, pair ->
|
||||
baseQuery += "\n" + (
|
||||
"""
|
||||
INNER JOIN ${pair.first} i$index
|
||||
ON i$index.$COL_MANGA_ID = meta.${SearchMetadataTable.COL_MANGA_ID}
|
||||
ON i$index.$COL_MANGA_ID = meta.${"manga_id"}
|
||||
""".trimIndent()
|
||||
)
|
||||
completeParams += pair.second
|
||||
@@ -113,7 +110,7 @@ class SearchEngine {
|
||||
|
||||
exclude.forEach {
|
||||
wheres += """
|
||||
(meta.${SearchMetadataTable.COL_MANGA_ID} NOT IN ${it.first})
|
||||
(meta.${"manga_id"} NOT IN ${it.first})
|
||||
""".trimIndent()
|
||||
whereParams += it.second
|
||||
}
|
||||
@@ -122,7 +119,7 @@ class SearchEngine {
|
||||
baseQuery += "\nWHERE\n"
|
||||
baseQuery += wheres.joinToString("\nAND\n")
|
||||
}
|
||||
baseQuery += "\nORDER BY ${SearchMetadataTable.COL_MANGA_ID}"
|
||||
baseQuery += "\nORDER BY manga_id"
|
||||
|
||||
return baseQuery to completeParams
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package exh.smartsearch
|
||||
|
||||
import eu.kanade.data.DatabaseHandler
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||
@@ -18,6 +19,7 @@ class SmartSearchEngine(
|
||||
private val extraSearchParams: String? = null,
|
||||
) {
|
||||
private val db: DatabaseHelper by injectLazy()
|
||||
private val handler: DatabaseHandler by injectLazy()
|
||||
|
||||
private val normalizedLevenshtein = NormalizedLevenshtein()
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import android.view.View
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import dev.chrisbanes.insetter.applyInsetter
|
||||
import eu.kanade.domain.manga.interactor.GetMangaById
|
||||
import eu.kanade.domain.manga.interactor.GetManga
|
||||
import eu.kanade.domain.manga.model.Manga
|
||||
import eu.kanade.tachiyomi.databinding.MetadataViewControllerBinding
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
@@ -29,7 +29,7 @@ class MetadataViewController : NucleusController<MetadataViewControllerBinding,
|
||||
}
|
||||
|
||||
constructor(mangaId: Long) : this(
|
||||
runBlocking { Injekt.get<GetMangaById>().await(mangaId)!! },
|
||||
runBlocking { Injekt.get<GetManga>().await(mangaId)!! },
|
||||
)
|
||||
|
||||
@Suppress("unused")
|
||||
|
||||
Reference in New Issue
Block a user