Use SQLDelight for all Manga related queries (#7447)
(cherry picked from commit 17951cfd68159d083df54c3e03094d8d66fe02ec) # 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:
parent
0c89c4cd64
commit
ea38ffc53e
@ -148,6 +148,7 @@ dependencies {
|
||||
implementation(androidx.paging.runtime)
|
||||
implementation(androidx.paging.compose)
|
||||
|
||||
implementation(libs.bundles.sqlite)
|
||||
implementation(androidx.sqlite)
|
||||
implementation(libs.sqldelight.android.driver)
|
||||
implementation(libs.sqldelight.coroutines)
|
||||
@ -201,11 +202,6 @@ dependencies {
|
||||
implementation(libs.unifile)
|
||||
implementation(libs.junrar)
|
||||
|
||||
// Database
|
||||
implementation(libs.bundles.sqlite)
|
||||
implementation("com.github.inorichi.storio:storio-common:8be19de@aar")
|
||||
implementation("com.github.inorichi.storio:storio-sqlite:8be19de@aar")
|
||||
|
||||
// Preferences
|
||||
implementation(libs.preferencektx)
|
||||
implementation(libs.flowpreferences)
|
||||
|
@ -91,9 +91,5 @@ class AndroidDatabaseHandler(
|
||||
|
||||
// SY -->
|
||||
fun getLibraryQuery() = LibraryQuery(driver)
|
||||
|
||||
fun rawQuery(query: (SqlDriver) -> Unit) {
|
||||
return query(driver)
|
||||
}
|
||||
// SY <--
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
package eu.kanade.data.manga
|
||||
|
||||
import eu.kanade.data.listOfStringsAndAdapter
|
||||
import eu.kanade.domain.chapter.model.Chapter
|
||||
import eu.kanade.domain.manga.model.Manga
|
||||
import eu.kanade.tachiyomi.data.database.models.LibraryManga
|
||||
|
||||
val mangaMapper: (Long, Long, String, String?, String?, String?, List<String>?, String, Long, String?, Boolean, Long?, Long?, Boolean, Long, Long, Long, Long, List<String>?) -> Manga =
|
||||
{ id, source, url, artist, author, description, genre, title, status, thumbnailUrl, favorite, lastUpdate, _, initialized, viewer, chapterFlags, coverLastModified, dateAdded, filteredScanlators ->
|
||||
@ -71,3 +73,30 @@ val mangaChapterMapper: (Long, Long, String, String?, String?, String?, List<Str
|
||||
scanlator = scanlator,
|
||||
)
|
||||
}
|
||||
|
||||
val libraryManga: (Long, Long, String, String?, String?, String?, List<String>?, String, Long, String?, Boolean, Long?, Long?, Boolean, Long, Long, Long, Long, List<String>?, Long, Long, Long) -> LibraryManga =
|
||||
{ _id, source, url, artist, author, description, genre, title, status, thumbnail_url, favorite, last_update, next_update, initialized, viewer, chapter_flags, cover_last_modified, date_added, filtered_scanlators, unread_count, read_count, category ->
|
||||
LibraryManga().apply {
|
||||
this.id = _id
|
||||
this.source = source
|
||||
this.url = url
|
||||
this.artist = artist
|
||||
this.author = author
|
||||
this.description = description
|
||||
this.genre = genre?.joinToString()
|
||||
this.title = title
|
||||
this.status = status.toInt()
|
||||
this.thumbnail_url = thumbnail_url
|
||||
this.favorite = favorite
|
||||
this.last_update = last_update ?: 0
|
||||
this.initialized = initialized
|
||||
this.viewer_flags = viewer.toInt()
|
||||
this.chapter_flags = chapter_flags.toInt()
|
||||
this.cover_last_modified = cover_last_modified
|
||||
this.date_added = date_added
|
||||
this.filtered_scanlators = filtered_scanlators?.let(listOfStringsAndAdapter::encode)
|
||||
this.unreadCount = unread_count.toInt()
|
||||
this.readCount = read_count.toInt()
|
||||
this.category = category.toInt()
|
||||
}
|
||||
}
|
||||
|
@ -72,4 +72,57 @@ class MangaMergeRepositoryImpl(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun insert(reference: MergedMangaReference): Long? {
|
||||
return handler.awaitOneOrNull {
|
||||
mergedQueries.insert(
|
||||
infoManga = reference.isInfoManga,
|
||||
getChapterUpdates = reference.getChapterUpdates,
|
||||
chapterSortMode = reference.chapterSortMode.toLong(),
|
||||
chapterPriority = reference.chapterPriority.toLong(),
|
||||
downloadChapters = reference.downloadChapters,
|
||||
mergeId = reference.mergeId!!,
|
||||
mergeUrl = reference.mergeUrl,
|
||||
mangaId = reference.mangaId,
|
||||
mangaUrl = reference.mangaUrl,
|
||||
mangaSource = reference.mangaSourceId,
|
||||
)
|
||||
mergedQueries.selectLastInsertedRowId()
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun insertAll(references: List<MergedMangaReference>) {
|
||||
handler.await(true) {
|
||||
references.forEach { reference ->
|
||||
mergedQueries.insert(
|
||||
infoManga = reference.isInfoManga,
|
||||
getChapterUpdates = reference.getChapterUpdates,
|
||||
chapterSortMode = reference.chapterSortMode.toLong(),
|
||||
chapterPriority = reference.chapterPriority.toLong(),
|
||||
downloadChapters = reference.downloadChapters,
|
||||
mergeId = reference.mergeId!!,
|
||||
mergeUrl = reference.mergeUrl,
|
||||
mangaId = reference.mangaId,
|
||||
mangaUrl = reference.mangaUrl,
|
||||
mangaSource = reference.mangaSourceId,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun deleteById(id: Long) {
|
||||
handler.await {
|
||||
mergedQueries.deleteById(id)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun deleteByMergeId(mergeId: Long) {
|
||||
handler.await {
|
||||
mergedQueries.deleteByMergeId(mergeId)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getMergeMangaForDownloading(mergeId: Long): List<Manga> {
|
||||
return handler.awaitList { mergedQueries.selectMergedMangasForDownloadingById(mergeId, mangaMapper) }
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package eu.kanade.data.manga
|
||||
|
||||
import eu.kanade.data.AndroidDatabaseHandler
|
||||
import eu.kanade.data.DatabaseHandler
|
||||
import eu.kanade.data.listOfStringsAdapter
|
||||
import eu.kanade.data.listOfStringsAndAdapter
|
||||
@ -7,6 +8,7 @@ import eu.kanade.data.toLong
|
||||
import eu.kanade.domain.manga.model.Manga
|
||||
import eu.kanade.domain.manga.model.MangaUpdate
|
||||
import eu.kanade.domain.manga.repository.MangaRepository
|
||||
import eu.kanade.tachiyomi.data.database.models.LibraryManga
|
||||
import eu.kanade.tachiyomi.util.system.logcat
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import logcat.LogPriority
|
||||
@ -19,26 +21,28 @@ class MangaRepositoryImpl(
|
||||
return handler.awaitOne { mangasQueries.getMangaById(id, mangaMapper) }
|
||||
}
|
||||
|
||||
override suspend fun subscribeMangaById(id: Long): Flow<Manga> {
|
||||
return handler.subscribeToOne { mangasQueries.getMangaById(id, mangaMapper) }
|
||||
}
|
||||
|
||||
override suspend fun getMangaByIdAsFlow(id: Long): Flow<Manga> {
|
||||
return handler.subscribeToOne { mangasQueries.getMangaById(id, mangaMapper) }
|
||||
}
|
||||
|
||||
override suspend fun getMangaByUrlAndSource(url: String, sourceId: Long): Manga? {
|
||||
override suspend fun getMangaByUrlAndSourceId(url: String, sourceId: Long): Manga? {
|
||||
return handler.awaitOneOrNull { mangasQueries.getMangaByUrlAndSource(url, sourceId, mangaMapper) }
|
||||
}
|
||||
|
||||
override suspend fun subscribeMangaByUrlAndSource(url: String, sourceId: Long): Flow<Manga?> {
|
||||
return handler.subscribeToOneOrNull { mangasQueries.getMangaByUrlAndSource(url, sourceId, mangaMapper) }
|
||||
}
|
||||
|
||||
override suspend fun getFavorites(): List<Manga> {
|
||||
return handler.awaitList { mangasQueries.getFavorites(mangaMapper) }
|
||||
}
|
||||
|
||||
override suspend fun getLibraryManga(): List<LibraryManga> {
|
||||
return handler.awaitList { (handler as AndroidDatabaseHandler).getLibraryQuery() }
|
||||
// return handler.awaitList { mangasQueries.getLibrary(libraryManga) }
|
||||
}
|
||||
|
||||
override fun getLibraryMangaAsFlow(): Flow<List<LibraryManga>> {
|
||||
return handler.subscribeToList { (handler as AndroidDatabaseHandler).getLibraryQuery() }
|
||||
// return handler.subscribeToList { mangasQueries.getLibrary(libraryManga) }
|
||||
}
|
||||
|
||||
override fun getFavoritesBySourceId(sourceId: Long): Flow<List<Manga>> {
|
||||
return handler.subscribeToList { mangasQueries.getFavoriteBySourceId(sourceId, mangaMapper) }
|
||||
}
|
||||
@ -68,6 +72,31 @@ class MangaRepositoryImpl(
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun insert(manga: Manga): Long? {
|
||||
return handler.awaitOneOrNull {
|
||||
mangasQueries.insert(
|
||||
source = manga.source,
|
||||
url = manga.url,
|
||||
artist = manga.artist,
|
||||
author = manga.author,
|
||||
description = manga.description,
|
||||
genre = manga.genre,
|
||||
title = manga.title,
|
||||
status = manga.status,
|
||||
thumbnail_url = manga.thumbnailUrl,
|
||||
favorite = manga.favorite,
|
||||
last_update = manga.lastUpdate,
|
||||
next_update = null,
|
||||
initialized = manga.initialized,
|
||||
viewer = manga.viewerFlags,
|
||||
chapter_flags = manga.chapterFlags,
|
||||
cover_last_modified = manga.coverLastModified,
|
||||
date_added = manga.dateAdded,
|
||||
)
|
||||
mangasQueries.selectLastInsertedRowId()
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun update(update: MangaUpdate): Boolean {
|
||||
return try {
|
||||
partialUpdate(update)
|
||||
@ -115,11 +144,15 @@ class MangaRepositoryImpl(
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getMangaBySource(sourceId: Long): List<Manga> {
|
||||
override suspend fun getMangaBySourceId(sourceId: Long): List<Manga> {
|
||||
return handler.awaitList { mangasQueries.getBySource(sourceId, mangaMapper) }
|
||||
}
|
||||
|
||||
override suspend fun getAll(): List<Manga> {
|
||||
return handler.awaitList { mangasQueries.getAll(mangaMapper) }
|
||||
}
|
||||
|
||||
override suspend fun deleteManga(mangaId: Long) {
|
||||
handler.await { mangasQueries.deleteById(mangaId) }
|
||||
}
|
||||
}
|
||||
|
@ -32,10 +32,13 @@ import eu.kanade.domain.history.interactor.UpsertHistory
|
||||
import eu.kanade.domain.history.repository.HistoryRepository
|
||||
import eu.kanade.domain.manga.interactor.GetDuplicateLibraryManga
|
||||
import eu.kanade.domain.manga.interactor.GetFavorites
|
||||
import eu.kanade.domain.manga.interactor.GetLibraryManga
|
||||
import eu.kanade.domain.manga.interactor.GetManga
|
||||
import eu.kanade.domain.manga.interactor.GetMangaWithChapters
|
||||
import eu.kanade.domain.manga.interactor.InsertManga
|
||||
import eu.kanade.domain.manga.interactor.ResetViewerFlags
|
||||
import eu.kanade.domain.manga.interactor.SetMangaChapterFlags
|
||||
import eu.kanade.domain.manga.interactor.SetMangaViewerFlags
|
||||
import eu.kanade.domain.manga.interactor.UpdateManga
|
||||
import eu.kanade.domain.manga.repository.MangaRepository
|
||||
import eu.kanade.domain.source.interactor.GetEnabledSources
|
||||
@ -71,11 +74,14 @@ class DomainModule : InjektModule {
|
||||
addSingletonFactory<MangaRepository> { MangaRepositoryImpl(get()) }
|
||||
addFactory { GetDuplicateLibraryManga(get()) }
|
||||
addFactory { GetFavorites(get()) }
|
||||
addFactory { GetLibraryManga(get()) }
|
||||
addFactory { GetMangaWithChapters(get(), get()) }
|
||||
addFactory { GetManga(get()) }
|
||||
addFactory { GetNextChapter(get()) }
|
||||
addFactory { ResetViewerFlags(get()) }
|
||||
addFactory { SetMangaChapterFlags(get()) }
|
||||
addFactory { SetMangaViewerFlags(get()) }
|
||||
addFactory { InsertManga(get()) }
|
||||
addFactory { UpdateManga(get()) }
|
||||
addFactory { SetMangaCategories(get()) }
|
||||
|
||||
|
@ -3,8 +3,12 @@ package eu.kanade.domain
|
||||
import eu.kanade.data.manga.FavoritesEntryRepositoryImpl
|
||||
import eu.kanade.data.manga.MangaMergeRepositoryImpl
|
||||
import eu.kanade.data.manga.MangaMetadataRepositoryImpl
|
||||
import eu.kanade.domain.chapter.interactor.DeleteChapters
|
||||
import eu.kanade.domain.chapter.interactor.GetMergedChapterByMangaId
|
||||
import eu.kanade.domain.manga.interactor.DeleteByMergeId
|
||||
import eu.kanade.domain.manga.interactor.DeleteFavoriteEntries
|
||||
import eu.kanade.domain.manga.interactor.DeleteMangaById
|
||||
import eu.kanade.domain.manga.interactor.DeleteMergeById
|
||||
import eu.kanade.domain.manga.interactor.GetAllManga
|
||||
import eu.kanade.domain.manga.interactor.GetExhFavoriteMangaWithMetadata
|
||||
import eu.kanade.domain.manga.interactor.GetFavoriteEntries
|
||||
@ -13,12 +17,15 @@ import eu.kanade.domain.manga.interactor.GetIdsOfFavoriteMangaWithMetadata
|
||||
import eu.kanade.domain.manga.interactor.GetMangaBySource
|
||||
import eu.kanade.domain.manga.interactor.GetMergedManga
|
||||
import eu.kanade.domain.manga.interactor.GetMergedMangaById
|
||||
import eu.kanade.domain.manga.interactor.GetMergedMangaForDownloading
|
||||
import eu.kanade.domain.manga.interactor.GetMergedReferencesById
|
||||
import eu.kanade.domain.manga.interactor.GetSearchTags
|
||||
import eu.kanade.domain.manga.interactor.GetSearchTitles
|
||||
import eu.kanade.domain.manga.interactor.InsertFavoriteEntries
|
||||
import eu.kanade.domain.manga.interactor.InsertFlatMetadata
|
||||
import eu.kanade.domain.manga.interactor.InsertMergedReference
|
||||
import eu.kanade.domain.manga.interactor.SetMangaFilteredScanlators
|
||||
import eu.kanade.domain.manga.interactor.UpdateMergedSettings
|
||||
import eu.kanade.domain.manga.repository.FavoritesEntryRepository
|
||||
import eu.kanade.domain.manga.repository.MangaMergeRepository
|
||||
import eu.kanade.domain.manga.repository.MangaMetadataRepository
|
||||
@ -44,6 +51,8 @@ class SYDomainModule : InjektModule {
|
||||
addFactory { SetMangaFilteredScanlators(get()) }
|
||||
addFactory { GetAllManga(get()) }
|
||||
addFactory { GetMangaBySource(get()) }
|
||||
addFactory { DeleteChapters(get()) }
|
||||
addFactory { DeleteMangaById(get()) }
|
||||
|
||||
addSingletonFactory<MangaMetadataRepository> { MangaMetadataRepositoryImpl(get()) }
|
||||
addFactory { GetFlatMetadataById(get()) }
|
||||
@ -58,6 +67,11 @@ class SYDomainModule : InjektModule {
|
||||
addFactory { GetMergedMangaById(get()) }
|
||||
addFactory { GetMergedReferencesById(get()) }
|
||||
addFactory { GetMergedChapterByMangaId(get()) }
|
||||
addFactory { InsertMergedReference(get()) }
|
||||
addFactory { UpdateMergedSettings(get()) }
|
||||
addFactory { DeleteByMergeId(get()) }
|
||||
addFactory { DeleteMergeById(get()) }
|
||||
addFactory { GetMergedMangaForDownloading(get()) }
|
||||
|
||||
addSingletonFactory<FavoritesEntryRepository> { FavoritesEntryRepositoryImpl(get()) }
|
||||
addFactory { GetFavoriteEntries(get()) }
|
||||
|
@ -0,0 +1,12 @@
|
||||
package eu.kanade.domain.chapter.interactor
|
||||
|
||||
import eu.kanade.domain.chapter.repository.ChapterRepository
|
||||
|
||||
class DeleteChapters(
|
||||
private val chapterRepository: ChapterRepository,
|
||||
) {
|
||||
|
||||
suspend fun await(chapters: List<Long>) {
|
||||
chapterRepository.removeChaptersWithIds(chapters)
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package eu.kanade.domain.manga.interactor
|
||||
|
||||
import eu.kanade.domain.manga.repository.MangaMergeRepository
|
||||
|
||||
class DeleteByMergeId(
|
||||
private val mangaMergeRepository: MangaMergeRepository,
|
||||
) {
|
||||
|
||||
suspend fun await(id: Long) {
|
||||
return mangaMergeRepository.deleteByMergeId(id)
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package eu.kanade.domain.manga.interactor
|
||||
|
||||
import eu.kanade.domain.manga.repository.MangaRepository
|
||||
|
||||
class DeleteMangaById(
|
||||
private val mangaRepository: MangaRepository,
|
||||
) {
|
||||
|
||||
suspend fun await(id: Long) {
|
||||
return mangaRepository.deleteManga(id)
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package eu.kanade.domain.manga.interactor
|
||||
|
||||
import eu.kanade.domain.manga.repository.MangaMergeRepository
|
||||
|
||||
class DeleteMergeById(
|
||||
private val mangaMergeRepository: MangaMergeRepository,
|
||||
) {
|
||||
|
||||
suspend fun await(id: Long) {
|
||||
return mangaMergeRepository.deleteById(id)
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package eu.kanade.domain.manga.interactor
|
||||
|
||||
import eu.kanade.domain.manga.repository.MangaRepository
|
||||
import eu.kanade.tachiyomi.data.database.models.LibraryManga
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
class GetLibraryManga(
|
||||
private val mangaRepository: MangaRepository,
|
||||
) {
|
||||
|
||||
suspend fun await(): List<LibraryManga> {
|
||||
return mangaRepository.getLibraryManga()
|
||||
}
|
||||
|
||||
fun subscribe(): Flow<List<LibraryManga>> {
|
||||
return mangaRepository.getLibraryMangaAsFlow()
|
||||
}
|
||||
}
|
@ -20,19 +20,10 @@ class GetManga(
|
||||
}
|
||||
|
||||
suspend fun subscribe(id: Long): Flow<Manga> {
|
||||
return mangaRepository.subscribeMangaById(id)
|
||||
return mangaRepository.getMangaByIdAsFlow(id)
|
||||
}
|
||||
|
||||
suspend fun await(url: String, sourceId: Long): Manga? {
|
||||
return try {
|
||||
mangaRepository.getMangaByUrlAndSource(url, sourceId)
|
||||
} catch (e: Exception) {
|
||||
logcat(LogPriority.ERROR, e)
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun subscribe(url: String, sourceId: Long): Flow<Manga?> {
|
||||
return mangaRepository.subscribeMangaByUrlAndSource(url, sourceId)
|
||||
return mangaRepository.getMangaByUrlAndSourceId(url, sourceId)
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,6 @@ class GetMangaBySource(
|
||||
) {
|
||||
|
||||
suspend fun await(sourceId: Long): List<Manga> {
|
||||
return mangaRepository.getMangaBySource(sourceId)
|
||||
return mangaRepository.getMangaBySourceId(sourceId)
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ class GetMangaWithChapters(
|
||||
|
||||
suspend fun subscribe(id: Long): Flow<Pair<Manga, List<Chapter>>> {
|
||||
return combine(
|
||||
mangaRepository.subscribeMangaById(id),
|
||||
mangaRepository.getMangaByIdAsFlow(id),
|
||||
chapterRepository.getChapterByMangaIdAsFlow(id),
|
||||
) { manga, chapters ->
|
||||
Pair(manga, chapters)
|
||||
|
@ -0,0 +1,13 @@
|
||||
package eu.kanade.domain.manga.interactor
|
||||
|
||||
import eu.kanade.domain.manga.model.Manga
|
||||
import eu.kanade.domain.manga.repository.MangaMergeRepository
|
||||
|
||||
class GetMergedMangaForDownloading(
|
||||
private val mangaMergeRepository: MangaMergeRepository,
|
||||
) {
|
||||
|
||||
suspend fun await(mergeId: Long): List<Manga> {
|
||||
return mangaMergeRepository.getMergeMangaForDownloading(mergeId)
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package eu.kanade.domain.manga.interactor
|
||||
|
||||
import eu.kanade.domain.manga.model.Manga
|
||||
import eu.kanade.domain.manga.repository.MangaRepository
|
||||
|
||||
class InsertManga(
|
||||
private val mangaRepository: MangaRepository,
|
||||
) {
|
||||
|
||||
suspend fun await(manga: Manga): Long? {
|
||||
return mangaRepository.insert(manga)
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package eu.kanade.domain.manga.interactor
|
||||
|
||||
import eu.kanade.domain.manga.repository.MangaMergeRepository
|
||||
import exh.merged.sql.models.MergedMangaReference
|
||||
|
||||
class InsertMergedReference(
|
||||
private val mangaMergedRepository: MangaMergeRepository,
|
||||
) {
|
||||
|
||||
suspend fun await(reference: MergedMangaReference): Long? {
|
||||
return mangaMergedRepository.insert(reference)
|
||||
}
|
||||
|
||||
suspend fun awaitAll(references: List<MergedMangaReference>) {
|
||||
mangaMergedRepository.insertAll(references)
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package eu.kanade.domain.manga.interactor
|
||||
|
||||
import eu.kanade.domain.manga.model.MangaUpdate
|
||||
import eu.kanade.domain.manga.repository.MangaRepository
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.OrientationType
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType
|
||||
|
||||
class SetMangaViewerFlags(
|
||||
private val mangaRepository: MangaRepository,
|
||||
) {
|
||||
|
||||
suspend fun awaitSetMangaReadingMode(id: Long, flag: Long) {
|
||||
mangaRepository.update(
|
||||
MangaUpdate(
|
||||
id = id,
|
||||
viewerFlags = flag.setFlag(flag, ReadingModeType.MASK.toLong()),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun awaitSetOrientationType(id: Long, flag: Long) {
|
||||
mangaRepository.update(
|
||||
MangaUpdate(
|
||||
id = id,
|
||||
viewerFlags = flag.setFlag(flag, OrientationType.MASK.toLong()),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun Long.setFlag(flag: Long, mask: Long): Long {
|
||||
return this and mask.inv() or (flag and mask)
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package eu.kanade.domain.manga.interactor
|
||||
|
||||
import eu.kanade.domain.manga.model.MergeMangaSettingsUpdate
|
||||
import eu.kanade.domain.manga.repository.MangaMergeRepository
|
||||
|
||||
class UpdateMergedSettings(
|
||||
private val mangaMergeRepository: MangaMergeRepository,
|
||||
) {
|
||||
|
||||
suspend fun await(mergeUpdate: MergeMangaSettingsUpdate): Boolean {
|
||||
return mangaMergeRepository.updateSettings(mergeUpdate)
|
||||
}
|
||||
|
||||
suspend fun awaitAll(values: List<MergeMangaSettingsUpdate>): Boolean {
|
||||
return mangaMergeRepository.updateAllSettings(values)
|
||||
}
|
||||
}
|
@ -214,6 +214,28 @@ fun Manga.toMangaInfo(): MangaInfo = MangaInfo(
|
||||
// SY <--
|
||||
)
|
||||
|
||||
fun Manga.toMangaUpdate(): MangaUpdate {
|
||||
return MangaUpdate(
|
||||
id = id,
|
||||
source = source,
|
||||
favorite = favorite,
|
||||
lastUpdate = lastUpdate,
|
||||
dateAdded = dateAdded,
|
||||
viewerFlags = viewerFlags,
|
||||
chapterFlags = chapterFlags,
|
||||
coverLastModified = coverLastModified,
|
||||
url = url,
|
||||
title = title,
|
||||
artist = artist,
|
||||
author = author,
|
||||
description = description,
|
||||
genre = genre,
|
||||
status = status,
|
||||
thumbnailUrl = thumbnailUrl,
|
||||
initialized = initialized,
|
||||
)
|
||||
}
|
||||
|
||||
fun Manga.isLocal(): Boolean = source == LocalSource.ID
|
||||
|
||||
fun Manga.hasCustomCover(coverCache: CoverCache = Injekt.get()): Boolean {
|
||||
|
@ -21,4 +21,14 @@ interface MangaMergeRepository {
|
||||
suspend fun updateSettings(update: MergeMangaSettingsUpdate): Boolean
|
||||
|
||||
suspend fun updateAllSettings(values: List<MergeMangaSettingsUpdate>): Boolean
|
||||
|
||||
suspend fun insert(reference: MergedMangaReference): Long?
|
||||
|
||||
suspend fun insertAll(references: List<MergedMangaReference>)
|
||||
|
||||
suspend fun deleteById(id: Long)
|
||||
|
||||
suspend fun deleteByMergeId(mergeId: Long)
|
||||
|
||||
suspend fun getMergeMangaForDownloading(mergeId: Long): List<Manga>
|
||||
}
|
||||
|
@ -2,22 +2,23 @@ package eu.kanade.domain.manga.repository
|
||||
|
||||
import eu.kanade.domain.manga.model.Manga
|
||||
import eu.kanade.domain.manga.model.MangaUpdate
|
||||
import eu.kanade.tachiyomi.data.database.models.LibraryManga
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface MangaRepository {
|
||||
|
||||
suspend fun getMangaById(id: Long): Manga
|
||||
|
||||
suspend fun subscribeMangaById(id: Long): Flow<Manga>
|
||||
|
||||
suspend fun getMangaByIdAsFlow(id: Long): Flow<Manga>
|
||||
|
||||
suspend fun getMangaByUrlAndSource(url: String, sourceId: Long): Manga?
|
||||
|
||||
suspend fun subscribeMangaByUrlAndSource(url: String, sourceId: Long): Flow<Manga?>
|
||||
suspend fun getMangaByUrlAndSourceId(url: String, sourceId: Long): Manga?
|
||||
|
||||
suspend fun getFavorites(): List<Manga>
|
||||
|
||||
suspend fun getLibraryManga(): List<LibraryManga>
|
||||
|
||||
fun getLibraryMangaAsFlow(): Flow<List<LibraryManga>>
|
||||
|
||||
fun getFavoritesBySourceId(sourceId: Long): Flow<List<Manga>>
|
||||
|
||||
suspend fun getDuplicateLibraryManga(title: String, sourceId: Long): Manga?
|
||||
@ -26,11 +27,15 @@ interface MangaRepository {
|
||||
|
||||
suspend fun setMangaCategories(mangaId: Long, categoryIds: List<Long>)
|
||||
|
||||
suspend fun insert(manga: Manga): Long?
|
||||
|
||||
suspend fun update(update: MangaUpdate): Boolean
|
||||
|
||||
suspend fun updateAll(values: List<MangaUpdate>): Boolean
|
||||
|
||||
suspend fun getMangaBySource(sourceId: Long): List<Manga>
|
||||
suspend fun getMangaBySourceId(sourceId: Long): List<Manga>
|
||||
|
||||
suspend fun getAll(): List<Manga>
|
||||
|
||||
suspend fun deleteManga(mangaId: Long)
|
||||
}
|
||||
|
@ -18,7 +18,6 @@ import eu.kanade.data.listOfStringsAdapter
|
||||
import eu.kanade.data.listOfStringsAndAdapter
|
||||
import eu.kanade.tachiyomi.data.cache.ChapterCache
|
||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
import eu.kanade.tachiyomi.data.database.DbOpenCallback
|
||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||
import eu.kanade.tachiyomi.data.library.CustomMangaManager
|
||||
@ -89,8 +88,6 @@ class AppModule(val app: Application) : InjektModule {
|
||||
|
||||
addSingletonFactory { PreferencesHelper(app) }
|
||||
|
||||
addSingletonFactory { DatabaseHelper(get()) }
|
||||
|
||||
addSingletonFactory { ChapterCache(app) }
|
||||
|
||||
addSingletonFactory { CoverCache(app) }
|
||||
@ -125,8 +122,6 @@ class AppModule(val app: Application) : InjektModule {
|
||||
|
||||
get<Database>()
|
||||
|
||||
get<DatabaseHelper>()
|
||||
|
||||
get<DownloadManager>()
|
||||
|
||||
// SY -->
|
||||
|
@ -6,13 +6,16 @@ import eu.kanade.data.DatabaseHandler
|
||||
import eu.kanade.data.manga.mangaMapper
|
||||
import eu.kanade.data.toLong
|
||||
import eu.kanade.domain.manga.interactor.GetFavorites
|
||||
import eu.kanade.domain.manga.interactor.GetFlatMetadataById
|
||||
import eu.kanade.domain.manga.interactor.GetMergedManga
|
||||
import eu.kanade.domain.manga.interactor.InsertFlatMetadata
|
||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.library.CustomMangaManager
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
import exh.metadata.metadata.base.FlatMetadata
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import data.Mangas as DbManga
|
||||
@ -30,6 +33,8 @@ abstract class AbstractBackupManager(protected val context: Context) {
|
||||
// SY -->
|
||||
private val getMergedManga: GetMergedManga = Injekt.get()
|
||||
protected val customMangaManager: CustomMangaManager = Injekt.get()
|
||||
private val insertFlatMetadata: InsertFlatMetadata = Injekt.get()
|
||||
private val getFlatMetadataById: GetFlatMetadataById = Injekt.get()
|
||||
// SY <--
|
||||
|
||||
abstract suspend fun createBackup(uri: Uri, flags: Int, isAutoBackup: Boolean): String
|
||||
@ -65,6 +70,10 @@ abstract class AbstractBackupManager(protected val context: Context) {
|
||||
protected suspend fun getMergedManga(): List<DomainManga> {
|
||||
return getMergedManga.await()
|
||||
}
|
||||
|
||||
protected suspend fun getFlatMetadata(mangaId: Long) = getFlatMetadataById.await(mangaId)
|
||||
|
||||
protected suspend fun insertFlatMetadata(flatMetadata: FlatMetadata) = insertFlatMetadata.await(flatMetadata)
|
||||
// SY <--
|
||||
|
||||
/**
|
||||
|
@ -42,8 +42,6 @@ import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.source.online.MetadataSource
|
||||
import eu.kanade.tachiyomi.util.system.logcat
|
||||
import exh.metadata.metadata.base.awaitFlatMetadataForManga
|
||||
import exh.metadata.metadata.base.awaitInsertFlatMetadata
|
||||
import exh.source.MERGED_SOURCE_ID
|
||||
import exh.source.getMainSource
|
||||
import exh.util.nullIfBlank
|
||||
@ -197,7 +195,7 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) {
|
||||
|
||||
val source = sourceManager.get(manga.source)?.getMainSource<MetadataSource<*, *>>()
|
||||
if (source != null) {
|
||||
handler.awaitFlatMetadataForManga(manga.id)?.let { flatMetadata ->
|
||||
getFlatMetadata(manga.id)?.let { flatMetadata ->
|
||||
mangaObject.flatMetadata = BackupFlatMetadata.copyFrom(flatMetadata)
|
||||
}
|
||||
}
|
||||
@ -535,18 +533,17 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) {
|
||||
mergeId = mergeMangaId
|
||||
mangaId = mergedManga.id
|
||||
handler.await {
|
||||
mergedQueries.insertMerged(
|
||||
null,
|
||||
isInfoManga,
|
||||
getChapterUpdates,
|
||||
chapterSortMode.toLong(),
|
||||
chapterPriority.toLong(),
|
||||
downloadChapters,
|
||||
mergeId!!,
|
||||
mergeUrl,
|
||||
mangaId,
|
||||
mangaUrl,
|
||||
mangaSourceId,
|
||||
mergedQueries.insert(
|
||||
infoManga = isInfoManga,
|
||||
getChapterUpdates = getChapterUpdates,
|
||||
chapterSortMode = chapterSortMode.toLong(),
|
||||
chapterPriority = chapterPriority.toLong(),
|
||||
downloadChapters = downloadChapters,
|
||||
mergeId = mergeId!!,
|
||||
mergeUrl = mergeUrl,
|
||||
mangaId = mangaId,
|
||||
mangaUrl = mangaUrl,
|
||||
mangaSource = mangaSourceId,
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -555,8 +552,8 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) {
|
||||
}
|
||||
|
||||
internal suspend fun restoreFlatMetadata(mangaId: Long, backupFlatMetadata: BackupFlatMetadata) {
|
||||
if (handler.awaitFlatMetadataForManga(mangaId) == null) {
|
||||
handler.awaitInsertFlatMetadata(backupFlatMetadata.getFlatMetadata(mangaId))
|
||||
if (getFlatMetadata(mangaId) == null) {
|
||||
insertFlatMetadata(backupFlatMetadata.getFlatMetadata(mangaId))
|
||||
}
|
||||
}
|
||||
// SY <--
|
||||
|
@ -1,53 +0,0 @@
|
||||
package eu.kanade.tachiyomi.data.database
|
||||
|
||||
import androidx.sqlite.db.SupportSQLiteOpenHelper
|
||||
import com.pushtorefresh.storio.sqlite.impl.DefaultStorIOSQLite
|
||||
import eu.kanade.tachiyomi.data.database.mappers.CategoryTypeMapping
|
||||
import eu.kanade.tachiyomi.data.database.mappers.ChapterTypeMapping
|
||||
import eu.kanade.tachiyomi.data.database.mappers.HistoryTypeMapping
|
||||
import eu.kanade.tachiyomi.data.database.mappers.MangaCategoryTypeMapping
|
||||
import eu.kanade.tachiyomi.data.database.mappers.MangaTypeMapping
|
||||
import eu.kanade.tachiyomi.data.database.mappers.TrackTypeMapping
|
||||
import eu.kanade.tachiyomi.data.database.models.Category
|
||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||
import eu.kanade.tachiyomi.data.database.models.History
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.database.models.MangaCategory
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.database.queries.ChapterQueries
|
||||
import eu.kanade.tachiyomi.data.database.queries.MangaQueries
|
||||
import exh.merged.sql.mappers.MergedMangaTypeMapping
|
||||
import exh.merged.sql.models.MergedMangaReference
|
||||
import exh.merged.sql.queries.MergedQueries
|
||||
|
||||
/**
|
||||
* This class provides operations to manage the database through its interfaces.
|
||||
*/
|
||||
class DatabaseHelper(
|
||||
openHelper: SupportSQLiteOpenHelper,
|
||||
) :
|
||||
MangaQueries,
|
||||
ChapterQueries,
|
||||
/* SY --> */
|
||||
MergedQueries
|
||||
/* SY <-- */ {
|
||||
|
||||
override val db = DefaultStorIOSQLite.builder()
|
||||
.sqliteOpenHelper(openHelper)
|
||||
.addTypeMapping(Manga::class.java, MangaTypeMapping())
|
||||
.addTypeMapping(Chapter::class.java, ChapterTypeMapping())
|
||||
.addTypeMapping(Track::class.java, TrackTypeMapping())
|
||||
.addTypeMapping(Category::class.java, CategoryTypeMapping())
|
||||
.addTypeMapping(MangaCategory::class.java, MangaCategoryTypeMapping())
|
||||
.addTypeMapping(History::class.java, HistoryTypeMapping())
|
||||
// SY -->
|
||||
.addTypeMapping(MergedMangaReference::class.java, MergedMangaTypeMapping())
|
||||
// SY <--
|
||||
.build()
|
||||
|
||||
inline fun inTransaction(block: () -> Unit) = db.inTransaction(block)
|
||||
|
||||
// SY -->
|
||||
fun lowLevel() = db.lowLevel()
|
||||
// SY <--
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
package eu.kanade.tachiyomi.data.database
|
||||
|
||||
import com.pushtorefresh.storio.sqlite.StorIOSQLite
|
||||
|
||||
inline fun StorIOSQLite.inTransaction(block: () -> Unit) {
|
||||
lowLevel().beginTransaction()
|
||||
try {
|
||||
block()
|
||||
lowLevel().setTransactionSuccessful()
|
||||
} finally {
|
||||
lowLevel().endTransaction()
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <T> StorIOSQLite.inTransactionReturn(block: () -> T): T {
|
||||
lowLevel().beginTransaction()
|
||||
try {
|
||||
val result = block()
|
||||
lowLevel().setTransactionSuccessful()
|
||||
return result
|
||||
} finally {
|
||||
lowLevel().endTransaction()
|
||||
}
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
package eu.kanade.tachiyomi.data.database
|
||||
|
||||
import com.pushtorefresh.storio.sqlite.impl.DefaultStorIOSQLite
|
||||
|
||||
interface DbProvider {
|
||||
val db: DefaultStorIOSQLite
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
package eu.kanade.tachiyomi.data.database.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 eu.kanade.tachiyomi.data.database.models.Category
|
||||
import eu.kanade.tachiyomi.data.database.models.CategoryImpl
|
||||
import eu.kanade.tachiyomi.data.database.tables.CategoryTable.COL_FLAGS
|
||||
import eu.kanade.tachiyomi.data.database.tables.CategoryTable.COL_ID
|
||||
import eu.kanade.tachiyomi.data.database.tables.CategoryTable.COL_MANGA_ORDER
|
||||
import eu.kanade.tachiyomi.data.database.tables.CategoryTable.COL_NAME
|
||||
import eu.kanade.tachiyomi.data.database.tables.CategoryTable.COL_ORDER
|
||||
import eu.kanade.tachiyomi.data.database.tables.CategoryTable.TABLE
|
||||
|
||||
class CategoryTypeMapping : SQLiteTypeMapping<Category>(
|
||||
CategoryPutResolver(),
|
||||
CategoryGetResolver(),
|
||||
CategoryDeleteResolver(),
|
||||
)
|
||||
|
||||
class CategoryPutResolver : DefaultPutResolver<Category>() {
|
||||
|
||||
override fun mapToInsertQuery(obj: Category) = InsertQuery.builder()
|
||||
.table(TABLE)
|
||||
.build()
|
||||
|
||||
override fun mapToUpdateQuery(obj: Category) = UpdateQuery.builder()
|
||||
.table(TABLE)
|
||||
.where("$COL_ID = ?")
|
||||
.whereArgs(obj.id)
|
||||
.build()
|
||||
|
||||
override fun mapToContentValues(obj: Category) =
|
||||
contentValuesOf(
|
||||
COL_ID to obj.id,
|
||||
COL_NAME to obj.name,
|
||||
COL_ORDER to obj.order,
|
||||
COL_FLAGS to obj.flags,
|
||||
COL_MANGA_ORDER to obj.mangaOrder.joinToString("/"),
|
||||
)
|
||||
}
|
||||
|
||||
class CategoryGetResolver : DefaultGetResolver<Category>() {
|
||||
|
||||
override fun mapFromCursor(cursor: Cursor): Category = CategoryImpl().apply {
|
||||
id = cursor.getInt(cursor.getColumnIndexOrThrow(COL_ID))
|
||||
name = cursor.getString(cursor.getColumnIndexOrThrow(COL_NAME))
|
||||
order = cursor.getInt(cursor.getColumnIndexOrThrow(COL_ORDER))
|
||||
flags = cursor.getInt(cursor.getColumnIndexOrThrow(COL_FLAGS))
|
||||
|
||||
// SY -->
|
||||
val orderString = cursor.getString(cursor.getColumnIndexOrThrow(COL_MANGA_ORDER))
|
||||
mangaOrder = orderString?.split("/")?.mapNotNull { it.toLongOrNull() }.orEmpty()
|
||||
// SY <--
|
||||
}
|
||||
}
|
||||
|
||||
class CategoryDeleteResolver : DefaultDeleteResolver<Category>() {
|
||||
|
||||
override fun mapToDeleteQuery(obj: Category) = DeleteQuery.builder()
|
||||
.table(TABLE)
|
||||
.where("$COL_ID = ?")
|
||||
.whereArgs(obj.id)
|
||||
.build()
|
||||
}
|
@ -1,88 +0,0 @@
|
||||
package eu.kanade.tachiyomi.data.database.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 eu.kanade.tachiyomi.data.database.models.Chapter
|
||||
import eu.kanade.tachiyomi.data.database.models.ChapterImpl
|
||||
import eu.kanade.tachiyomi.data.database.tables.ChapterTable.COL_BOOKMARK
|
||||
import eu.kanade.tachiyomi.data.database.tables.ChapterTable.COL_CHAPTER_NUMBER
|
||||
import eu.kanade.tachiyomi.data.database.tables.ChapterTable.COL_DATE_FETCH
|
||||
import eu.kanade.tachiyomi.data.database.tables.ChapterTable.COL_DATE_UPLOAD
|
||||
import eu.kanade.tachiyomi.data.database.tables.ChapterTable.COL_ID
|
||||
import eu.kanade.tachiyomi.data.database.tables.ChapterTable.COL_LAST_PAGE_READ
|
||||
import eu.kanade.tachiyomi.data.database.tables.ChapterTable.COL_MANGA_ID
|
||||
import eu.kanade.tachiyomi.data.database.tables.ChapterTable.COL_NAME
|
||||
import eu.kanade.tachiyomi.data.database.tables.ChapterTable.COL_READ
|
||||
import eu.kanade.tachiyomi.data.database.tables.ChapterTable.COL_SCANLATOR
|
||||
import eu.kanade.tachiyomi.data.database.tables.ChapterTable.COL_SOURCE_ORDER
|
||||
import eu.kanade.tachiyomi.data.database.tables.ChapterTable.COL_URL
|
||||
import eu.kanade.tachiyomi.data.database.tables.ChapterTable.TABLE
|
||||
|
||||
class ChapterTypeMapping : SQLiteTypeMapping<Chapter>(
|
||||
ChapterPutResolver(),
|
||||
ChapterGetResolver(),
|
||||
ChapterDeleteResolver(),
|
||||
)
|
||||
|
||||
class ChapterPutResolver : DefaultPutResolver<Chapter>() {
|
||||
|
||||
override fun mapToInsertQuery(obj: Chapter) = InsertQuery.builder()
|
||||
.table(TABLE)
|
||||
.build()
|
||||
|
||||
override fun mapToUpdateQuery(obj: Chapter) = UpdateQuery.builder()
|
||||
.table(TABLE)
|
||||
.where("$COL_ID = ?")
|
||||
.whereArgs(obj.id)
|
||||
.build()
|
||||
|
||||
override fun mapToContentValues(obj: Chapter) =
|
||||
contentValuesOf(
|
||||
COL_ID to obj.id,
|
||||
COL_MANGA_ID to obj.manga_id,
|
||||
COL_URL to obj.url,
|
||||
COL_NAME to obj.name,
|
||||
COL_READ to obj.read,
|
||||
COL_SCANLATOR to obj.scanlator,
|
||||
COL_BOOKMARK to obj.bookmark,
|
||||
COL_DATE_FETCH to obj.date_fetch,
|
||||
COL_DATE_UPLOAD to obj.date_upload,
|
||||
COL_LAST_PAGE_READ to obj.last_page_read,
|
||||
COL_CHAPTER_NUMBER to obj.chapter_number,
|
||||
COL_SOURCE_ORDER to obj.source_order,
|
||||
)
|
||||
}
|
||||
|
||||
class ChapterGetResolver : DefaultGetResolver<Chapter>() {
|
||||
|
||||
override fun mapFromCursor(cursor: Cursor): Chapter = ChapterImpl().apply {
|
||||
id = cursor.getLong(cursor.getColumnIndexOrThrow(COL_ID))
|
||||
manga_id = cursor.getLong(cursor.getColumnIndexOrThrow(COL_MANGA_ID))
|
||||
url = cursor.getString(cursor.getColumnIndexOrThrow(COL_URL))
|
||||
name = cursor.getString(cursor.getColumnIndexOrThrow(COL_NAME))
|
||||
scanlator = cursor.getString(cursor.getColumnIndexOrThrow(COL_SCANLATOR))
|
||||
read = cursor.getInt(cursor.getColumnIndexOrThrow(COL_READ)) == 1
|
||||
bookmark = cursor.getInt(cursor.getColumnIndexOrThrow(COL_BOOKMARK)) == 1
|
||||
date_fetch = cursor.getLong(cursor.getColumnIndexOrThrow(COL_DATE_FETCH))
|
||||
date_upload = cursor.getLong(cursor.getColumnIndexOrThrow(COL_DATE_UPLOAD))
|
||||
last_page_read = cursor.getInt(cursor.getColumnIndexOrThrow(COL_LAST_PAGE_READ))
|
||||
chapter_number = cursor.getFloat(cursor.getColumnIndexOrThrow(COL_CHAPTER_NUMBER))
|
||||
source_order = cursor.getInt(cursor.getColumnIndexOrThrow(COL_SOURCE_ORDER))
|
||||
}
|
||||
}
|
||||
|
||||
class ChapterDeleteResolver : DefaultDeleteResolver<Chapter>() {
|
||||
|
||||
override fun mapToDeleteQuery(obj: Chapter) = DeleteQuery.builder()
|
||||
.table(TABLE)
|
||||
.where("$COL_ID = ?")
|
||||
.whereArgs(obj.id)
|
||||
.build()
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
package eu.kanade.tachiyomi.data.database.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 eu.kanade.tachiyomi.data.database.models.History
|
||||
import eu.kanade.tachiyomi.data.database.models.HistoryImpl
|
||||
import eu.kanade.tachiyomi.data.database.tables.HistoryTable.COL_CHAPTER_ID
|
||||
import eu.kanade.tachiyomi.data.database.tables.HistoryTable.COL_ID
|
||||
import eu.kanade.tachiyomi.data.database.tables.HistoryTable.COL_LAST_READ
|
||||
import eu.kanade.tachiyomi.data.database.tables.HistoryTable.COL_TIME_READ
|
||||
import eu.kanade.tachiyomi.data.database.tables.HistoryTable.TABLE
|
||||
|
||||
class HistoryTypeMapping : SQLiteTypeMapping<History>(
|
||||
HistoryPutResolver(),
|
||||
HistoryGetResolver(),
|
||||
HistoryDeleteResolver(),
|
||||
)
|
||||
|
||||
open class HistoryPutResolver : DefaultPutResolver<History>() {
|
||||
|
||||
override fun mapToInsertQuery(obj: History) = InsertQuery.builder()
|
||||
.table(TABLE)
|
||||
.build()
|
||||
|
||||
override fun mapToUpdateQuery(obj: History) = UpdateQuery.builder()
|
||||
.table(TABLE)
|
||||
.where("$COL_ID = ?")
|
||||
.whereArgs(obj.id)
|
||||
.build()
|
||||
|
||||
override fun mapToContentValues(obj: History) =
|
||||
contentValuesOf(
|
||||
COL_ID to obj.id,
|
||||
COL_CHAPTER_ID to obj.chapter_id,
|
||||
COL_LAST_READ to obj.last_read,
|
||||
COL_TIME_READ to obj.time_read,
|
||||
)
|
||||
}
|
||||
|
||||
class HistoryGetResolver : DefaultGetResolver<History>() {
|
||||
|
||||
override fun mapFromCursor(cursor: Cursor): History = HistoryImpl().apply {
|
||||
id = cursor.getLong(cursor.getColumnIndexOrThrow(COL_ID))
|
||||
chapter_id = cursor.getLong(cursor.getColumnIndexOrThrow(COL_CHAPTER_ID))
|
||||
last_read = cursor.getLong(cursor.getColumnIndexOrThrow(COL_LAST_READ))
|
||||
time_read = cursor.getLong(cursor.getColumnIndexOrThrow(COL_TIME_READ))
|
||||
}
|
||||
}
|
||||
|
||||
class HistoryDeleteResolver : DefaultDeleteResolver<History>() {
|
||||
|
||||
override fun mapToDeleteQuery(obj: History) = DeleteQuery.builder()
|
||||
.table(TABLE)
|
||||
.where("$COL_ID = ?")
|
||||
.whereArgs(obj.id)
|
||||
.build()
|
||||
}
|
@ -1,60 +0,0 @@
|
||||
package eu.kanade.tachiyomi.data.database.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 eu.kanade.tachiyomi.data.database.models.MangaCategory
|
||||
import eu.kanade.tachiyomi.data.database.tables.MangaCategoryTable.COL_CATEGORY_ID
|
||||
import eu.kanade.tachiyomi.data.database.tables.MangaCategoryTable.COL_ID
|
||||
import eu.kanade.tachiyomi.data.database.tables.MangaCategoryTable.COL_MANGA_ID
|
||||
import eu.kanade.tachiyomi.data.database.tables.MangaCategoryTable.TABLE
|
||||
|
||||
class MangaCategoryTypeMapping : SQLiteTypeMapping<MangaCategory>(
|
||||
MangaCategoryPutResolver(),
|
||||
MangaCategoryGetResolver(),
|
||||
MangaCategoryDeleteResolver(),
|
||||
)
|
||||
|
||||
class MangaCategoryPutResolver : DefaultPutResolver<MangaCategory>() {
|
||||
|
||||
override fun mapToInsertQuery(obj: MangaCategory) = InsertQuery.builder()
|
||||
.table(TABLE)
|
||||
.build()
|
||||
|
||||
override fun mapToUpdateQuery(obj: MangaCategory) = UpdateQuery.builder()
|
||||
.table(TABLE)
|
||||
.where("$COL_ID = ?")
|
||||
.whereArgs(obj.id)
|
||||
.build()
|
||||
|
||||
override fun mapToContentValues(obj: MangaCategory) =
|
||||
contentValuesOf(
|
||||
COL_ID to obj.id,
|
||||
COL_MANGA_ID to obj.manga_id,
|
||||
COL_CATEGORY_ID to obj.category_id,
|
||||
)
|
||||
}
|
||||
|
||||
class MangaCategoryGetResolver : DefaultGetResolver<MangaCategory>() {
|
||||
|
||||
override fun mapFromCursor(cursor: Cursor): MangaCategory = MangaCategory().apply {
|
||||
id = cursor.getLong(cursor.getColumnIndexOrThrow(COL_ID))
|
||||
manga_id = cursor.getLong(cursor.getColumnIndexOrThrow(COL_MANGA_ID))
|
||||
category_id = cursor.getInt(cursor.getColumnIndexOrThrow(COL_CATEGORY_ID))
|
||||
}
|
||||
}
|
||||
|
||||
class MangaCategoryDeleteResolver : DefaultDeleteResolver<MangaCategory>() {
|
||||
|
||||
override fun mapToDeleteQuery(obj: MangaCategory) = DeleteQuery.builder()
|
||||
.table(TABLE)
|
||||
.where("$COL_ID = ?")
|
||||
.whereArgs(obj.id)
|
||||
.build()
|
||||
}
|
@ -1,114 +0,0 @@
|
||||
package eu.kanade.tachiyomi.data.database.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 eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.database.models.MangaImpl
|
||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_ARTIST
|
||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_AUTHOR
|
||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_CHAPTER_FLAGS
|
||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_COVER_LAST_MODIFIED
|
||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_DATE_ADDED
|
||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_DESCRIPTION
|
||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_FAVORITE
|
||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_FILTERED_SCANLATORS
|
||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_GENRE
|
||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_ID
|
||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_INITIALIZED
|
||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_LAST_UPDATE
|
||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_SOURCE
|
||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_STATUS
|
||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_THUMBNAIL_URL
|
||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_TITLE
|
||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_URL
|
||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_VIEWER
|
||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable.TABLE
|
||||
|
||||
class MangaTypeMapping : SQLiteTypeMapping<Manga>(
|
||||
MangaPutResolver(),
|
||||
MangaGetResolver(),
|
||||
MangaDeleteResolver(),
|
||||
)
|
||||
|
||||
class MangaPutResolver : DefaultPutResolver<Manga>() {
|
||||
|
||||
override fun mapToInsertQuery(obj: Manga) = InsertQuery.builder()
|
||||
.table(TABLE)
|
||||
.build()
|
||||
|
||||
override fun mapToUpdateQuery(obj: Manga) = UpdateQuery.builder()
|
||||
.table(TABLE)
|
||||
.where("$COL_ID = ?")
|
||||
.whereArgs(obj.id)
|
||||
.build()
|
||||
|
||||
override fun mapToContentValues(obj: Manga) =
|
||||
contentValuesOf(
|
||||
COL_ID to obj.id,
|
||||
COL_SOURCE to obj.source,
|
||||
COL_URL to obj.url,
|
||||
// SY -->
|
||||
COL_ARTIST to obj.originalArtist,
|
||||
COL_AUTHOR to obj.originalAuthor,
|
||||
COL_DESCRIPTION to obj.originalDescription,
|
||||
COL_GENRE to obj.originalGenre,
|
||||
COL_TITLE to obj.originalTitle,
|
||||
COL_STATUS to obj.originalStatus,
|
||||
// SY <--
|
||||
COL_THUMBNAIL_URL to obj.thumbnail_url,
|
||||
COL_FAVORITE to obj.favorite,
|
||||
COL_LAST_UPDATE to obj.last_update,
|
||||
COL_INITIALIZED to obj.initialized,
|
||||
COL_VIEWER to obj.viewer_flags,
|
||||
COL_CHAPTER_FLAGS to obj.chapter_flags,
|
||||
COL_COVER_LAST_MODIFIED to obj.cover_last_modified,
|
||||
COL_DATE_ADDED to obj.date_added,
|
||||
COL_FILTERED_SCANLATORS to obj.filtered_scanlators,
|
||||
)
|
||||
}
|
||||
|
||||
interface BaseMangaGetResolver {
|
||||
fun mapBaseFromCursor(manga: Manga, cursor: Cursor) = manga.apply {
|
||||
id = cursor.getLong(cursor.getColumnIndexOrThrow(COL_ID))
|
||||
source = cursor.getLong(cursor.getColumnIndexOrThrow(COL_SOURCE))
|
||||
url = cursor.getString(cursor.getColumnIndexOrThrow(COL_URL))
|
||||
artist = cursor.getString(cursor.getColumnIndexOrThrow(COL_ARTIST))
|
||||
author = cursor.getString(cursor.getColumnIndexOrThrow(COL_AUTHOR))
|
||||
description = cursor.getString(cursor.getColumnIndexOrThrow(COL_DESCRIPTION))
|
||||
genre = cursor.getString(cursor.getColumnIndexOrThrow(COL_GENRE))
|
||||
title = cursor.getString(cursor.getColumnIndexOrThrow(COL_TITLE))
|
||||
status = cursor.getInt(cursor.getColumnIndexOrThrow(COL_STATUS))
|
||||
thumbnail_url = cursor.getString(cursor.getColumnIndexOrThrow(COL_THUMBNAIL_URL))
|
||||
favorite = cursor.getInt(cursor.getColumnIndexOrThrow(COL_FAVORITE)) == 1
|
||||
last_update = cursor.getLong(cursor.getColumnIndexOrThrow(COL_LAST_UPDATE))
|
||||
initialized = cursor.getInt(cursor.getColumnIndexOrThrow(COL_INITIALIZED)) == 1
|
||||
viewer_flags = cursor.getInt(cursor.getColumnIndexOrThrow(COL_VIEWER))
|
||||
chapter_flags = cursor.getInt(cursor.getColumnIndexOrThrow(COL_CHAPTER_FLAGS))
|
||||
cover_last_modified = cursor.getLong(cursor.getColumnIndexOrThrow(COL_COVER_LAST_MODIFIED))
|
||||
date_added = cursor.getLong(cursor.getColumnIndexOrThrow(COL_DATE_ADDED))
|
||||
filtered_scanlators = cursor.getString(cursor.getColumnIndexOrThrow(COL_FILTERED_SCANLATORS))
|
||||
}
|
||||
}
|
||||
|
||||
open class MangaGetResolver : DefaultGetResolver<Manga>(), BaseMangaGetResolver {
|
||||
|
||||
override fun mapFromCursor(cursor: Cursor): Manga {
|
||||
return mapBaseFromCursor(MangaImpl(), cursor)
|
||||
}
|
||||
}
|
||||
|
||||
class MangaDeleteResolver : DefaultDeleteResolver<Manga>() {
|
||||
|
||||
override fun mapToDeleteQuery(obj: Manga) = DeleteQuery.builder()
|
||||
.table(TABLE)
|
||||
.where("$COL_ID = ?")
|
||||
.whereArgs(obj.id)
|
||||
.build()
|
||||
}
|
@ -1,91 +0,0 @@
|
||||
package eu.kanade.tachiyomi.data.database.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 eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.database.models.TrackImpl
|
||||
import eu.kanade.tachiyomi.data.database.tables.TrackTable.COL_FINISH_DATE
|
||||
import eu.kanade.tachiyomi.data.database.tables.TrackTable.COL_ID
|
||||
import eu.kanade.tachiyomi.data.database.tables.TrackTable.COL_LAST_CHAPTER_READ
|
||||
import eu.kanade.tachiyomi.data.database.tables.TrackTable.COL_LIBRARY_ID
|
||||
import eu.kanade.tachiyomi.data.database.tables.TrackTable.COL_MANGA_ID
|
||||
import eu.kanade.tachiyomi.data.database.tables.TrackTable.COL_MEDIA_ID
|
||||
import eu.kanade.tachiyomi.data.database.tables.TrackTable.COL_SCORE
|
||||
import eu.kanade.tachiyomi.data.database.tables.TrackTable.COL_START_DATE
|
||||
import eu.kanade.tachiyomi.data.database.tables.TrackTable.COL_STATUS
|
||||
import eu.kanade.tachiyomi.data.database.tables.TrackTable.COL_SYNC_ID
|
||||
import eu.kanade.tachiyomi.data.database.tables.TrackTable.COL_TITLE
|
||||
import eu.kanade.tachiyomi.data.database.tables.TrackTable.COL_TOTAL_CHAPTERS
|
||||
import eu.kanade.tachiyomi.data.database.tables.TrackTable.COL_TRACKING_URL
|
||||
import eu.kanade.tachiyomi.data.database.tables.TrackTable.TABLE
|
||||
|
||||
class TrackTypeMapping : SQLiteTypeMapping<Track>(
|
||||
TrackPutResolver(),
|
||||
TrackGetResolver(),
|
||||
TrackDeleteResolver(),
|
||||
)
|
||||
|
||||
class TrackPutResolver : DefaultPutResolver<Track>() {
|
||||
|
||||
override fun mapToInsertQuery(obj: Track) = InsertQuery.builder()
|
||||
.table(TABLE)
|
||||
.build()
|
||||
|
||||
override fun mapToUpdateQuery(obj: Track) = UpdateQuery.builder()
|
||||
.table(TABLE)
|
||||
.where("$COL_ID = ?")
|
||||
.whereArgs(obj.id)
|
||||
.build()
|
||||
|
||||
override fun mapToContentValues(obj: Track) =
|
||||
contentValuesOf(
|
||||
COL_ID to obj.id,
|
||||
COL_MANGA_ID to obj.manga_id,
|
||||
COL_SYNC_ID to obj.sync_id,
|
||||
COL_MEDIA_ID to obj.media_id,
|
||||
COL_LIBRARY_ID to obj.library_id,
|
||||
COL_TITLE to obj.title,
|
||||
COL_LAST_CHAPTER_READ to obj.last_chapter_read,
|
||||
COL_TOTAL_CHAPTERS to obj.total_chapters,
|
||||
COL_STATUS to obj.status,
|
||||
COL_TRACKING_URL to obj.tracking_url,
|
||||
COL_SCORE to obj.score,
|
||||
COL_START_DATE to obj.started_reading_date,
|
||||
COL_FINISH_DATE to obj.finished_reading_date,
|
||||
)
|
||||
}
|
||||
|
||||
class TrackGetResolver : DefaultGetResolver<Track>() {
|
||||
|
||||
override fun mapFromCursor(cursor: Cursor): Track = TrackImpl().apply {
|
||||
id = cursor.getLong(cursor.getColumnIndexOrThrow(COL_ID))
|
||||
manga_id = cursor.getLong(cursor.getColumnIndexOrThrow(COL_MANGA_ID))
|
||||
sync_id = cursor.getInt(cursor.getColumnIndexOrThrow(COL_SYNC_ID))
|
||||
media_id = cursor.getLong(cursor.getColumnIndexOrThrow(COL_MEDIA_ID))
|
||||
library_id = cursor.getLong(cursor.getColumnIndexOrThrow(COL_LIBRARY_ID))
|
||||
title = cursor.getString(cursor.getColumnIndexOrThrow(COL_TITLE))
|
||||
last_chapter_read = cursor.getFloat(cursor.getColumnIndexOrThrow(COL_LAST_CHAPTER_READ))
|
||||
total_chapters = cursor.getInt(cursor.getColumnIndexOrThrow(COL_TOTAL_CHAPTERS))
|
||||
status = cursor.getInt(cursor.getColumnIndexOrThrow(COL_STATUS))
|
||||
score = cursor.getFloat(cursor.getColumnIndexOrThrow(COL_SCORE))
|
||||
tracking_url = cursor.getString(cursor.getColumnIndexOrThrow(COL_TRACKING_URL))
|
||||
started_reading_date = cursor.getLong(cursor.getColumnIndexOrThrow(COL_START_DATE))
|
||||
finished_reading_date = cursor.getLong(cursor.getColumnIndexOrThrow(COL_FINISH_DATE))
|
||||
}
|
||||
}
|
||||
|
||||
class TrackDeleteResolver : DefaultDeleteResolver<Track>() {
|
||||
|
||||
override fun mapToDeleteQuery(obj: Track) = DeleteQuery.builder()
|
||||
.table(TABLE)
|
||||
.where("$COL_ID = ?")
|
||||
.whereArgs(obj.id)
|
||||
.build()
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
package eu.kanade.tachiyomi.data.database.queries
|
||||
|
||||
import com.pushtorefresh.storio.sqlite.queries.Query
|
||||
import eu.kanade.tachiyomi.data.database.DbProvider
|
||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.database.resolvers.ChapterProgressPutResolver
|
||||
import eu.kanade.tachiyomi.data.database.tables.ChapterTable
|
||||
|
||||
interface ChapterQueries : DbProvider {
|
||||
// SY -->
|
||||
fun getChapters(manga: Manga) = getChapters(manga.id)
|
||||
|
||||
fun getChapters(mangaId: Long?) = db.get()
|
||||
.listOfObjects(Chapter::class.java)
|
||||
.withQuery(
|
||||
Query.builder()
|
||||
.table(ChapterTable.TABLE)
|
||||
.where("${ChapterTable.COL_MANGA_ID} = ?")
|
||||
.whereArgs(mangaId)
|
||||
.build(),
|
||||
)
|
||||
.prepare()
|
||||
// SY <--
|
||||
|
||||
fun deleteChapters(chapters: List<Chapter>) = db.delete().objects(chapters).prepare()
|
||||
|
||||
fun updateChapterProgress(chapter: Chapter) = db.put()
|
||||
.`object`(chapter)
|
||||
.withPutResolver(ChapterProgressPutResolver())
|
||||
.prepare()
|
||||
|
||||
fun updateChaptersProgress(chapters: List<Chapter>) = db.put()
|
||||
.objects(chapters)
|
||||
.withPutResolver(ChapterProgressPutResolver())
|
||||
.prepare()
|
||||
}
|
@ -1,79 +0,0 @@
|
||||
package eu.kanade.tachiyomi.data.database.queries
|
||||
|
||||
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.LibraryManga
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.database.resolvers.LibraryMangaGetResolver
|
||||
import eu.kanade.tachiyomi.data.database.resolvers.MangaFlagsPutResolver
|
||||
import eu.kanade.tachiyomi.data.database.tables.CategoryTable
|
||||
import eu.kanade.tachiyomi.data.database.tables.ChapterTable
|
||||
import eu.kanade.tachiyomi.data.database.tables.MangaCategoryTable
|
||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable
|
||||
|
||||
interface MangaQueries : DbProvider {
|
||||
|
||||
fun getLibraryMangas() = db.get()
|
||||
.listOfObjects(LibraryManga::class.java)
|
||||
.withQuery(
|
||||
RawQuery.builder()
|
||||
.query(libraryQuery)
|
||||
.observesTables(MangaTable.TABLE, ChapterTable.TABLE, MangaCategoryTable.TABLE, CategoryTable.TABLE)
|
||||
.build(),
|
||||
)
|
||||
.withGetResolver(LibraryMangaGetResolver.INSTANCE)
|
||||
.prepare()
|
||||
|
||||
fun getFavoriteMangas() = db.get()
|
||||
.listOfObjects(Manga::class.java)
|
||||
.withQuery(
|
||||
Query.builder()
|
||||
.table(MangaTable.TABLE)
|
||||
.where("${MangaTable.COL_FAVORITE} = ?")
|
||||
.whereArgs(1)
|
||||
.build(),
|
||||
)
|
||||
.prepare()
|
||||
|
||||
fun getManga(url: String, sourceId: Long) = db.get()
|
||||
.`object`(Manga::class.java)
|
||||
.withQuery(
|
||||
Query.builder()
|
||||
.table(MangaTable.TABLE)
|
||||
.where("${MangaTable.COL_URL} = ? AND ${MangaTable.COL_SOURCE} = ?")
|
||||
.whereArgs(url, sourceId)
|
||||
.build(),
|
||||
)
|
||||
.prepare()
|
||||
|
||||
fun getManga(id: Long) = db.get()
|
||||
.`object`(Manga::class.java)
|
||||
.withQuery(
|
||||
Query.builder()
|
||||
.table(MangaTable.TABLE)
|
||||
.where("${MangaTable.COL_ID} = ?")
|
||||
.whereArgs(id)
|
||||
.build(),
|
||||
)
|
||||
.prepare()
|
||||
|
||||
fun insertManga(manga: Manga) = db.put().`object`(manga).prepare()
|
||||
|
||||
fun updateChapterFlags(manga: Manga) = db.put()
|
||||
.`object`(manga)
|
||||
.withPutResolver(MangaFlagsPutResolver(MangaTable.COL_CHAPTER_FLAGS, Manga::chapter_flags))
|
||||
.prepare()
|
||||
|
||||
fun updateChapterFlags(manga: List<Manga>) = db.put()
|
||||
.objects(manga)
|
||||
.withPutResolver(MangaFlagsPutResolver(MangaTable.COL_CHAPTER_FLAGS, Manga::chapter_flags))
|
||||
.prepare()
|
||||
|
||||
fun updateViewerFlags(manga: Manga) = db.put()
|
||||
.`object`(manga)
|
||||
.withPutResolver(MangaFlagsPutResolver(MangaTable.COL_VIEWER, Manga::viewer_flags))
|
||||
.prepare()
|
||||
|
||||
fun deleteManga(manga: Manga) = db.delete().`object`(manga).prepare()
|
||||
}
|
@ -1,131 +0,0 @@
|
||||
package eu.kanade.tachiyomi.data.database.queries
|
||||
|
||||
import exh.source.MERGED_SOURCE_ID
|
||||
import eu.kanade.tachiyomi.data.database.tables.ChapterTable as Chapter
|
||||
import eu.kanade.tachiyomi.data.database.tables.MangaCategoryTable as MangaCategory
|
||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable as Manga
|
||||
import exh.merged.sql.tables.MergedTable as Merged
|
||||
|
||||
// SY -->
|
||||
/**
|
||||
* Query to get the manga merged into a merged manga
|
||||
*/
|
||||
fun getMergedMangaQuery() =
|
||||
"""
|
||||
SELECT ${Manga.TABLE}.*
|
||||
FROM (
|
||||
SELECT ${Merged.COL_MANGA_ID} FROM ${Merged.TABLE} WHERE ${Merged.COL_MERGE_ID} = ?
|
||||
) AS M
|
||||
JOIN ${Manga.TABLE}
|
||||
ON ${Manga.TABLE}.${Manga.COL_ID} = M.${Merged.COL_MANGA_ID}
|
||||
"""
|
||||
|
||||
/**
|
||||
* Query to get the manga merged into a merged manga
|
||||
*/
|
||||
fun getMergedMangaForDownloadingQuery() =
|
||||
"""
|
||||
SELECT ${Manga.TABLE}.*
|
||||
FROM (
|
||||
SELECT ${Merged.COL_MANGA_ID} FROM ${Merged.TABLE} WHERE ${Merged.COL_MERGE_ID} = ? AND ${Merged.COL_DOWNLOAD_CHAPTERS} = 1
|
||||
) AS M
|
||||
JOIN ${Manga.TABLE}
|
||||
ON ${Manga.TABLE}.${Manga.COL_ID} = M.${Merged.COL_MANGA_ID}
|
||||
"""
|
||||
|
||||
/**
|
||||
* Query to get all the manga that are merged into other manga
|
||||
*/
|
||||
fun getAllMergedMangaQuery() =
|
||||
"""
|
||||
SELECT ${Manga.TABLE}.*
|
||||
FROM (
|
||||
SELECT ${Merged.COL_MANGA_ID} FROM ${Merged.TABLE}
|
||||
) AS M
|
||||
JOIN ${Manga.TABLE}
|
||||
ON ${Manga.TABLE}.${Manga.COL_ID} = M.${Merged.COL_MANGA_ID}
|
||||
"""
|
||||
|
||||
/**
|
||||
* Query to get the manga merged into a merged manga using the Url
|
||||
*/
|
||||
fun getMergedMangaFromUrlQuery() =
|
||||
"""
|
||||
SELECT ${Manga.TABLE}.*
|
||||
FROM (
|
||||
SELECT ${Merged.COL_MANGA_ID} FROM ${Merged.TABLE} WHERE ${Merged.COL_MERGE_URL} = ?
|
||||
) AS M
|
||||
JOIN ${Manga.TABLE}
|
||||
ON ${Manga.TABLE}.${Manga.COL_ID} = M.${Merged.COL_MANGA_ID}
|
||||
"""
|
||||
|
||||
/**
|
||||
* Query to get the chapters of all manga in a merged manga
|
||||
*/
|
||||
fun getMergedChaptersQuery() =
|
||||
"""
|
||||
SELECT ${Chapter.TABLE}.*
|
||||
FROM (
|
||||
SELECT ${Merged.COL_MANGA_ID} FROM ${Merged.TABLE} WHERE ${Merged.COL_MERGE_ID} = ?
|
||||
) AS M
|
||||
JOIN ${Chapter.TABLE}
|
||||
ON ${Chapter.TABLE}.${Chapter.COL_MANGA_ID} = M.${Merged.COL_MANGA_ID}
|
||||
"""
|
||||
|
||||
/**
|
||||
* Query to get the manga from the library, with their categories, read and unread count.
|
||||
*/
|
||||
val libraryQuery =
|
||||
"""
|
||||
SELECT M.*, COALESCE(MC.${MangaCategory.COL_CATEGORY_ID}, 0) AS ${Manga.COL_CATEGORY}
|
||||
FROM (
|
||||
SELECT ${Manga.TABLE}.*, COALESCE(C.unreadCount, 0) AS ${Manga.COMPUTED_COL_UNREAD_COUNT}, COALESCE(R.readCount, 0) AS ${Manga.COMPUTED_COL_READ_COUNT}
|
||||
FROM ${Manga.TABLE}
|
||||
LEFT JOIN (
|
||||
SELECT ${Chapter.TABLE}.${Chapter.COL_MANGA_ID}, COUNT(*) AS unreadCount
|
||||
FROM ${Chapter.TABLE}
|
||||
WHERE ${Chapter.COL_READ} = 0
|
||||
GROUP BY ${Chapter.TABLE}.${Chapter.COL_MANGA_ID}
|
||||
) AS C
|
||||
ON ${Manga.TABLE}.${Manga.COL_ID} = C.${Chapter.COL_MANGA_ID}
|
||||
LEFT JOIN (
|
||||
SELECT ${Chapter.COL_MANGA_ID}, COUNT(*) AS readCount
|
||||
FROM ${Chapter.TABLE}
|
||||
WHERE ${Chapter.COL_READ} = 1
|
||||
GROUP BY ${Chapter.COL_MANGA_ID}
|
||||
) AS R
|
||||
ON ${Manga.TABLE}.${Manga.COL_ID} = R.${Chapter.COL_MANGA_ID}
|
||||
WHERE ${Manga.COL_FAVORITE} = 1 AND ${Manga.COL_SOURCE} <> $MERGED_SOURCE_ID
|
||||
GROUP BY ${Manga.TABLE}.${Manga.COL_ID}
|
||||
UNION
|
||||
SELECT ${Manga.TABLE}.*, COALESCE(C.unreadCount, 0) AS ${Manga.COMPUTED_COL_UNREAD_COUNT}, COALESCE(R.readCount, 0) AS ${Manga.COMPUTED_COL_READ_COUNT}
|
||||
FROM ${Manga.TABLE}
|
||||
LEFT JOIN (
|
||||
SELECT ${Merged.TABLE}.${Merged.COL_MERGE_ID}, COUNT(*) as unreadCount
|
||||
FROM ${Merged.TABLE}
|
||||
JOIN ${Chapter.TABLE}
|
||||
ON ${Chapter.TABLE}.${Chapter.COL_MANGA_ID} = ${Merged.TABLE}.${Merged.COL_MANGA_ID}
|
||||
WHERE ${Chapter.TABLE}.${Chapter.COL_READ} = 0
|
||||
GROUP BY ${Merged.TABLE}.${Merged.COL_MERGE_ID}
|
||||
) AS C
|
||||
ON ${Manga.TABLE}.${Manga.COL_ID} = C.${Merged.COL_MERGE_ID}
|
||||
LEFT JOIN (
|
||||
SELECT ${Merged.TABLE}.${Merged.COL_MERGE_ID}, COUNT(*) as readCount
|
||||
FROM ${Merged.TABLE}
|
||||
JOIN ${Chapter.TABLE}
|
||||
ON ${Chapter.TABLE}.${Chapter.COL_MANGA_ID} = ${Merged.TABLE}.${Merged.COL_MANGA_ID}
|
||||
WHERE ${Chapter.TABLE}.${Chapter.COL_READ} = 1
|
||||
GROUP BY ${Merged.TABLE}.${Merged.COL_MERGE_ID}
|
||||
) AS R
|
||||
ON ${Manga.TABLE}.${Manga.COL_ID} = R.${Merged.COL_MERGE_ID}
|
||||
WHERE ${Manga.COL_FAVORITE} = 1 AND ${Manga.COL_SOURCE} = $MERGED_SOURCE_ID
|
||||
GROUP BY ${Manga.TABLE}.${Manga.COL_ID}
|
||||
ORDER BY ${Manga.COL_TITLE}
|
||||
) AS M
|
||||
LEFT JOIN (
|
||||
SELECT * FROM ${MangaCategory.TABLE}
|
||||
) AS MC
|
||||
ON MC.${MangaCategory.COL_MANGA_ID} = M.${Manga.COL_ID};
|
||||
"""
|
||||
|
||||
// SY <--
|
@ -1,34 +0,0 @@
|
||||
package eu.kanade.tachiyomi.data.database.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 eu.kanade.tachiyomi.data.database.models.Chapter
|
||||
import eu.kanade.tachiyomi.data.database.tables.ChapterTable
|
||||
|
||||
class ChapterProgressPutResolver : PutResolver<Chapter>() {
|
||||
|
||||
override fun performPut(db: StorIOSQLite, chapter: Chapter) = db.inTransactionReturn {
|
||||
val updateQuery = mapToUpdateQuery(chapter)
|
||||
val contentValues = mapToContentValues(chapter)
|
||||
|
||||
val numberOfRowsUpdated = db.lowLevel().update(updateQuery, contentValues)
|
||||
PutResult.newUpdateResult(numberOfRowsUpdated, updateQuery.table())
|
||||
}
|
||||
|
||||
fun mapToUpdateQuery(chapter: Chapter) = UpdateQuery.builder()
|
||||
.table(ChapterTable.TABLE)
|
||||
.where("${ChapterTable.COL_ID} = ?")
|
||||
.whereArgs(chapter.id)
|
||||
.build()
|
||||
|
||||
fun mapToContentValues(chapter: Chapter) =
|
||||
contentValuesOf(
|
||||
ChapterTable.COL_READ to chapter.read,
|
||||
ChapterTable.COL_BOOKMARK to chapter.bookmark,
|
||||
ChapterTable.COL_LAST_PAGE_READ to chapter.last_page_read,
|
||||
)
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
package eu.kanade.tachiyomi.data.database.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 eu.kanade.tachiyomi.data.database.models.History
|
||||
import eu.kanade.tachiyomi.data.database.tables.HistoryTable
|
||||
|
||||
class HistoryChapterIdPutResolver : PutResolver<History>() {
|
||||
|
||||
override fun performPut(db: StorIOSQLite, history: History) = db.inTransactionReturn {
|
||||
val updateQuery = mapToUpdateQuery(history)
|
||||
val contentValues = mapToContentValues(history)
|
||||
|
||||
val numberOfRowsUpdated = db.lowLevel().update(updateQuery, contentValues)
|
||||
PutResult.newUpdateResult(numberOfRowsUpdated, updateQuery.table())
|
||||
}
|
||||
|
||||
fun mapToUpdateQuery(history: History) = UpdateQuery.builder()
|
||||
.table(HistoryTable.TABLE)
|
||||
.where("${HistoryTable.COL_ID} = ?")
|
||||
.whereArgs(history.id)
|
||||
.build()
|
||||
|
||||
fun mapToContentValues(history: History) =
|
||||
contentValuesOf(
|
||||
HistoryTable.COL_CHAPTER_ID to history.chapter_id,
|
||||
)
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
package eu.kanade.tachiyomi.data.database.resolvers
|
||||
|
||||
import androidx.annotation.NonNull
|
||||
import androidx.core.content.contentValuesOf
|
||||
import com.pushtorefresh.storio.sqlite.StorIOSQLite
|
||||
import com.pushtorefresh.storio.sqlite.operations.put.PutResult
|
||||
import com.pushtorefresh.storio.sqlite.queries.Query
|
||||
import com.pushtorefresh.storio.sqlite.queries.UpdateQuery
|
||||
import eu.kanade.tachiyomi.data.database.inTransactionReturn
|
||||
import eu.kanade.tachiyomi.data.database.mappers.HistoryPutResolver
|
||||
import eu.kanade.tachiyomi.data.database.models.History
|
||||
import eu.kanade.tachiyomi.data.database.tables.HistoryTable
|
||||
|
||||
class HistoryUpsertResolver : HistoryPutResolver() {
|
||||
|
||||
/**
|
||||
* Updates last_read time of chapter
|
||||
*/
|
||||
override fun performPut(@NonNull db: StorIOSQLite, @NonNull history: History): PutResult = db.inTransactionReturn {
|
||||
val updateQuery = mapToUpdateQuery(history)
|
||||
|
||||
val cursor = db.lowLevel().query(
|
||||
Query.builder()
|
||||
.table(updateQuery.table())
|
||||
.where(updateQuery.where())
|
||||
.whereArgs(updateQuery.whereArgs())
|
||||
.build(),
|
||||
)
|
||||
|
||||
cursor.use { putCursor ->
|
||||
if (putCursor.count == 0) {
|
||||
val insertQuery = mapToInsertQuery(history)
|
||||
val insertedId = db.lowLevel().insert(insertQuery, mapToContentValues(history))
|
||||
PutResult.newInsertResult(insertedId, insertQuery.table())
|
||||
} else {
|
||||
val numberOfRowsUpdated = db.lowLevel().update(updateQuery, mapToUpdateContentValues(history))
|
||||
PutResult.newUpdateResult(numberOfRowsUpdated, updateQuery.table())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun mapToUpdateQuery(obj: History) = UpdateQuery.builder()
|
||||
.table(HistoryTable.TABLE)
|
||||
.where("${HistoryTable.COL_CHAPTER_ID} = ?")
|
||||
.whereArgs(obj.chapter_id)
|
||||
.build()
|
||||
|
||||
private fun mapToUpdateContentValues(history: History) =
|
||||
contentValuesOf(
|
||||
HistoryTable.COL_LAST_READ to history.last_read,
|
||||
)
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
package eu.kanade.tachiyomi.data.database.resolvers
|
||||
|
||||
import android.database.Cursor
|
||||
import com.pushtorefresh.storio.sqlite.operations.get.DefaultGetResolver
|
||||
import eu.kanade.tachiyomi.data.database.mappers.BaseMangaGetResolver
|
||||
import eu.kanade.tachiyomi.data.database.models.LibraryManga
|
||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable
|
||||
|
||||
class LibraryMangaGetResolver : DefaultGetResolver<LibraryManga>(), BaseMangaGetResolver {
|
||||
|
||||
companion object {
|
||||
val INSTANCE = LibraryMangaGetResolver()
|
||||
}
|
||||
|
||||
override fun mapFromCursor(cursor: Cursor): LibraryManga {
|
||||
val manga = LibraryManga()
|
||||
|
||||
mapBaseFromCursor(manga, cursor)
|
||||
manga.unreadCount = cursor.getInt(cursor.getColumnIndexOrThrow(MangaTable.COMPUTED_COL_UNREAD_COUNT))
|
||||
manga.category = cursor.getInt(cursor.getColumnIndexOrThrow(MangaTable.COL_CATEGORY))
|
||||
manga.readCount = cursor.getInt(cursor.getColumnIndexOrThrow(MangaTable.COMPUTED_COL_READ_COUNT))
|
||||
|
||||
return manga
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
package eu.kanade.tachiyomi.data.database.resolvers
|
||||
|
||||
import android.database.Cursor
|
||||
import com.pushtorefresh.storio.sqlite.operations.get.DefaultGetResolver
|
||||
import eu.kanade.tachiyomi.data.database.mappers.ChapterGetResolver
|
||||
import eu.kanade.tachiyomi.data.database.mappers.MangaGetResolver
|
||||
import eu.kanade.tachiyomi.data.database.models.MangaChapter
|
||||
|
||||
class MangaChapterGetResolver : DefaultGetResolver<MangaChapter>() {
|
||||
|
||||
companion object {
|
||||
val INSTANCE = MangaChapterGetResolver()
|
||||
}
|
||||
|
||||
private val mangaGetResolver = MangaGetResolver()
|
||||
|
||||
private val chapterGetResolver = ChapterGetResolver()
|
||||
|
||||
override fun mapFromCursor(cursor: Cursor): MangaChapter {
|
||||
val manga = mangaGetResolver.mapFromCursor(cursor)
|
||||
val chapter = chapterGetResolver.mapFromCursor(cursor)
|
||||
manga.id = chapter.manga_id
|
||||
manga.url = cursor.getString(cursor.getColumnIndexOrThrow("mangaUrl"))
|
||||
|
||||
return MangaChapter(manga, chapter)
|
||||
}
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
package eu.kanade.tachiyomi.data.database.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 eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable
|
||||
|
||||
class MangaFavoritePutResolver : PutResolver<Manga>() {
|
||||
|
||||
override fun performPut(db: StorIOSQLite, manga: Manga) = db.inTransactionReturn {
|
||||
val updateQuery = mapToUpdateQuery(manga)
|
||||
val contentValues = mapToContentValues(manga)
|
||||
|
||||
val numberOfRowsUpdated = db.lowLevel().update(updateQuery, contentValues)
|
||||
PutResult.newUpdateResult(numberOfRowsUpdated, updateQuery.table())
|
||||
}
|
||||
|
||||
fun mapToUpdateQuery(manga: Manga) = UpdateQuery.builder()
|
||||
.table(MangaTable.TABLE)
|
||||
.where("${MangaTable.COL_ID} = ?")
|
||||
.whereArgs(manga.id)
|
||||
.build()
|
||||
|
||||
fun mapToContentValues(manga: Manga) =
|
||||
contentValuesOf(
|
||||
MangaTable.COL_FAVORITE to manga.favorite,
|
||||
MangaTable.COL_DATE_ADDED to manga.date_added,
|
||||
)
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
package eu.kanade.tachiyomi.data.database.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 eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable
|
||||
|
||||
// [EXH]
|
||||
class MangaFilteredScanlatorsPutResolver : PutResolver<Manga>() {
|
||||
|
||||
override fun performPut(db: StorIOSQLite, manga: Manga) = db.inTransactionReturn {
|
||||
val updateQuery = mapToUpdateQuery(manga)
|
||||
val contentValues = mapToContentValues(manga)
|
||||
|
||||
val numberOfRowsUpdated = db.lowLevel().update(updateQuery, contentValues)
|
||||
PutResult.newUpdateResult(numberOfRowsUpdated, updateQuery.table())
|
||||
}
|
||||
|
||||
fun mapToUpdateQuery(manga: Manga) = UpdateQuery.builder()
|
||||
.table(MangaTable.TABLE)
|
||||
.where("${MangaTable.COL_ID} = ?")
|
||||
.whereArgs(manga.id)
|
||||
.build()
|
||||
|
||||
fun mapToContentValues(manga: Manga) = contentValuesOf(
|
||||
MangaTable.COL_FILTERED_SCANLATORS to manga.filtered_scanlators,
|
||||
)
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
package eu.kanade.tachiyomi.data.database.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 eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable
|
||||
import kotlin.reflect.KProperty1
|
||||
|
||||
class MangaFlagsPutResolver(private val colName: String, private val fieldGetter: KProperty1<Manga, Int>) : PutResolver<Manga>() {
|
||||
|
||||
override fun performPut(db: StorIOSQLite, manga: Manga) = db.inTransactionReturn {
|
||||
val updateQuery = mapToUpdateQuery(manga)
|
||||
val contentValues = mapToContentValues(manga)
|
||||
|
||||
val numberOfRowsUpdated = db.lowLevel().update(updateQuery, contentValues)
|
||||
PutResult.newUpdateResult(numberOfRowsUpdated, updateQuery.table())
|
||||
}
|
||||
|
||||
fun mapToUpdateQuery(manga: Manga) = UpdateQuery.builder()
|
||||
.table(MangaTable.TABLE)
|
||||
.where("${MangaTable.COL_ID} = ?")
|
||||
.whereArgs(manga.id)
|
||||
.build()
|
||||
|
||||
fun mapToContentValues(manga: Manga) =
|
||||
contentValuesOf(
|
||||
colName to fieldGetter.get(manga),
|
||||
)
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
package eu.kanade.tachiyomi.data.database.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 eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable
|
||||
import exh.util.nullIfZero
|
||||
|
||||
class MangaInfoPutResolver(val reset: Boolean = false) : PutResolver<Manga>() {
|
||||
|
||||
override fun performPut(db: StorIOSQLite, manga: Manga) = db.inTransactionReturn {
|
||||
val updateQuery = mapToUpdateQuery(manga)
|
||||
val contentValues = if (reset) resetToContentValues(manga) else mapToContentValues(manga)
|
||||
|
||||
val numberOfRowsUpdated = db.lowLevel().update(updateQuery, contentValues)
|
||||
PutResult.newUpdateResult(numberOfRowsUpdated, updateQuery.table())
|
||||
}
|
||||
|
||||
fun mapToUpdateQuery(manga: Manga) = UpdateQuery.builder()
|
||||
.table(MangaTable.TABLE)
|
||||
.where("${MangaTable.COL_ID} = ?")
|
||||
.whereArgs(manga.id)
|
||||
.build()
|
||||
|
||||
fun mapToContentValues(manga: Manga) = contentValuesOf(
|
||||
MangaTable.COL_TITLE to manga.originalTitle,
|
||||
MangaTable.COL_GENRE to manga.originalGenre,
|
||||
MangaTable.COL_AUTHOR to manga.originalAuthor,
|
||||
MangaTable.COL_ARTIST to manga.originalArtist,
|
||||
MangaTable.COL_DESCRIPTION to manga.originalDescription,
|
||||
MangaTable.COL_STATUS to manga.originalStatus,
|
||||
)
|
||||
|
||||
private fun resetToContentValues(manga: Manga) = contentValuesOf(
|
||||
MangaTable.COL_TITLE to manga.title.split(splitter).last(),
|
||||
MangaTable.COL_GENRE to manga.genre?.split(splitter)?.lastOrNull(),
|
||||
MangaTable.COL_AUTHOR to manga.author?.split(splitter)?.lastOrNull(),
|
||||
MangaTable.COL_ARTIST to manga.artist?.split(splitter)?.lastOrNull(),
|
||||
MangaTable.COL_DESCRIPTION to manga.description?.split(splitter)?.lastOrNull(),
|
||||
MangaTable.COL_STATUS to manga.status.nullIfZero()?.toString()?.split(splitter)?.lastOrNull(),
|
||||
)
|
||||
|
||||
companion object {
|
||||
const val splitter = "▒ ▒∩▒"
|
||||
}
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
package eu.kanade.tachiyomi.data.database.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 eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable
|
||||
|
||||
class MangaMigrationPutResolver : PutResolver<Manga>() {
|
||||
|
||||
override fun performPut(db: StorIOSQLite, manga: Manga) = db.inTransactionReturn {
|
||||
val updateQuery = mapToUpdateQuery(manga)
|
||||
val contentValues = mapToContentValues(manga)
|
||||
|
||||
val numberOfRowsUpdated = db.lowLevel().update(updateQuery, contentValues)
|
||||
PutResult.newUpdateResult(numberOfRowsUpdated, updateQuery.table())
|
||||
}
|
||||
|
||||
fun mapToUpdateQuery(manga: Manga) = UpdateQuery.builder()
|
||||
.table(MangaTable.TABLE)
|
||||
.where("${MangaTable.COL_ID} = ?")
|
||||
.whereArgs(manga.id)
|
||||
.build()
|
||||
|
||||
fun mapToContentValues(manga: Manga) = contentValuesOf(
|
||||
MangaTable.COL_FAVORITE to manga.favorite,
|
||||
MangaTable.COL_DATE_ADDED to manga.date_added,
|
||||
MangaTable.COL_TITLE to manga.title,
|
||||
MangaTable.COL_CHAPTER_FLAGS to manga.chapter_flags,
|
||||
MangaTable.COL_VIEWER to manga.viewer_flags,
|
||||
)
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
package eu.kanade.tachiyomi.data.database.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 eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable
|
||||
|
||||
// SY
|
||||
class MangaThumbnailPutResolver : PutResolver<Manga>() {
|
||||
|
||||
override fun performPut(db: StorIOSQLite, manga: Manga) = db.inTransactionReturn {
|
||||
val updateQuery = mapToUpdateQuery(manga)
|
||||
val contentValues = mapToContentValues(manga)
|
||||
|
||||
val numberOfRowsUpdated = db.lowLevel().update(updateQuery, contentValues)
|
||||
PutResult.newUpdateResult(numberOfRowsUpdated, updateQuery.table())
|
||||
}
|
||||
|
||||
fun mapToUpdateQuery(manga: Manga) = UpdateQuery.builder()
|
||||
.table(MangaTable.TABLE)
|
||||
.where("${MangaTable.COL_ID} = ?")
|
||||
.whereArgs(manga.id)
|
||||
.build()
|
||||
|
||||
fun mapToContentValues(manga: Manga) = contentValuesOf(
|
||||
MangaTable.COL_THUMBNAIL_URL to manga.thumbnail_url,
|
||||
)
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
package eu.kanade.tachiyomi.data.database.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 eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable
|
||||
|
||||
// [EXH]
|
||||
class MangaUrlPutResolver : PutResolver<Manga>() {
|
||||
|
||||
override fun performPut(db: StorIOSQLite, manga: Manga) = db.inTransactionReturn {
|
||||
val updateQuery = mapToUpdateQuery(manga)
|
||||
val contentValues = mapToContentValues(manga)
|
||||
|
||||
val numberOfRowsUpdated = db.lowLevel().update(updateQuery, contentValues)
|
||||
PutResult.newUpdateResult(numberOfRowsUpdated, updateQuery.table())
|
||||
}
|
||||
|
||||
fun mapToUpdateQuery(manga: Manga) = UpdateQuery.builder()
|
||||
.table(MangaTable.TABLE)
|
||||
.where("${MangaTable.COL_ID} = ?")
|
||||
.whereArgs(manga.id)
|
||||
.build()
|
||||
|
||||
fun mapToContentValues(manga: Manga) = contentValuesOf(
|
||||
MangaTable.COL_URL to manga.url,
|
||||
)
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
package eu.kanade.tachiyomi.data.database.tables
|
||||
|
||||
object CategoryTable {
|
||||
|
||||
const val TABLE = "categories"
|
||||
|
||||
const val COL_ID = "_id"
|
||||
|
||||
const val COL_NAME = "name"
|
||||
|
||||
const val COL_ORDER = "sort"
|
||||
|
||||
const val COL_FLAGS = "flags"
|
||||
|
||||
// SY -->
|
||||
const val COL_MANGA_ORDER = "manga_order"
|
||||
// SY <--
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
package eu.kanade.tachiyomi.data.database.tables
|
||||
|
||||
object ChapterTable {
|
||||
|
||||
const val TABLE = "chapters"
|
||||
|
||||
const val COL_ID = "_id"
|
||||
|
||||
const val COL_MANGA_ID = "manga_id"
|
||||
|
||||
const val COL_URL = "url"
|
||||
|
||||
const val COL_NAME = "name"
|
||||
|
||||
const val COL_READ = "read"
|
||||
|
||||
const val COL_SCANLATOR = "scanlator"
|
||||
|
||||
const val COL_BOOKMARK = "bookmark"
|
||||
|
||||
const val COL_DATE_FETCH = "date_fetch"
|
||||
|
||||
const val COL_DATE_UPLOAD = "date_upload"
|
||||
|
||||
const val COL_LAST_PAGE_READ = "last_page_read"
|
||||
|
||||
const val COL_CHAPTER_NUMBER = "chapter_number"
|
||||
|
||||
const val COL_SOURCE_ORDER = "source_order"
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
package eu.kanade.tachiyomi.data.database.tables
|
||||
|
||||
object HistoryTable {
|
||||
|
||||
/**
|
||||
* Table name
|
||||
*/
|
||||
const val TABLE = "history"
|
||||
|
||||
/**
|
||||
* Id column name
|
||||
*/
|
||||
const val COL_ID = "_id"
|
||||
|
||||
/**
|
||||
* Chapter id column name
|
||||
*/
|
||||
const val COL_CHAPTER_ID = "chapter_id"
|
||||
|
||||
/**
|
||||
* Last read column name
|
||||
*/
|
||||
const val COL_LAST_READ = "last_read"
|
||||
|
||||
/**
|
||||
* Time read column name
|
||||
*/
|
||||
const val COL_TIME_READ = "time_read"
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
package eu.kanade.tachiyomi.data.database.tables
|
||||
|
||||
object MangaCategoryTable {
|
||||
|
||||
const val TABLE = "mangas_categories"
|
||||
|
||||
const val COL_ID = "_id"
|
||||
|
||||
const val COL_MANGA_ID = "manga_id"
|
||||
|
||||
const val COL_CATEGORY_ID = "category_id"
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
package eu.kanade.tachiyomi.data.database.tables
|
||||
|
||||
object MangaTable {
|
||||
|
||||
const val TABLE = "mangas"
|
||||
|
||||
const val COL_ID = "_id"
|
||||
|
||||
const val COL_SOURCE = "source"
|
||||
|
||||
const val COL_URL = "url"
|
||||
|
||||
const val COL_ARTIST = "artist"
|
||||
|
||||
const val COL_AUTHOR = "author"
|
||||
|
||||
const val COL_DESCRIPTION = "description"
|
||||
|
||||
const val COL_GENRE = "genre"
|
||||
|
||||
const val COL_TITLE = "title"
|
||||
|
||||
const val COL_STATUS = "status"
|
||||
|
||||
const val COL_THUMBNAIL_URL = "thumbnail_url"
|
||||
|
||||
const val COL_FAVORITE = "favorite"
|
||||
|
||||
const val COL_LAST_UPDATE = "last_update"
|
||||
|
||||
// Not actually used anymore
|
||||
const val COL_NEXT_UPDATE = "next_update"
|
||||
|
||||
const val COL_DATE_ADDED = "date_added"
|
||||
|
||||
const val COL_INITIALIZED = "initialized"
|
||||
|
||||
const val COL_VIEWER = "viewer"
|
||||
|
||||
const val COL_CHAPTER_FLAGS = "chapter_flags"
|
||||
|
||||
// SY -->
|
||||
const val COL_FILTERED_SCANLATORS = "filtered_scanlators"
|
||||
// SY <--
|
||||
|
||||
const val COL_CATEGORY = "category"
|
||||
|
||||
const val COL_COVER_LAST_MODIFIED = "cover_last_modified"
|
||||
|
||||
// Not an actual value but computed when created
|
||||
const val COMPUTED_COL_UNREAD_COUNT = "unread_count"
|
||||
|
||||
const val COMPUTED_COL_READ_COUNT = "read_count"
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
package eu.kanade.tachiyomi.data.database.tables
|
||||
|
||||
object TrackTable {
|
||||
|
||||
const val TABLE = "manga_sync"
|
||||
|
||||
const val COL_ID = "_id"
|
||||
|
||||
const val COL_MANGA_ID = "manga_id"
|
||||
|
||||
const val COL_SYNC_ID = "sync_id"
|
||||
|
||||
const val COL_MEDIA_ID = "remote_id"
|
||||
|
||||
const val COL_LIBRARY_ID = "library_id"
|
||||
|
||||
const val COL_TITLE = "title"
|
||||
|
||||
const val COL_LAST_CHAPTER_READ = "last_chapter_read"
|
||||
|
||||
const val COL_STATUS = "status"
|
||||
|
||||
const val COL_SCORE = "score"
|
||||
|
||||
const val COL_TOTAL_CHAPTERS = "total_chapters"
|
||||
|
||||
const val COL_TRACKING_URL = "remote_url"
|
||||
|
||||
const val COL_START_DATE = "start_date"
|
||||
|
||||
const val COL_FINISH_DATE = "finish_date"
|
||||
}
|
@ -5,7 +5,6 @@ import com.hippo.unifile.UniFile
|
||||
import com.jakewharton.rxrelay.BehaviorRelay
|
||||
import eu.kanade.domain.category.interactor.GetCategories
|
||||
import eu.kanade.tachiyomi.R
|
||||
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.download.model.Download
|
||||
@ -34,7 +33,6 @@ import uy.kohesive.injekt.injectLazy
|
||||
*/
|
||||
class DownloadManager(
|
||||
private val context: Context,
|
||||
private val db: DatabaseHelper = Injekt.get(),
|
||||
private val getCategories: GetCategories = Injekt.get(),
|
||||
) {
|
||||
|
||||
|
@ -14,18 +14,21 @@ import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource
|
||||
import eu.kanade.domain.chapter.interactor.SyncChaptersWithTrackServiceTwoWay
|
||||
import eu.kanade.domain.chapter.model.toDbChapter
|
||||
import eu.kanade.domain.manga.interactor.GetFavorites
|
||||
import eu.kanade.domain.manga.interactor.GetLibraryManga
|
||||
import eu.kanade.domain.manga.interactor.GetManga
|
||||
import eu.kanade.domain.manga.interactor.GetMergedMangaForDownloading
|
||||
import eu.kanade.domain.manga.interactor.InsertFlatMetadata
|
||||
import eu.kanade.domain.manga.interactor.InsertManga
|
||||
import eu.kanade.domain.manga.interactor.UpdateManga
|
||||
import eu.kanade.domain.manga.model.toDbManga
|
||||
import eu.kanade.domain.manga.model.toMangaInfo
|
||||
import eu.kanade.domain.manga.model.toMangaUpdate
|
||||
import eu.kanade.domain.track.interactor.GetTracks
|
||||
import eu.kanade.domain.track.interactor.InsertTrack
|
||||
import eu.kanade.domain.track.model.toDbTrack
|
||||
import eu.kanade.domain.track.model.toDomainTrack
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||
import eu.kanade.tachiyomi.data.database.models.LibraryManga
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
@ -47,6 +50,7 @@ import eu.kanade.tachiyomi.data.track.TrackStatus
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
import eu.kanade.tachiyomi.source.UnmeteredSource
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.source.model.toMangaInfo
|
||||
import eu.kanade.tachiyomi.source.model.toSChapter
|
||||
import eu.kanade.tachiyomi.source.model.toSManga
|
||||
import eu.kanade.tachiyomi.source.online.all.MergedSource
|
||||
@ -67,7 +71,6 @@ import exh.source.LIBRARY_UPDATE_EXCLUDED_SOURCES
|
||||
import exh.source.MERGED_SOURCE_ID
|
||||
import exh.source.isMdBasedSource
|
||||
import exh.source.mangaDexSourceIds
|
||||
import exh.util.executeOnIO
|
||||
import exh.util.nullIfBlank
|
||||
import kotlinx.coroutines.CoroutineExceptionHandler
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
@ -102,12 +105,12 @@ import eu.kanade.domain.manga.model.Manga as DomainManga
|
||||
* destroyed.
|
||||
*/
|
||||
class LibraryUpdateService(
|
||||
val db: DatabaseHelper = Injekt.get(),
|
||||
val sourceManager: SourceManager = Injekt.get(),
|
||||
val preferences: PreferencesHelper = Injekt.get(),
|
||||
val downloadManager: DownloadManager = Injekt.get(),
|
||||
val trackManager: TrackManager = Injekt.get(),
|
||||
val coverCache: CoverCache = Injekt.get(),
|
||||
private val getLibraryManga: GetLibraryManga = Injekt.get(),
|
||||
private val getManga: GetManga = Injekt.get(),
|
||||
private val updateManga: UpdateManga = Injekt.get(),
|
||||
private val getChapterByMangaId: GetChapterByMangaId = Injekt.get(),
|
||||
@ -119,6 +122,8 @@ class LibraryUpdateService(
|
||||
// SY -->
|
||||
private val getFavorites: GetFavorites = Injekt.get(),
|
||||
private val insertFlatMetadata: InsertFlatMetadata = Injekt.get(),
|
||||
private val insertManga: InsertManga = Injekt.get(),
|
||||
private val getMergedMangaForDownloading: GetMergedMangaForDownloading = Injekt.get(),
|
||||
// SY <--
|
||||
) : Service() {
|
||||
|
||||
@ -301,7 +306,7 @@ class LibraryUpdateService(
|
||||
* @param categoryId the ID of the category to update, or -1 if no category specified.
|
||||
*/
|
||||
fun addMangaToQueue(categoryId: Long, group: Int, groupExtra: String?) {
|
||||
val libraryManga = db.getLibraryMangas().executeAsBlocking()
|
||||
val libraryManga = runBlocking { getLibraryManga.await() }
|
||||
// SY -->
|
||||
val groupLibraryUpdateType = preferences.groupLibraryUpdateType().get()
|
||||
// SY <--
|
||||
@ -499,12 +504,12 @@ class LibraryUpdateService(
|
||||
// may don't like it and they could ban the user.
|
||||
// SY -->
|
||||
if (manga.source == MERGED_SOURCE_ID) {
|
||||
val downloadingManga = db.getMergedMangasForDownloading(manga.id!!).executeAsBlocking()
|
||||
.associateBy { it.id!! }
|
||||
val downloadingManga = runBlocking { getMergedMangaForDownloading.await(manga.id!!) }
|
||||
.associateBy { it.id }
|
||||
chapters.groupBy { it.manga_id }
|
||||
.forEach {
|
||||
downloadManager.downloadChapters(
|
||||
downloadingManga[it.key] ?: return@forEach,
|
||||
downloadingManga[it.key]?.toDbManga() ?: return@forEach,
|
||||
chapters,
|
||||
false,
|
||||
)
|
||||
@ -593,7 +598,14 @@ class LibraryUpdateService(
|
||||
mangaWithNotif.prepUpdateCover(coverCache, sManga, true)
|
||||
sManga.thumbnail_url?.let {
|
||||
mangaWithNotif.thumbnail_url = it
|
||||
db.insertManga(mangaWithNotif).executeAsBlocking()
|
||||
try {
|
||||
updateManga.await(
|
||||
mangaWithNotif.toDomainManga()!!
|
||||
.toMangaUpdate(),
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
logcat(LogPriority.ERROR) { "Manga don't exist anymore" }
|
||||
}
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
// Ignore errors and continue
|
||||
@ -714,24 +726,29 @@ class LibraryUpdateService(
|
||||
count++
|
||||
notifier.showProgressNotification(listOf(networkManga), count, size)
|
||||
|
||||
var dbManga = db.getManga(networkManga.url, mangaDex.id)
|
||||
.executeOnIO()
|
||||
var dbManga = getManga.await(networkManga.url, mangaDex.id)
|
||||
|
||||
if (dbManga == null) {
|
||||
dbManga = Manga.create(
|
||||
val newManga = Manga.create(
|
||||
networkManga.url,
|
||||
networkManga.title,
|
||||
mangaDex.id,
|
||||
)
|
||||
dbManga.date_added = System.currentTimeMillis()
|
||||
newManga.favorite = true
|
||||
newManga.date_added = System.currentTimeMillis()
|
||||
newManga.id = -1
|
||||
val result = runBlocking {
|
||||
val id = insertManga.await(newManga.toDomainManga()!!)
|
||||
getManga.await(id!!)
|
||||
}
|
||||
dbManga = result ?: return
|
||||
} else if (!dbManga.favorite) {
|
||||
updateManga.awaitUpdateFavorite(dbManga.id, true)
|
||||
}
|
||||
|
||||
dbManga.copyFrom(networkManga)
|
||||
dbManga.favorite = true
|
||||
val id = db.insertManga(dbManga).executeOnIO().insertedId()
|
||||
if (id != null) {
|
||||
metadata.mangaId = id
|
||||
insertFlatMetadata.await(metadata)
|
||||
}
|
||||
updateManga.awaitUpdateFromSource(dbManga, networkManga.toMangaInfo(), true)
|
||||
metadata.mangaId = dbManga.id
|
||||
insertFlatMetadata.await(metadata)
|
||||
}
|
||||
|
||||
notifier.cancelProgressNotification()
|
||||
|
@ -4,7 +4,11 @@ import eu.kanade.domain.category.interactor.GetCategories
|
||||
import eu.kanade.domain.chapter.interactor.GetMergedChapterByMangaId
|
||||
import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource
|
||||
import eu.kanade.domain.chapter.model.toDbChapter
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
import eu.kanade.domain.manga.interactor.GetManga
|
||||
import eu.kanade.domain.manga.interactor.GetMergedReferencesById
|
||||
import eu.kanade.domain.manga.interactor.InsertManga
|
||||
import eu.kanade.domain.manga.model.toDbManga
|
||||
import eu.kanade.domain.manga.model.toMangaInfo
|
||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.database.models.toDomainManga
|
||||
@ -22,7 +26,6 @@ import eu.kanade.tachiyomi.source.model.toSManga
|
||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
import eu.kanade.tachiyomi.util.lang.withIOContext
|
||||
import eu.kanade.tachiyomi.util.shouldDownloadNewChapters
|
||||
import exh.log.xLogW
|
||||
import exh.merged.sql.models.MergedMangaReference
|
||||
import exh.source.MERGED_SOURCE_ID
|
||||
import kotlinx.coroutines.CancellationException
|
||||
@ -42,8 +45,10 @@ import eu.kanade.domain.chapter.model.Chapter as DomainChapter
|
||||
import eu.kanade.domain.manga.model.Manga as DomainManga
|
||||
|
||||
class MergedSource : HttpSource() {
|
||||
private val db: DatabaseHelper by injectLazy()
|
||||
private val getManga: GetManga by injectLazy()
|
||||
private val getMergedReferencesById: GetMergedReferencesById by injectLazy()
|
||||
private val getMergedChaptersByMangaId: GetMergedChapterByMangaId by injectLazy()
|
||||
private val insertManga: InsertManga by injectLazy()
|
||||
private val getCategories: GetCategories by injectLazy()
|
||||
private val sourceManager: SourceManager by injectLazy()
|
||||
private val downloadManager: DownloadManager by injectLazy()
|
||||
@ -74,9 +79,8 @@ class MergedSource : HttpSource() {
|
||||
|
||||
override suspend fun getMangaDetails(manga: MangaInfo): MangaInfo {
|
||||
return withIOContext {
|
||||
val mergedManga = db.getManga(manga.key, id).executeAsBlocking()
|
||||
?: throw Exception("merged manga not in db")
|
||||
val mangaReferences = db.getMergedMangaReferences(mergedManga.id!!).executeAsBlocking()
|
||||
val mergedManga = getManga.await(manga.key, id) ?: throw Exception("merged manga not in db")
|
||||
val mangaReferences = getMergedReferencesById.await(mergedManga.id)
|
||||
.apply {
|
||||
if (isEmpty()) {
|
||||
throw IllegalArgumentException(
|
||||
@ -93,7 +97,7 @@ class MergedSource : HttpSource() {
|
||||
val mangaInfoReference = mangaReferences.firstOrNull { it.isInfoManga }
|
||||
?: mangaReferences.firstOrNull { it.mangaId != it.mergeId }
|
||||
val dbManga = mangaInfoReference?.run {
|
||||
db.getManga(mangaUrl, mangaSourceId).executeAsBlocking()?.toMangaInfo()
|
||||
getManga.await(mangaUrl, mangaSourceId)?.toMangaInfo()
|
||||
}
|
||||
(dbManga ?: mergedManga.toMangaInfo()).copy(
|
||||
key = manga.key,
|
||||
@ -102,8 +106,8 @@ class MergedSource : HttpSource() {
|
||||
}
|
||||
|
||||
// TODO more chapter dedupe
|
||||
fun transformMergedChapters(mangaId: Long, chapterList: List<DomainChapter>, editScanlators: Boolean, dedupe: Boolean): List<DomainChapter> {
|
||||
val mangaReferences = db.getMergedMangaReferences(mangaId).executeAsBlocking()
|
||||
suspend fun transformMergedChapters(mangaId: Long, chapterList: List<DomainChapter>, editScanlators: Boolean, dedupe: Boolean): List<DomainChapter> {
|
||||
val mangaReferences = getMergedReferencesById.await(mangaId)
|
||||
val chapters = if (editScanlators) {
|
||||
val sources = mangaReferences.map { sourceManager.getOrStub(it.mangaSourceId) to it.mangaId }
|
||||
chapterList.map { chapter ->
|
||||
@ -127,7 +131,11 @@ class MergedSource : HttpSource() {
|
||||
}
|
||||
|
||||
fun getChaptersAsBlocking(mangaId: Long, editScanlators: Boolean = false, dedupe: Boolean = true): List<DomainChapter> {
|
||||
return transformMergedChapters(mangaId, runBlocking { getMergedChaptersByMangaId.await(mangaId) }, editScanlators, dedupe)
|
||||
return runBlocking { getChapters(mangaId, editScanlators, dedupe) }
|
||||
}
|
||||
|
||||
suspend fun getChapters(mangaId: Long, editScanlators: Boolean = false, dedupe: Boolean = true): List<DomainChapter> {
|
||||
return transformMergedChapters(mangaId, getMergedChaptersByMangaId.await(mangaId), editScanlators, dedupe)
|
||||
}
|
||||
|
||||
private fun dedupeChapterList(mangaReferences: List<MergedMangaReference>, chapterList: List<DomainChapter>): List<DomainChapter> {
|
||||
@ -165,7 +173,7 @@ class MergedSource : HttpSource() {
|
||||
|
||||
suspend fun fetchChaptersAndSync(manga: DomainManga, downloadChapters: Boolean = true): Pair<List<DomainChapter>, List<DomainChapter>> {
|
||||
val syncChaptersWithSource = Injekt.get<SyncChaptersWithSource>()
|
||||
val mangaReferences = db.getMergedMangaReferences(manga.id).executeAsBlocking()
|
||||
val mangaReferences = getMergedReferencesById.await(manga.id)
|
||||
if (mangaReferences.isEmpty()) {
|
||||
throw IllegalArgumentException("Manga references are empty, chapters unavailable, merge is likely corrupted")
|
||||
}
|
||||
@ -183,15 +191,15 @@ class MergedSource : HttpSource() {
|
||||
values.map {
|
||||
try {
|
||||
val (source, loadedManga, reference) =
|
||||
it.load(db, sourceManager)
|
||||
it.load(sourceManager, getManga, insertManga)
|
||||
if (loadedManga != null && reference.getChapterUpdates) {
|
||||
val chapterList = source.getChapterList(loadedManga.toMangaInfo())
|
||||
.map(ChapterInfo::toSChapter)
|
||||
val results =
|
||||
syncChaptersWithSource.await(chapterList, loadedManga.toDomainManga()!!, source)
|
||||
syncChaptersWithSource.await(chapterList, loadedManga, source)
|
||||
if (ifDownloadNewChapters && reference.downloadChapters) {
|
||||
downloadManager.downloadChapters(
|
||||
loadedManga,
|
||||
loadedManga.toDbManga(),
|
||||
results.first.map(DomainChapter::toDbChapter),
|
||||
)
|
||||
}
|
||||
@ -218,26 +226,25 @@ class MergedSource : HttpSource() {
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun MergedMangaReference.load(db: DatabaseHelper, sourceManager: SourceManager): LoadedMangaSource {
|
||||
var manga = db.getManga(mangaUrl, mangaSourceId).executeAsBlocking()
|
||||
suspend fun MergedMangaReference.load(sourceManager: SourceManager, getManga: GetManga, insertManga: InsertManga): LoadedMangaSource {
|
||||
var manga = getManga.await(mangaUrl, mangaSourceId)
|
||||
val source = sourceManager.getOrStub(manga?.source ?: mangaSourceId)
|
||||
if (manga == null) {
|
||||
manga = Manga.create(mangaSourceId).apply {
|
||||
val newManga = Manga.create(mangaSourceId).apply {
|
||||
url = mangaUrl
|
||||
}
|
||||
manga.copyFrom(source.getMangaDetails(manga.toMangaInfo()).toSManga())
|
||||
try {
|
||||
manga.id = db.insertManga(manga).executeAsBlocking().insertedId()
|
||||
mangaId = manga.id
|
||||
db.insertNewMergedMangaId(this).executeAsBlocking()
|
||||
} catch (e: Exception) {
|
||||
xLogW("Error inserting merged manga id", e)
|
||||
newManga.copyFrom(source.getMangaDetails(newManga.toMangaInfo()).toSManga())
|
||||
newManga.id = -1
|
||||
val result = run {
|
||||
val id = insertManga.await(newManga.toDomainManga()!!)
|
||||
getManga.await(id!!)
|
||||
}
|
||||
manga = result
|
||||
}
|
||||
return LoadedMangaSource(source, manga, this)
|
||||
}
|
||||
|
||||
data class LoadedMangaSource(val source: Source, val manga: Manga?, val reference: MergedMangaReference)
|
||||
data class LoadedMangaSource(val source: Source, val manga: DomainManga?, val reference: MergedMangaReference)
|
||||
|
||||
override val lang = "all"
|
||||
override val supportsLatest = false
|
||||
|
@ -4,8 +4,13 @@ import android.os.Bundle
|
||||
import eu.kanade.data.DatabaseHandler
|
||||
import eu.kanade.data.exh.feedSavedSearchMapper
|
||||
import eu.kanade.data.exh.savedSearchMapper
|
||||
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.interactor.UpdateManga
|
||||
import eu.kanade.domain.manga.model.toDbManga
|
||||
import eu.kanade.domain.manga.model.toMangaUpdate
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.database.models.toDomainManga
|
||||
import eu.kanade.tachiyomi.data.database.models.toMangaInfo
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||
@ -23,6 +28,7 @@ import exh.savedsearches.models.FeedSavedSearch
|
||||
import exh.savedsearches.models.SavedSearch
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.json.Json
|
||||
import logcat.LogPriority
|
||||
@ -40,14 +46,16 @@ import xyz.nulldev.ts.api.http.serializer.FilterSerializer
|
||||
* Function calls should be done from here. UI calls should be done from the controller.
|
||||
*
|
||||
* @param sourceManager manages the different sources.
|
||||
* @param database manages the database calls.
|
||||
* @param handler manages the database calls.
|
||||
* @param preferences manages the preference calls.
|
||||
*/
|
||||
open class FeedPresenter(
|
||||
val sourceManager: SourceManager = Injekt.get(),
|
||||
val database: DatabaseHandler = Injekt.get(),
|
||||
val db: DatabaseHelper = Injekt.get(),
|
||||
val handler: DatabaseHandler = Injekt.get(),
|
||||
val preferences: PreferencesHelper = Injekt.get(),
|
||||
private val getManga: GetManga = Injekt.get(),
|
||||
private val insertManga: InsertManga = Injekt.get(),
|
||||
private val updateManga: UpdateManga = Injekt.get(),
|
||||
) : BasePresenter<FeedController>() {
|
||||
|
||||
/**
|
||||
@ -68,7 +76,7 @@ open class FeedPresenter(
|
||||
override fun onCreate(savedState: Bundle?) {
|
||||
super.onCreate(savedState)
|
||||
|
||||
database.subscribeToList { feed_saved_searchQueries.selectAllGlobal() }
|
||||
handler.subscribeToList { feed_saved_searchQueries.selectAllGlobal() }
|
||||
.onEach {
|
||||
getFeed()
|
||||
}
|
||||
@ -82,7 +90,7 @@ open class FeedPresenter(
|
||||
}
|
||||
|
||||
suspend fun hasTooManyFeeds(): Boolean {
|
||||
return database.awaitOne { feed_saved_searchQueries.countGlobal() } > 10
|
||||
return handler.awaitOne { feed_saved_searchQueries.countGlobal() } > 10
|
||||
}
|
||||
|
||||
fun getEnabledSources(): List<CatalogueSource> {
|
||||
@ -97,12 +105,12 @@ open class FeedPresenter(
|
||||
}
|
||||
|
||||
suspend fun getSourceSavedSearches(source: CatalogueSource): List<SavedSearch> {
|
||||
return database.awaitList { saved_searchQueries.selectBySource(source.id, savedSearchMapper) }
|
||||
return handler.awaitList { saved_searchQueries.selectBySource(source.id, savedSearchMapper) }
|
||||
}
|
||||
|
||||
fun createFeed(source: CatalogueSource, savedSearch: SavedSearch?) {
|
||||
launchIO {
|
||||
database.await {
|
||||
handler.await {
|
||||
feed_saved_searchQueries.insertFeedSavedSearch(
|
||||
_id = null,
|
||||
source = source.id,
|
||||
@ -115,17 +123,17 @@ open class FeedPresenter(
|
||||
|
||||
fun deleteFeed(feed: FeedSavedSearch) {
|
||||
launchIO {
|
||||
database.await {
|
||||
handler.await {
|
||||
feed_saved_searchQueries.deleteById(feed.id ?: return@await)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun getSourcesToGetFeed(): List<Pair<FeedSavedSearch, SavedSearch?>> {
|
||||
val savedSearches = database.awaitList {
|
||||
val savedSearches = handler.awaitList {
|
||||
feed_saved_searchQueries.selectGlobalFeedSavedSearch(savedSearchMapper)
|
||||
}.associateBy { it.id }
|
||||
return database.awaitList { feed_saved_searchQueries.selectAllGlobal(feedSavedSearchMapper) }
|
||||
return handler.awaitList { feed_saved_searchQueries.selectAllGlobal(feedSavedSearchMapper) }
|
||||
.map { it to savedSearches[it.savedSearch] }
|
||||
}
|
||||
|
||||
@ -263,7 +271,7 @@ open class FeedPresenter(
|
||||
val networkManga = source.getMangaDetails(manga.toMangaInfo())
|
||||
manga.copyFrom(networkManga.toSManga())
|
||||
manga.initialized = true
|
||||
db.insertManga(manga).executeAsBlocking()
|
||||
updateManga.await(manga.toDomainManga()!!.toMangaUpdate())
|
||||
manga
|
||||
}
|
||||
.onErrorResumeNext { Observable.just(manga) }
|
||||
@ -276,15 +284,22 @@ open class FeedPresenter(
|
||||
* @param sManga the manga from the source.
|
||||
* @return a manga from the database.
|
||||
*/
|
||||
protected open fun networkToLocalManga(sManga: SManga, sourceId: Long): Manga {
|
||||
var localManga = db.getManga(sManga.url, sourceId).executeAsBlocking()
|
||||
private fun networkToLocalManga(sManga: SManga, sourceId: Long): Manga {
|
||||
var localManga = runBlocking { 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).executeAsBlocking()
|
||||
newManga.id = result.insertedId()
|
||||
localManga = newManga
|
||||
newManga.id = -1
|
||||
val result = runBlocking {
|
||||
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()!!
|
||||
}
|
||||
}
|
||||
|
@ -5,8 +5,9 @@ import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import androidx.appcompat.widget.SearchView
|
||||
import androidx.core.os.bundleOf
|
||||
import eu.kanade.domain.manga.interactor.GetManga
|
||||
import eu.kanade.domain.manga.model.toDbManga
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
@ -17,6 +18,7 @@ import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchPresenter
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import reactivecircus.flowbinding.appcompat.QueryTextEvent
|
||||
import reactivecircus.flowbinding.appcompat.queryTextEvents
|
||||
import uy.kohesive.injekt.Injekt
|
||||
@ -34,7 +36,11 @@ class SearchController(
|
||||
) {
|
||||
constructor(targetController: MigrationListController?, mangaId: Long, sources: LongArray) :
|
||||
this(
|
||||
Injekt.get<DatabaseHelper>().getManga(mangaId).executeAsBlocking(),
|
||||
runBlocking {
|
||||
Injekt.get<GetManga>()
|
||||
.await(mangaId)
|
||||
?.toDbManga()
|
||||
},
|
||||
sources.map { Injekt.get<SourceManager>().getOrStub(it) }.filterIsInstance<CatalogueSource>(),
|
||||
) {
|
||||
this.targetController = targetController
|
||||
|
@ -9,11 +9,14 @@ import eu.kanade.domain.category.interactor.SetMangaCategories
|
||||
import eu.kanade.domain.chapter.interactor.GetChapterByMangaId
|
||||
import eu.kanade.domain.chapter.interactor.SyncChaptersWithTrackServiceTwoWay
|
||||
import eu.kanade.domain.manga.interactor.GetDuplicateLibraryManga
|
||||
import eu.kanade.domain.manga.interactor.GetManga
|
||||
import eu.kanade.domain.manga.interactor.InsertManga
|
||||
import eu.kanade.domain.manga.interactor.UpdateManga
|
||||
import eu.kanade.domain.manga.model.toDbManga
|
||||
import eu.kanade.domain.manga.model.toMangaUpdate
|
||||
import eu.kanade.domain.track.interactor.InsertTrack
|
||||
import eu.kanade.domain.track.model.toDomainTrack
|
||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.database.models.toDomainManga
|
||||
import eu.kanade.tachiyomi.data.database.models.toMangaInfo
|
||||
@ -87,14 +90,16 @@ open class BrowseSourcePresenter(
|
||||
private val savedSearch: Long? = null,
|
||||
// SY <--
|
||||
private val sourceManager: SourceManager = Injekt.get(),
|
||||
private val db: DatabaseHelper = Injekt.get(),
|
||||
private val database: DatabaseHandler = Injekt.get(),
|
||||
private val prefs: PreferencesHelper = Injekt.get(),
|
||||
private val coverCache: CoverCache = Injekt.get(),
|
||||
private val getManga: GetManga = Injekt.get(),
|
||||
private val getDuplicateLibraryManga: GetDuplicateLibraryManga = Injekt.get(),
|
||||
private val getCategories: GetCategories = Injekt.get(),
|
||||
private val getChapterByMangaId: GetChapterByMangaId = Injekt.get(),
|
||||
private val setMangaCategories: SetMangaCategories = Injekt.get(),
|
||||
private val insertManga: InsertManga = Injekt.get(),
|
||||
private val updateManga: UpdateManga = Injekt.get(),
|
||||
private val insertTrack: InsertTrack = Injekt.get(),
|
||||
private val syncChaptersWithTrackServiceTwoWay: SyncChaptersWithTrackServiceTwoWay = Injekt.get(),
|
||||
) : BasePresenter<BrowseSourceController>() {
|
||||
@ -278,19 +283,22 @@ open class BrowseSourcePresenter(
|
||||
* @return a manga from the database.
|
||||
*/
|
||||
private fun networkToLocalManga(sManga: SManga, sourceId: Long): Manga {
|
||||
var localManga = db.getManga(sManga.url, sourceId).executeAsBlocking()
|
||||
var localManga = runBlocking { 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).executeAsBlocking()
|
||||
newManga.id = result.insertedId()
|
||||
localManga = newManga
|
||||
newManga.id = -1
|
||||
val result = runBlocking {
|
||||
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.title = sManga.title
|
||||
localManga = localManga.copy(ogTitle = sManga.title)
|
||||
}
|
||||
return localManga
|
||||
return localManga?.toDbManga()!!
|
||||
}
|
||||
|
||||
/**
|
||||
@ -325,7 +333,11 @@ open class BrowseSourcePresenter(
|
||||
val networkManga = source.getMangaDetails(manga.toMangaInfo())
|
||||
manga.copyFrom(networkManga.toSManga())
|
||||
manga.initialized = true
|
||||
db.insertManga(manga).executeAsBlocking()
|
||||
updateManga.await(
|
||||
manga
|
||||
.toDomainManga()
|
||||
?.toMangaUpdate()!!,
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
logcat(LogPriority.ERROR, e)
|
||||
}
|
||||
@ -352,7 +364,13 @@ open class BrowseSourcePresenter(
|
||||
autoAddTrack(manga)
|
||||
}
|
||||
|
||||
db.insertManga(manga).executeAsBlocking()
|
||||
runBlocking {
|
||||
updateManga.await(
|
||||
manga
|
||||
.toDomainManga()
|
||||
?.toMangaUpdate()!!,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun autoAddTrack(manga: Manga) {
|
||||
|
@ -5,8 +5,13 @@ import eu.davidea.flexibleadapter.items.IFlexible
|
||||
import eu.kanade.data.DatabaseHandler
|
||||
import eu.kanade.data.exh.feedSavedSearchMapper
|
||||
import eu.kanade.data.exh.savedSearchMapper
|
||||
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.interactor.UpdateManga
|
||||
import eu.kanade.domain.manga.model.toDbManga
|
||||
import eu.kanade.domain.manga.model.toMangaUpdate
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.database.models.toDomainManga
|
||||
import eu.kanade.tachiyomi.data.database.models.toMangaInfo
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||
@ -28,6 +33,7 @@ import exh.savedsearches.models.SavedSearch
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.JsonArray
|
||||
@ -40,7 +46,6 @@ import rx.subjects.PublishSubject
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import xyz.nulldev.ts.api.http.serializer.FilterSerializer
|
||||
import java.lang.RuntimeException
|
||||
|
||||
sealed class SourceFeed {
|
||||
object Latest : SourceFeed()
|
||||
@ -53,14 +58,16 @@ sealed class SourceFeed {
|
||||
* Function calls should be done from here. UI calls should be done from the controller.
|
||||
*
|
||||
* @param source the source.
|
||||
* @param database manages the database calls.
|
||||
* @param handler manages the database calls.
|
||||
* @param preferences manages the preference calls.
|
||||
*/
|
||||
open class SourceFeedPresenter(
|
||||
val source: CatalogueSource,
|
||||
val database: DatabaseHandler = Injekt.get(),
|
||||
val db: DatabaseHelper = Injekt.get(),
|
||||
val handler: DatabaseHandler = Injekt.get(),
|
||||
val preferences: PreferencesHelper = Injekt.get(),
|
||||
private val getManga: GetManga = Injekt.get(),
|
||||
private val insertManga: InsertManga = Injekt.get(),
|
||||
private val updateManga: UpdateManga = Injekt.get(),
|
||||
) : BasePresenter<SourceFeedController>() {
|
||||
|
||||
/**
|
||||
@ -98,7 +105,7 @@ open class SourceFeedPresenter(
|
||||
|
||||
sourceFilters = source.getFilterList()
|
||||
|
||||
database.subscribeToList { feed_saved_searchQueries.selectSourceFeedSavedSearch(source.id, savedSearchMapper) }
|
||||
handler.subscribeToList { feed_saved_searchQueries.selectSourceFeedSavedSearch(source.id, savedSearchMapper) }
|
||||
.onEach {
|
||||
getFeed()
|
||||
}
|
||||
@ -113,19 +120,19 @@ open class SourceFeedPresenter(
|
||||
|
||||
suspend fun hasTooManyFeeds(): Boolean {
|
||||
return withIOContext {
|
||||
database.awaitList {
|
||||
handler.awaitList {
|
||||
feed_saved_searchQueries.selectSourceFeedSavedSearch(source.id)
|
||||
}.size > 10
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getSourceSavedSearches(): List<SavedSearch> {
|
||||
return database.awaitList { saved_searchQueries.selectBySource(source.id, savedSearchMapper) }
|
||||
return handler.awaitList { saved_searchQueries.selectBySource(source.id, savedSearchMapper) }
|
||||
}
|
||||
|
||||
fun createFeed(savedSearchId: Long) {
|
||||
launchIO {
|
||||
database.await {
|
||||
handler.await {
|
||||
feed_saved_searchQueries.insertFeedSavedSearch(
|
||||
_id = null,
|
||||
source = source.id,
|
||||
@ -138,12 +145,12 @@ open class SourceFeedPresenter(
|
||||
|
||||
fun deleteFeed(feed: FeedSavedSearch) {
|
||||
launchIO {
|
||||
database.await { feed_saved_searchQueries.deleteById(feed.id ?: return@await) }
|
||||
handler.await { feed_saved_searchQueries.deleteById(feed.id ?: return@await) }
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun getSourcesToGetFeed(): List<SourceFeed> {
|
||||
val savedSearches = database.awaitList { feed_saved_searchQueries.selectSourceFeedSavedSearch(source.id, savedSearchMapper) }
|
||||
val savedSearches = handler.awaitList { feed_saved_searchQueries.selectSourceFeedSavedSearch(source.id, savedSearchMapper) }
|
||||
.associateBy { it.id!! }
|
||||
|
||||
return listOfNotNull(
|
||||
@ -151,7 +158,7 @@ open class SourceFeedPresenter(
|
||||
SourceFeed.Latest
|
||||
} else null,
|
||||
SourceFeed.Browse,
|
||||
) + database.awaitList { feed_saved_searchQueries.selectBySource(source.id, feedSavedSearchMapper) }
|
||||
) + handler.awaitList { feed_saved_searchQueries.selectBySource(source.id, feedSavedSearchMapper) }
|
||||
.map { SourceFeed.SourceSavedSearch(it, savedSearches[it.savedSearch]!!) }
|
||||
}
|
||||
|
||||
@ -284,7 +291,7 @@ open class SourceFeedPresenter(
|
||||
val networkManga = source.getMangaDetails(manga.toMangaInfo())
|
||||
manga.copyFrom(networkManga.toSManga())
|
||||
manga.initialized = true
|
||||
db.insertManga(manga).executeAsBlocking()
|
||||
updateManga.await(manga.toDomainManga()!!.toMangaUpdate())
|
||||
manga
|
||||
}
|
||||
.onErrorResumeNext { Observable.just(manga) }
|
||||
@ -297,21 +304,28 @@ open class SourceFeedPresenter(
|
||||
* @param sManga the manga from the source.
|
||||
* @return a manga from the database.
|
||||
*/
|
||||
protected open fun networkToLocalManga(sManga: SManga, sourceId: Long): Manga {
|
||||
var localManga = db.getManga(sManga.url, sourceId).executeAsBlocking()
|
||||
private fun networkToLocalManga(sManga: SManga, sourceId: Long): Manga {
|
||||
var localManga = runBlocking { 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).executeAsBlocking()
|
||||
newManga.id = result.insertedId()
|
||||
localManga = newManga
|
||||
newManga.id = -1
|
||||
val result = runBlocking {
|
||||
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()!!
|
||||
}
|
||||
|
||||
suspend fun loadSearch(searchId: Long): EXHSavedSearch? {
|
||||
return withIOContext {
|
||||
val search = database.awaitOneOrNull {
|
||||
val search = handler.awaitOneOrNull {
|
||||
saved_searchQueries.selectById(searchId, savedSearchMapper)
|
||||
} ?: return@withIOContext null
|
||||
EXHSavedSearch(
|
||||
@ -334,7 +348,7 @@ open class SourceFeedPresenter(
|
||||
|
||||
suspend fun loadSearches(): List<EXHSavedSearch> {
|
||||
return withIOContext {
|
||||
database.awaitList { saved_searchQueries.selectBySource(source.id, savedSearchMapper) }.map {
|
||||
handler.awaitList { saved_searchQueries.selectBySource(source.id, savedSearchMapper) }.map {
|
||||
val filtersJson = it.filtersJson ?: return@map EXHSavedSearch(
|
||||
id = it.id!!,
|
||||
name = it.name,
|
||||
|
@ -1,8 +1,13 @@
|
||||
package eu.kanade.tachiyomi.ui.browse.source.globalsearch
|
||||
|
||||
import android.os.Bundle
|
||||
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.interactor.UpdateManga
|
||||
import eu.kanade.domain.manga.model.toDbManga
|
||||
import eu.kanade.domain.manga.model.toMangaUpdate
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.database.models.toDomainManga
|
||||
import eu.kanade.tachiyomi.data.database.models.toMangaInfo
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.extension.ExtensionManager
|
||||
@ -16,6 +21,7 @@ import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
||||
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourcePresenter
|
||||
import eu.kanade.tachiyomi.util.lang.runAsObservable
|
||||
import eu.kanade.tachiyomi.util.system.logcat
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import logcat.LogPriority
|
||||
import rx.Observable
|
||||
import rx.Subscription
|
||||
@ -39,8 +45,10 @@ open class GlobalSearchPresenter(
|
||||
private val initialExtensionFilter: String? = null,
|
||||
private val sourcesToUse: List<CatalogueSource>? = null,
|
||||
val sourceManager: SourceManager = Injekt.get(),
|
||||
val db: DatabaseHelper = Injekt.get(),
|
||||
val preferences: PreferencesHelper = Injekt.get(),
|
||||
private val getManga: GetManga = Injekt.get(),
|
||||
private val insertManga: InsertManga = Injekt.get(),
|
||||
private val updateManga: UpdateManga = Injekt.get(),
|
||||
) : BasePresenter<GlobalSearchController>() {
|
||||
|
||||
/**
|
||||
@ -250,7 +258,7 @@ open class GlobalSearchPresenter(
|
||||
val networkManga = source.getMangaDetails(manga.toMangaInfo())
|
||||
manga.copyFrom(networkManga.toSManga())
|
||||
manga.initialized = true
|
||||
db.insertManga(manga).executeAsBlocking()
|
||||
runBlocking { updateManga.await(manga.toDomainManga()!!.toMangaUpdate()) }
|
||||
return manga
|
||||
}
|
||||
|
||||
@ -262,18 +270,21 @@ open class GlobalSearchPresenter(
|
||||
* @return a manga from the database.
|
||||
*/
|
||||
protected open fun networkToLocalManga(sManga: SManga, sourceId: Long): Manga {
|
||||
var localManga = db.getManga(sManga.url, sourceId).executeAsBlocking()
|
||||
var localManga = runBlocking { 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).executeAsBlocking()
|
||||
newManga.id = result.insertedId()
|
||||
localManga = newManga
|
||||
newManga.id = -1
|
||||
val result = runBlocking {
|
||||
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.title = sManga.title
|
||||
localManga = localManga.copy(ogTitle = sManga.title)
|
||||
}
|
||||
return localManga
|
||||
return localManga!!.toDbManga()
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
package eu.kanade.tachiyomi.ui.category.sources
|
||||
|
||||
import android.os.Bundle
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
@ -14,9 +13,7 @@ import uy.kohesive.injekt.api.get
|
||||
/**
|
||||
* Presenter of [SourceCategoryController]. Used to manage the categories of the library.
|
||||
*/
|
||||
class SourceCategoryPresenter(
|
||||
private val db: DatabaseHelper = Injekt.get(),
|
||||
) : BasePresenter<SourceCategoryController>() {
|
||||
class SourceCategoryPresenter : BasePresenter<SourceCategoryController>() {
|
||||
|
||||
/**
|
||||
* List containing categories.
|
||||
|
@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.ui.library
|
||||
import android.os.Bundle
|
||||
import com.jakewharton.rxrelay.BehaviorRelay
|
||||
import eu.kanade.core.util.asObservable
|
||||
import eu.kanade.data.AndroidDatabaseHandler
|
||||
import eu.kanade.data.DatabaseHandler
|
||||
import eu.kanade.domain.category.interactor.GetCategories
|
||||
import eu.kanade.domain.category.interactor.SetMangaCategories
|
||||
@ -13,6 +12,7 @@ import eu.kanade.domain.chapter.interactor.GetMergedChapterByMangaId
|
||||
import eu.kanade.domain.chapter.interactor.UpdateChapter
|
||||
import eu.kanade.domain.chapter.model.ChapterUpdate
|
||||
import eu.kanade.domain.chapter.model.toDbChapter
|
||||
import eu.kanade.domain.manga.interactor.GetLibraryManga
|
||||
import eu.kanade.domain.manga.interactor.GetMergedMangaById
|
||||
import eu.kanade.domain.manga.interactor.UpdateManga
|
||||
import eu.kanade.domain.manga.model.Manga
|
||||
@ -74,6 +74,7 @@ typealias LibraryMap = Map<Long, List<LibraryItem>>
|
||||
*/
|
||||
class LibraryPresenter(
|
||||
private val handler: DatabaseHandler = Injekt.get(),
|
||||
private val getLibraryManga: GetLibraryManga = Injekt.get(),
|
||||
private val getTracks: GetTracks = Injekt.get(),
|
||||
private val getCategories: GetCategories = Injekt.get(),
|
||||
private val getChapterByMangaId: GetChapterByMangaId = Injekt.get(),
|
||||
@ -561,39 +562,7 @@ class LibraryPresenter(
|
||||
val defaultLibraryDisplayMode = preferences.libraryDisplayMode()
|
||||
val shouldSetFromCategory = preferences.categorizedDisplaySettings()
|
||||
|
||||
// TODO: Move this to domain/data layer
|
||||
return handler
|
||||
.subscribeToList {
|
||||
// SY -->
|
||||
(handler as AndroidDatabaseHandler).getLibraryQuery()
|
||||
/*mangasQueries.getLibrary { _id: Long, source: Long, url: String, artist: String?, author: String?, description: String?, genre: List<String>?, title: String, status: Long, thumbnail_url: String?, favorite: Boolean, last_update: Long?, next_update: Long?, initialized: Boolean, viewer: Long, chapter_flags: Long, cover_last_modified: Long, date_added: Long, filteredScanlators: List<String>?, unread_count: Long, read_count: Long, category: Long ->
|
||||
LibraryManga().apply {
|
||||
this.id = _id
|
||||
this.source = source
|
||||
this.url = url
|
||||
this.artist = artist
|
||||
this.author = author
|
||||
this.description = description
|
||||
this.genre = genre?.joinToString()
|
||||
this.title = title
|
||||
this.status = status.toInt()
|
||||
this.thumbnail_url = thumbnail_url
|
||||
this.favorite = favorite
|
||||
this.last_update = last_update ?: 0
|
||||
this.initialized = initialized
|
||||
this.viewer_flags = viewer.toInt()
|
||||
this.chapter_flags = chapter_flags.toInt()
|
||||
this.cover_last_modified = cover_last_modified
|
||||
this.date_added = date_added
|
||||
this.filtered_scanlators = filteredScanlators?.let(listOfStringsAndAdapter::encode)
|
||||
this.unreadCount = unread_count.toInt()
|
||||
this.readCount = read_count.toInt()
|
||||
this.category = category.toInt()
|
||||
}
|
||||
}*/
|
||||
// SY <--
|
||||
}
|
||||
.asObservable()
|
||||
return getLibraryManga.subscribe().asObservable()
|
||||
.map { list ->
|
||||
list.map { libraryManga ->
|
||||
// Display mode based on user preference: take it from global library setting or category
|
||||
|
@ -237,7 +237,7 @@ class MangaController :
|
||||
private fun openMergedSettingsDialog() {
|
||||
EditMergedSettingsDialog(
|
||||
this,
|
||||
presenter.manga!!.toDbManga(),
|
||||
presenter.manga ?: return,
|
||||
).showDialog(router)
|
||||
}
|
||||
|
||||
|
@ -12,16 +12,22 @@ import eu.kanade.domain.chapter.interactor.SyncChaptersWithTrackServiceTwoWay
|
||||
import eu.kanade.domain.chapter.interactor.UpdateChapter
|
||||
import eu.kanade.domain.chapter.model.ChapterUpdate
|
||||
import eu.kanade.domain.chapter.model.toDbChapter
|
||||
import eu.kanade.domain.manga.interactor.DeleteByMergeId
|
||||
import eu.kanade.domain.manga.interactor.DeleteMangaById
|
||||
import eu.kanade.domain.manga.interactor.GetDuplicateLibraryManga
|
||||
import eu.kanade.domain.manga.interactor.GetFlatMetadataById
|
||||
import eu.kanade.domain.manga.interactor.GetManga
|
||||
import eu.kanade.domain.manga.interactor.GetMangaWithChapters
|
||||
import eu.kanade.domain.manga.interactor.GetMergedMangaById
|
||||
import eu.kanade.domain.manga.interactor.GetMergedReferencesById
|
||||
import eu.kanade.domain.manga.interactor.InsertManga
|
||||
import eu.kanade.domain.manga.interactor.InsertMergedReference
|
||||
import eu.kanade.domain.manga.interactor.SetMangaChapterFlags
|
||||
import eu.kanade.domain.manga.interactor.SetMangaFilteredScanlators
|
||||
import eu.kanade.domain.manga.interactor.UpdateManga
|
||||
import eu.kanade.domain.manga.interactor.UpdateMergedSettings
|
||||
import eu.kanade.domain.manga.model.MangaUpdate
|
||||
import eu.kanade.domain.manga.model.MergeMangaSettingsUpdate
|
||||
import eu.kanade.domain.manga.model.TriStateFilter
|
||||
import eu.kanade.domain.manga.model.isLocal
|
||||
import eu.kanade.domain.manga.model.toDbManga
|
||||
@ -32,7 +38,6 @@ import eu.kanade.domain.track.interactor.InsertTrack
|
||||
import eu.kanade.domain.track.model.toDbTrack
|
||||
import eu.kanade.domain.track.model.toDomainTrack
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.database.models.toDomainChapter
|
||||
@ -127,6 +132,11 @@ class MangaPresenter(
|
||||
private val getMergedChapterByMangaId: GetMergedChapterByMangaId = Injekt.get(),
|
||||
private val getMergedMangaById: GetMergedMangaById = Injekt.get(),
|
||||
private val getMergedReferencesById: GetMergedReferencesById = Injekt.get(),
|
||||
private val insertMergedReference: InsertMergedReference = Injekt.get(),
|
||||
private val updateMergedSettings: UpdateMergedSettings = Injekt.get(),
|
||||
private val insertManga: InsertManga = Injekt.get(),
|
||||
private val deleteMangaById: DeleteMangaById = Injekt.get(),
|
||||
private val deleteByMergeId: DeleteByMergeId = Injekt.get(),
|
||||
private val getFlatMetadata: GetFlatMetadataById = Injekt.get(),
|
||||
// SY <--
|
||||
private val getDuplicateLibraryManga: GetDuplicateLibraryManga = Injekt.get(),
|
||||
@ -223,7 +233,7 @@ class MangaPresenter(
|
||||
|
||||
presenterScope.launchIO {
|
||||
if (!getMangaAndChapters.awaitManga(mangaId).favorite) {
|
||||
ChapterSettingsHelper.applySettingDefaults(mangaId, setMangaChapterFlags)
|
||||
ChapterSettingsHelper.applySettingDefaults(mangaId)
|
||||
}
|
||||
|
||||
getMangaAndChapters.subscribe(mangaId)
|
||||
@ -431,8 +441,6 @@ class MangaPresenter(
|
||||
}
|
||||
|
||||
suspend fun smartSearchMerge(context: Context, manga: DomainManga, originalMangaId: Long): DomainManga {
|
||||
val db = Injekt.get<DatabaseHelper>()
|
||||
|
||||
val originalManga = getManga.await(originalMangaId)
|
||||
?: throw IllegalArgumentException(context.getString(R.string.merge_unknown_manga, originalMangaId))
|
||||
if (originalManga.source == MERGED_SOURCE_ID) {
|
||||
@ -474,7 +482,7 @@ class MangaPresenter(
|
||||
}
|
||||
|
||||
// todo
|
||||
db.insertMergedMangas(mangaReferences).executeAsBlocking()
|
||||
insertMergedReference.awaitAll(mangaReferences)
|
||||
|
||||
return originalManga
|
||||
} else {
|
||||
@ -494,8 +502,10 @@ class MangaPresenter(
|
||||
throw IllegalArgumentException(context.getString(R.string.merge_duplicate))
|
||||
} else if (!existingManga.favorite) {
|
||||
withContext(NonCancellable) {
|
||||
db.deleteManga(existingManga!!.toDbManga()).executeAsBlocking()
|
||||
db.deleteMangaForMergedManga(existingManga!!.id).executeAsBlocking()
|
||||
existingManga?.id?.let {
|
||||
deleteByMergeId.await(it)
|
||||
deleteMangaById.await(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
existingManga = getManga.await(mergedManga.url, mergedManga.source)
|
||||
@ -503,13 +513,13 @@ class MangaPresenter(
|
||||
|
||||
// Reload chapters immediately
|
||||
mergedManga.initialized = false
|
||||
|
||||
val newId = db.insertManga(mergedManga).executeAsBlocking().insertedId()
|
||||
if (newId != null) mergedManga.id = newId
|
||||
mergedManga.id = -1
|
||||
val newId = insertManga.await(mergedManga.toDomainManga()!!)
|
||||
mergedManga.id = newId ?: throw NullPointerException("Invalid new manga id")
|
||||
|
||||
getCategories.await(originalMangaId)
|
||||
.let {
|
||||
setMangaCategories.await(mergedManga.id!!, it.map { it.id })
|
||||
setMangaCategories.await(newId, it.map { it.id })
|
||||
}
|
||||
|
||||
val originalMangaReference = MergedMangaReference(
|
||||
@ -554,7 +564,7 @@ class MangaPresenter(
|
||||
mangaSourceId = MERGED_SOURCE_ID,
|
||||
)
|
||||
|
||||
db.insertMergedMangas(listOf(originalMangaReference, newMangaReference, mergedMangaReference)).executeAsBlocking()
|
||||
insertMergedReference.awaitAll(listOf(originalMangaReference, newMangaReference, mergedMangaReference))
|
||||
|
||||
return mergedManga.toDomainManga()!!
|
||||
}
|
||||
@ -562,14 +572,21 @@ class MangaPresenter(
|
||||
// Note that if the manga are merged in a different order, this won't trigger, but I don't care lol
|
||||
}
|
||||
|
||||
fun updateMergeSettings(mergeReference: MergedMangaReference?, mergedMangaReferences: List<MergedMangaReference>) {
|
||||
fun updateMergeSettings(mergedMangaReferences: List<MergedMangaReference>) {
|
||||
launchIO {
|
||||
// todo
|
||||
val db = Injekt.get<DatabaseHelper>()
|
||||
mergeReference?.let {
|
||||
db.updateMergeMangaSettings(it).executeAsBlocking()
|
||||
if (mergedMangaReferences.isNotEmpty()) {
|
||||
updateMergedSettings.awaitAll(
|
||||
mergedMangaReferences.map {
|
||||
MergeMangaSettingsUpdate(
|
||||
it.id!!,
|
||||
it.isInfoManga,
|
||||
it.getChapterUpdates,
|
||||
it.chapterPriority,
|
||||
it.downloadChapters,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
if (mergedMangaReferences.isNotEmpty()) db.updateMergedMangaSettings(mergedMangaReferences).executeAsBlocking()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,8 +5,8 @@ import androidx.recyclerview.widget.RecyclerView
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||
import eu.davidea.flexibleadapter.items.IFlexible
|
||||
import eu.kanade.domain.manga.model.Manga
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.databinding.EditMergedSettingsItemBinding
|
||||
import exh.merged.sql.models.MergedMangaReference
|
||||
|
||||
|
@ -7,15 +7,22 @@ import androidx.core.os.bundleOf
|
||||
import androidx.recyclerview.widget.ConcatAdapter
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import eu.kanade.domain.manga.interactor.DeleteMergeById
|
||||
import eu.kanade.domain.manga.interactor.GetManga
|
||||
import eu.kanade.domain.manga.interactor.GetMergedMangaById
|
||||
import eu.kanade.domain.manga.interactor.GetMergedReferencesById
|
||||
import eu.kanade.domain.manga.model.Manga
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.databinding.EditMergedSettingsDialogBinding
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import exh.merged.sql.models.MergedMangaReference
|
||||
import exh.source.MERGED_SOURCE_ID
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
class EditMergedSettingsDialog : DialogController, EditMergedMangaAdapter.EditMergedMangaItemListener {
|
||||
@ -27,13 +34,15 @@ class EditMergedSettingsDialog : DialogController, EditMergedMangaAdapter.EditMe
|
||||
|
||||
lateinit var binding: EditMergedSettingsDialogBinding
|
||||
|
||||
private val db: DatabaseHelper by injectLazy()
|
||||
private val getMergedMangaById: GetMergedMangaById by injectLazy()
|
||||
private val getMergedReferencesById: GetMergedReferencesById by injectLazy()
|
||||
private val deleteMergeById: DeleteMergeById by injectLazy()
|
||||
|
||||
private val mangaController
|
||||
get() = targetController as MangaController
|
||||
|
||||
constructor(target: MangaController, manga: Manga) : super(
|
||||
bundleOf(KEY_MANGA to manga.id!!),
|
||||
bundleOf(KEY_MANGA to manga.id),
|
||||
) {
|
||||
targetController = target
|
||||
this.manga = manga
|
||||
@ -41,8 +50,7 @@ class EditMergedSettingsDialog : DialogController, EditMergedMangaAdapter.EditMe
|
||||
|
||||
@Suppress("unused")
|
||||
constructor(bundle: Bundle) : super(bundle) {
|
||||
manga = db.getManga(bundle.getLong(KEY_MANGA))
|
||||
.executeAsBlocking()!!
|
||||
manga = runBlocking { Injekt.get<GetManga>().await(bundle.getLong(KEY_MANGA))!! }
|
||||
}
|
||||
|
||||
private var mergedHeaderAdapter: EditMergedSettingsHeaderAdapter? = null
|
||||
@ -62,8 +70,8 @@ class EditMergedSettingsDialog : DialogController, EditMergedMangaAdapter.EditMe
|
||||
}
|
||||
|
||||
fun onViewCreated() {
|
||||
val mergedManga = db.getMergedMangas(manga.id!!).executeAsBlocking()
|
||||
val mergedReferences = db.getMergedMangaReferences(manga.id!!).executeAsBlocking()
|
||||
val mergedManga = runBlocking { getMergedMangaById.await(manga.id) }
|
||||
val mergedReferences = runBlocking { getMergedReferencesById.await(manga.id) }
|
||||
if (mergedReferences.isEmpty() || mergedReferences.size == 1) {
|
||||
activity?.toast(R.string.merged_references_invalid)
|
||||
router.popCurrentController()
|
||||
@ -85,7 +93,7 @@ class EditMergedSettingsDialog : DialogController, EditMergedMangaAdapter.EditMe
|
||||
}
|
||||
|
||||
private fun onPositiveButtonClick() {
|
||||
mangaController.presenter.updateMergeSettings(mergeReference, mergedMangas.map { it.second })
|
||||
mangaController.presenter.updateMergeSettings(listOfNotNull(mergeReference) + mergedMangas.map { it.second })
|
||||
}
|
||||
|
||||
override fun onItemReleased(position: Int) {
|
||||
@ -105,7 +113,9 @@ class EditMergedSettingsDialog : DialogController, EditMergedMangaAdapter.EditMe
|
||||
.setTitle(R.string.delete_merged_manga)
|
||||
.setMessage(R.string.delete_merged_manga_desc)
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
db.deleteMergedManga(mergeMangaReference).executeAsBlocking()
|
||||
launchIO {
|
||||
deleteMergeById.await(mergeMangaReference.id!!)
|
||||
}
|
||||
dialog?.dismiss()
|
||||
mangaController.router.popController(mangaController)
|
||||
}
|
||||
|
@ -14,12 +14,14 @@ import eu.kanade.domain.history.interactor.UpsertHistory
|
||||
import eu.kanade.domain.history.model.HistoryUpdate
|
||||
import eu.kanade.domain.manga.interactor.GetFlatMetadataById
|
||||
import eu.kanade.domain.manga.interactor.GetManga
|
||||
import eu.kanade.domain.manga.interactor.GetMergedManga
|
||||
import eu.kanade.domain.manga.interactor.GetMergedReferencesById
|
||||
import eu.kanade.domain.manga.interactor.SetMangaViewerFlags
|
||||
import eu.kanade.domain.manga.model.isLocal
|
||||
import eu.kanade.domain.manga.model.toDbManga
|
||||
import eu.kanade.domain.track.interactor.GetTracks
|
||||
import eu.kanade.domain.track.interactor.InsertTrack
|
||||
import eu.kanade.domain.track.model.toDbTrack
|
||||
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.models.toDomainManga
|
||||
@ -86,7 +88,6 @@ import java.util.concurrent.TimeUnit
|
||||
* Presenter used by the activity to perform background operations.
|
||||
*/
|
||||
class ReaderPresenter(
|
||||
private val db: DatabaseHelper = Injekt.get(),
|
||||
private val sourceManager: SourceManager = Injekt.get(),
|
||||
private val downloadManager: DownloadManager = Injekt.get(),
|
||||
private val preferences: PreferencesHelper = Injekt.get(),
|
||||
@ -97,8 +98,11 @@ class ReaderPresenter(
|
||||
private val insertTrack: InsertTrack = Injekt.get(),
|
||||
private val upsertHistory: UpsertHistory = Injekt.get(),
|
||||
private val updateChapter: UpdateChapter = Injekt.get(),
|
||||
private val setMangaViewerFlags: SetMangaViewerFlags = Injekt.get(),
|
||||
// SY -->
|
||||
private val getFlatMetadataById: GetFlatMetadataById,
|
||||
private val getFlatMetadataById: GetFlatMetadataById = Injekt.get(),
|
||||
private val getMergedManga: GetMergedManga = Injekt.get(),
|
||||
private val getMergedReferencesById: GetMergedReferencesById = Injekt.get(),
|
||||
// SY <--
|
||||
) : BasePresenter<ReaderActivity>() {
|
||||
|
||||
@ -314,8 +318,8 @@ class ReaderPresenter(
|
||||
|
||||
val context = Injekt.get<Application>()
|
||||
val source = sourceManager.getOrStub(manga.source)
|
||||
val mergedReferences = if (source is MergedSource) db.getMergedMangaReferences(manga.id!!).executeAsBlocking() else emptyList()
|
||||
mergedManga = if (source is MergedSource) db.getMergedMangas(manga.id!!).executeAsBlocking().associateBy { it.id!! } else emptyMap()
|
||||
val mergedReferences = if (source is MergedSource) runBlocking { getMergedReferencesById.await(manga.id!!) } else emptyList()
|
||||
mergedManga = if (source is MergedSource) runBlocking { getMergedManga.await() }.map { it.toDbManga() }.associateBy { it.id!! } else emptyMap()
|
||||
loader = ChapterLoader(context, downloadManager, manga, source, sourceManager, mergedReferences, mergedManga ?: emptyMap())
|
||||
|
||||
Observable.just(manga).subscribeLatestCache(ReaderActivity::setManga)
|
||||
@ -648,7 +652,14 @@ class ReaderPresenter(
|
||||
fun toggleBookmark(chapterId: Long, bookmarked: Boolean) {
|
||||
val chapter = chapterList.find { it.chapter.id == chapterId }?.chapter ?: return
|
||||
chapter.bookmark = bookmarked
|
||||
db.updateChapterProgress(chapter).executeAsBlocking()
|
||||
launchIO {
|
||||
updateChapter.await(
|
||||
ChapterUpdate(
|
||||
id = chapter.id!!.toLong(),
|
||||
bookmark = bookmarked,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
// SY <--
|
||||
|
||||
@ -677,7 +688,9 @@ class ReaderPresenter(
|
||||
fun setMangaReadingMode(readingModeType: Int) {
|
||||
val manga = manga ?: return
|
||||
manga.readingModeType = readingModeType
|
||||
db.updateViewerFlags(manga).executeAsBlocking()
|
||||
runBlocking {
|
||||
setMangaViewerFlags.awaitSetMangaReadingMode(manga.id!!.toLong(), readingModeType.toLong())
|
||||
}
|
||||
|
||||
Observable.timer(250, TimeUnit.MILLISECONDS, AndroidSchedulers.mainThread())
|
||||
.subscribeFirst({ view, _ ->
|
||||
@ -712,7 +725,9 @@ class ReaderPresenter(
|
||||
fun setMangaOrientationType(rotationType: Int) {
|
||||
val manga = manga ?: return
|
||||
manga.orientationType = rotationType
|
||||
db.updateViewerFlags(manga).executeAsBlocking()
|
||||
runBlocking {
|
||||
setMangaViewerFlags.awaitSetOrientationType(manga.id!!.toLong(), rotationType.toLong())
|
||||
}
|
||||
|
||||
logcat(LogPriority.INFO) { "Manga orientation is ${manga.orientationType}" }
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
package eu.kanade.tachiyomi.util.chapter
|
||||
|
||||
import eu.kanade.domain.manga.interactor.GetFavorites
|
||||
import eu.kanade.domain.manga.interactor.SetMangaChapterFlags
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||
@ -10,7 +10,8 @@ import uy.kohesive.injekt.injectLazy
|
||||
object ChapterSettingsHelper {
|
||||
|
||||
private val prefs: PreferencesHelper by injectLazy()
|
||||
private val db: DatabaseHelper by injectLazy()
|
||||
private val getFavorites: GetFavorites by injectLazy()
|
||||
private val setMangaChapterFlags: SetMangaChapterFlags by injectLazy()
|
||||
|
||||
/**
|
||||
* Updates the global Chapter Settings in Preferences.
|
||||
@ -23,19 +24,20 @@ object ChapterSettingsHelper {
|
||||
* Updates a single manga's Chapter Settings to match what's set in Preferences.
|
||||
*/
|
||||
fun applySettingDefaults(manga: Manga) {
|
||||
with(manga) {
|
||||
readFilter = prefs.filterChapterByRead()
|
||||
downloadedFilter = prefs.filterChapterByDownloaded()
|
||||
bookmarkedFilter = prefs.filterChapterByBookmarked()
|
||||
sorting = prefs.sortChapterBySourceOrNumber()
|
||||
displayMode = prefs.displayChapterByNameOrNumber()
|
||||
setChapterOrder(prefs.sortChapterByAscendingOrDescending())
|
||||
launchIO {
|
||||
setMangaChapterFlags.awaitSetAllFlags(
|
||||
mangaId = manga.id!!,
|
||||
unreadFilter = prefs.filterChapterByRead().toLong(),
|
||||
downloadedFilter = prefs.filterChapterByDownloaded().toLong(),
|
||||
bookmarkedFilter = prefs.filterChapterByBookmarked().toLong(),
|
||||
sortingMode = prefs.sortChapterBySourceOrNumber().toLong(),
|
||||
sortingDirection = prefs.sortChapterByAscendingOrDescending().toLong(),
|
||||
displayMode = prefs.displayChapterByNameOrNumber().toLong(),
|
||||
)
|
||||
}
|
||||
|
||||
db.updateChapterFlags(manga).executeAsBlocking()
|
||||
}
|
||||
|
||||
suspend fun applySettingDefaults(mangaId: Long, setMangaChapterFlags: SetMangaChapterFlags) {
|
||||
suspend fun applySettingDefaults(mangaId: Long) {
|
||||
setMangaChapterFlags.awaitSetAllFlags(
|
||||
mangaId = mangaId,
|
||||
unreadFilter = prefs.filterChapterByRead().toLong(),
|
||||
@ -52,21 +54,18 @@ object ChapterSettingsHelper {
|
||||
*/
|
||||
fun updateAllMangasWithGlobalDefaults() {
|
||||
launchIO {
|
||||
val updatedMangas = db.getFavoriteMangas()
|
||||
.executeAsBlocking()
|
||||
getFavorites.await()
|
||||
.map { manga ->
|
||||
with(manga) {
|
||||
readFilter = prefs.filterChapterByRead()
|
||||
downloadedFilter = prefs.filterChapterByDownloaded()
|
||||
bookmarkedFilter = prefs.filterChapterByBookmarked()
|
||||
sorting = prefs.sortChapterBySourceOrNumber()
|
||||
displayMode = prefs.displayChapterByNameOrNumber()
|
||||
setChapterOrder(prefs.sortChapterByAscendingOrDescending())
|
||||
}
|
||||
manga
|
||||
setMangaChapterFlags.awaitSetAllFlags(
|
||||
mangaId = manga.id,
|
||||
unreadFilter = prefs.filterChapterByRead().toLong(),
|
||||
downloadedFilter = prefs.filterChapterByDownloaded().toLong(),
|
||||
bookmarkedFilter = prefs.filterChapterByBookmarked().toLong(),
|
||||
sortingMode = prefs.sortChapterBySourceOrNumber().toLong(),
|
||||
sortingDirection = prefs.sortChapterByAscendingOrDescending().toLong(),
|
||||
displayMode = prefs.displayChapterByNameOrNumber().toLong(),
|
||||
)
|
||||
}
|
||||
|
||||
db.updateChapterFlags(updatedMangas).executeAsBlocking()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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() }
|
@ -4,4 +4,29 @@ DELETE FROM manga_sync WHERE sync_id = :syncId;
|
||||
migrateSource:
|
||||
UPDATE mangas
|
||||
SET source = :newId
|
||||
WHERE source = :oldId;
|
||||
WHERE source = :oldId;
|
||||
|
||||
getChaptersByMangaIds:
|
||||
SELECT * FROM chapters WHERE manga_id IN :mangaIds;
|
||||
|
||||
resetFilteredScanlatorsForAllManga:
|
||||
UPDATE mangas
|
||||
SET filtered_scanlators = NULL;
|
||||
|
||||
migrateAllNhentaiToOtherLang:
|
||||
UPDATE mangas
|
||||
SET source = :nh
|
||||
WHERE favorite = 1 AND source IN :sources;
|
||||
|
||||
resetReaderViewerForAllManga:
|
||||
UPDATE mangas
|
||||
SET viewer = 0;
|
||||
|
||||
fixReaderViewerBackupBug:
|
||||
UPDATE mangas
|
||||
SET viewer = 0
|
||||
WHERE viewer = -1;
|
||||
|
||||
addAllMangaInDatabaseToLibrary:
|
||||
UPDATE mangas
|
||||
SET favorite = 1;
|
@ -166,6 +166,44 @@ WHERE favorite = 0 AND source IN :sourceIdsAND AND _id NOT IN (
|
||||
SELECT manga_id FROM chapters WHERE read = 1 OR last_page_read != 0
|
||||
);
|
||||
|
||||
INSERT INTO mangas(
|
||||
source,
|
||||
url,
|
||||
artist,
|
||||
author,
|
||||
description,
|
||||
genre,
|
||||
title,
|
||||
status,
|
||||
thumbnail_url,
|
||||
favorite,
|
||||
last_update,
|
||||
next_update,
|
||||
initialized,
|
||||
viewer,
|
||||
chapter_flags,
|
||||
cover_last_modified,
|
||||
date_added
|
||||
) VALUES (
|
||||
:source,
|
||||
:url,
|
||||
:artist,
|
||||
:author,
|
||||
:description,
|
||||
:genre,
|
||||
:title,
|
||||
:status,
|
||||
:thumbnailUrl,
|
||||
:favorite,
|
||||
:lastUpdate,
|
||||
0,
|
||||
:initialized,
|
||||
:viewerFlags,
|
||||
:chapterFlags,
|
||||
:coverLastModified,
|
||||
:dateAdded
|
||||
);
|
||||
|
||||
update:
|
||||
UPDATE mangas SET
|
||||
source = coalesce(:source, source),
|
||||
@ -208,6 +246,9 @@ SELECT * FROM mangas WHERE source = :sourceId;
|
||||
getAll:
|
||||
SELECT * FROM mangas;
|
||||
|
||||
deleteById:
|
||||
DELETE FROM mangas WHERE _id = :id;
|
||||
|
||||
selectLastInsertRow:
|
||||
SELECT *
|
||||
FROM mangas
|
||||
|
@ -73,9 +73,31 @@ FROM (
|
||||
JOIN chapters
|
||||
ON chapters.manga_id = M.manga_id;
|
||||
|
||||
insertMerged:
|
||||
INSERT INTO merged (_id, info_manga, get_chapter_updates, chapter_sort_mode, chapter_priority, download_chapters, merge_id, merge_url, manga_id, manga_url, manga_source)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
|
||||
insert:
|
||||
INSERT INTO merged(
|
||||
info_manga,
|
||||
get_chapter_updates,
|
||||
chapter_sort_mode,
|
||||
chapter_priority,
|
||||
download_chapters,
|
||||
merge_id,
|
||||
merge_url,
|
||||
manga_id,
|
||||
manga_url,
|
||||
manga_source
|
||||
)
|
||||
VALUES (
|
||||
:infoManga,
|
||||
:getChapterUpdates,
|
||||
:chapterSortMode,
|
||||
:chapterPriority,
|
||||
:downloadChapters,
|
||||
:mergeId,
|
||||
:mergeUrl,
|
||||
:mangaId,
|
||||
:mangaUrl,
|
||||
:mangaSource
|
||||
);
|
||||
|
||||
updateSettingsById:
|
||||
UPDATE merged
|
||||
@ -89,5 +111,8 @@ WHERE _id = :id;
|
||||
deleteById:
|
||||
DELETE FROM merged WHERE _id = ?;
|
||||
|
||||
deleteBy:
|
||||
deleteAll:
|
||||
DELETE FROM merged;
|
||||
|
||||
selectLastInsertedRowId:
|
||||
SELECT last_insert_rowid();
|
Loading…
x
Reference in New Issue
Block a user