Use SQLDelight for more SY specific things

This commit is contained in:
Jobobby04 2022-07-03 13:37:27 -04:00
parent e71c9e2775
commit d88c769d3b
83 changed files with 678 additions and 1504 deletions

View File

@ -91,5 +91,9 @@ class AndroidDatabaseHandler(
// SY -->
fun getLibraryQuery() = LibraryQuery(driver)
fun rawQuery(query: (SqlDriver) -> Unit) {
return query(driver)
}
// SY <--
}

View File

@ -0,0 +1,26 @@
package eu.kanade.data.manga
import eu.kanade.data.DatabaseHandler
import eu.kanade.data.exh.favoriteEntryMapper
import eu.kanade.domain.manga.repository.FavoritesEntryRepository
import exh.favorites.sql.models.FavoriteEntry
class FavoritesEntryRepositoryImpl(
private val handler: DatabaseHandler,
) : FavoritesEntryRepository {
override suspend fun deleteAll() {
handler.await { eh_favoritesQueries.deleteAll() }
}
override suspend fun insertAll(favoriteEntries: List<FavoriteEntry>) {
handler.await(true) {
favoriteEntries.forEach {
eh_favoritesQueries.insertEhFavorites(it.id, it.title, it.gid, it.token, it.category.toLong())
}
}
}
override suspend fun selectAll(): List<FavoriteEntry> {
return handler.awaitList { eh_favoritesQueries.selectAll(favoriteEntryMapper) }
}
}

View File

@ -2,10 +2,14 @@ package eu.kanade.data.manga
import eu.kanade.data.DatabaseHandler
import eu.kanade.data.exh.mergedMangaReferenceMapper
import eu.kanade.data.toLong
import eu.kanade.domain.manga.model.Manga
import eu.kanade.domain.manga.model.MergeMangaSettingsUpdate
import eu.kanade.domain.manga.repository.MangaMergeRepository
import eu.kanade.tachiyomi.util.system.logcat
import exh.merged.sql.models.MergedMangaReference
import kotlinx.coroutines.flow.Flow
import logcat.LogPriority
class MangaMergeRepositoryImpl(
private val handler: DatabaseHandler,
@ -34,4 +38,38 @@ class MangaMergeRepositoryImpl(
override suspend fun subscribeReferencesById(id: Long): Flow<List<MergedMangaReference>> {
return handler.subscribeToList { mergedQueries.selectByMergeId(id, mergedMangaReferenceMapper) }
}
override suspend fun updateSettings(update: MergeMangaSettingsUpdate): Boolean {
return try {
partialUpdate(update)
true
} catch (e: Exception) {
logcat(LogPriority.ERROR, e)
false
}
}
override suspend fun updateAllSettings(values: List<MergeMangaSettingsUpdate>): Boolean {
return try {
partialUpdate(*values.toTypedArray())
true
} catch (e: Exception) {
logcat(LogPriority.ERROR, e)
false
}
}
private suspend fun partialUpdate(vararg values: MergeMangaSettingsUpdate) {
handler.await(inTransaction = true) {
values.forEach { value ->
mergedQueries.updateSettingsById(
id = value.id,
getChapterUpdates = value.getChapterUpdates?.toLong(),
downloadChapters = value.downloadChapters?.toLong(),
infoManga = value.isInfoManga?.toLong(),
chapterPriority = value.chapterPriority?.toLong(),
)
}
}
}
}

View File

@ -4,10 +4,14 @@ import eu.kanade.data.DatabaseHandler
import eu.kanade.data.exh.searchMetadataMapper
import eu.kanade.data.exh.searchTagMapper
import eu.kanade.data.exh.searchTitleMapper
import eu.kanade.domain.manga.model.Manga
import eu.kanade.domain.manga.repository.MangaMetadataRepository
import exh.metadata.metadata.base.FlatMetadata
import exh.metadata.sql.models.SearchMetadata
import exh.metadata.sql.models.SearchTag
import exh.metadata.sql.models.SearchTitle
import exh.source.EH_SOURCE_ID
import exh.source.EXH_SOURCE_ID
import kotlinx.coroutines.flow.Flow
class MangaMetadataRepositoryImpl(
@ -37,4 +41,34 @@ class MangaMetadataRepositoryImpl(
override suspend fun subscribeTitlesById(id: Long): Flow<List<SearchTitle>> {
return handler.subscribeToList { search_titlesQueries.selectByMangaId(id, searchTitleMapper) }
}
override suspend fun insertFlatMetadata(flatMetadata: FlatMetadata) {
require(flatMetadata.metadata.mangaId != -1L)
handler.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)
}
}
}
override suspend fun getExhFavoriteMangaWithMetadata(): List<Manga> {
return handler.awaitList { mangasQueries.getEhMangaWithMetadata(EH_SOURCE_ID, EXH_SOURCE_ID, mangaMapper) }
}
override suspend fun getIdsOfFavoriteMangaWithMetadata(): List<Long> {
return handler.awaitList { mangasQueries.getIdsOfFavoriteMangaWithMetadata() }
}
override suspend fun getSearchMetadata(): List<SearchMetadata> {
return handler.awaitList { search_metadataQueries.selectAll(searchMetadataMapper) }
}
}

View File

@ -114,4 +114,12 @@ class MangaRepositoryImpl(
}
}
}
override suspend fun getMangaBySource(sourceId: Long): List<Manga> {
return handler.awaitList { mangasQueries.getBySource(sourceId, mangaMapper) }
}
override suspend fun getAll(): List<Manga> {
return handler.awaitList { mangasQueries.getAll(mangaMapper) }
}
}

View File

@ -32,7 +32,7 @@ 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.GetMangaById
import eu.kanade.domain.manga.interactor.GetManga
import eu.kanade.domain.manga.interactor.GetMangaWithChapters
import eu.kanade.domain.manga.interactor.ResetViewerFlags
import eu.kanade.domain.manga.interactor.SetMangaChapterFlags
@ -72,7 +72,7 @@ class DomainModule : InjektModule {
addFactory { GetDuplicateLibraryManga(get()) }
addFactory { GetFavorites(get()) }
addFactory { GetMangaWithChapters(get(), get()) }
addFactory { GetMangaById(get()) }
addFactory { GetManga(get()) }
addFactory { GetNextChapter(get()) }
addFactory { ResetViewerFlags(get()) }
addFactory { SetMangaChapterFlags(get()) }

View File

@ -1,14 +1,25 @@
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.GetMergedChapterByMangaId
import eu.kanade.domain.manga.interactor.DeleteFavoriteEntries
import eu.kanade.domain.manga.interactor.GetAllManga
import eu.kanade.domain.manga.interactor.GetExhFavoriteMangaWithMetadata
import eu.kanade.domain.manga.interactor.GetFavoriteEntries
import eu.kanade.domain.manga.interactor.GetFlatMetadataById
import eu.kanade.domain.manga.interactor.GetMangaByUrlAndSource
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.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.SetMangaFilteredScanlators
import eu.kanade.domain.manga.repository.FavoritesEntryRepository
import eu.kanade.domain.manga.repository.MangaMergeRepository
import eu.kanade.domain.manga.repository.MangaMetadataRepository
import eu.kanade.domain.source.interactor.GetShowLatest
@ -31,15 +42,26 @@ class SYDomainModule : InjektModule {
addFactory { SetSourceCategories(get()) }
addFactory { ToggleSources(get()) }
addFactory { SetMangaFilteredScanlators(get()) }
addFactory { GetMangaByUrlAndSource(get()) }
addFactory { GetAllManga(get()) }
addFactory { GetMangaBySource(get()) }
addSingletonFactory<MangaMetadataRepository> { MangaMetadataRepositoryImpl(get()) }
addFactory { GetFlatMetadataById(get()) }
addFactory { InsertFlatMetadata(get()) }
addFactory { GetExhFavoriteMangaWithMetadata(get()) }
addFactory { GetSearchTags(get()) }
addFactory { GetSearchTitles(get()) }
addFactory { GetIdsOfFavoriteMangaWithMetadata(get()) }
addSingletonFactory<MangaMergeRepository> { MangaMergeRepositoryImpl(get()) }
addFactory { GetMergedManga(get()) }
addFactory { GetMergedMangaById(get()) }
addFactory { GetMergedReferencesById(get()) }
addFactory { GetMergedChapterByMangaId(get()) }
addSingletonFactory<FavoritesEntryRepository> { FavoritesEntryRepositoryImpl(get()) }
addFactory { GetFavoriteEntries(get()) }
addFactory { InsertFavoriteEntries(get()) }
addFactory { DeleteFavoriteEntries(get()) }
}
}

View File

@ -0,0 +1,12 @@
package eu.kanade.domain.manga.interactor
import eu.kanade.domain.manga.repository.FavoritesEntryRepository
class DeleteFavoriteEntries(
private val favoriteEntryRepository: FavoritesEntryRepository,
) {
suspend fun await() {
return favoriteEntryRepository.deleteAll()
}
}

View File

@ -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 GetAllManga(
private val mangaRepository: MangaRepository,
) {
suspend fun await(): List<Manga> {
return mangaRepository.getAll()
}
}

View File

@ -0,0 +1,13 @@
package eu.kanade.domain.manga.interactor
import eu.kanade.domain.manga.model.Manga
import eu.kanade.domain.manga.repository.MangaMetadataRepository
class GetExhFavoriteMangaWithMetadata(
private val mangaMetadataRepository: MangaMetadataRepository,
) {
suspend fun await(): List<Manga> {
return mangaMetadataRepository.getExhFavoriteMangaWithMetadata()
}
}

View File

@ -0,0 +1,13 @@
package eu.kanade.domain.manga.interactor
import eu.kanade.domain.manga.repository.FavoritesEntryRepository
import exh.favorites.sql.models.FavoriteEntry
class GetFavoriteEntries(
private val favoriteEntryRepository: FavoritesEntryRepository,
) {
suspend fun await(): List<FavoriteEntry> {
return favoriteEntryRepository.selectAll()
}
}

View File

@ -0,0 +1,12 @@
package eu.kanade.domain.manga.interactor
import eu.kanade.domain.manga.repository.MangaMetadataRepository
class GetIdsOfFavoriteMangaWithMetadata(
private val mangaMetadataRepository: MangaMetadataRepository,
) {
suspend fun await(): List<Long> {
return mangaMetadataRepository.getIdsOfFavoriteMangaWithMetadata()
}
}

View File

@ -6,10 +6,23 @@ import eu.kanade.tachiyomi.util.system.logcat
import kotlinx.coroutines.flow.Flow
import logcat.LogPriority
class GetMangaByUrlAndSource(
class GetManga(
private val mangaRepository: MangaRepository,
) {
suspend fun await(id: Long): Manga? {
return try {
mangaRepository.getMangaById(id)
} catch (e: Exception) {
logcat(LogPriority.ERROR, e)
null
}
}
suspend fun subscribe(id: Long): Flow<Manga> {
return mangaRepository.subscribeMangaById(id)
}
suspend fun await(url: String, sourceId: Long): Manga? {
return try {
mangaRepository.getMangaByUrlAndSource(url, sourceId)

View File

@ -1,25 +0,0 @@
package eu.kanade.domain.manga.interactor
import eu.kanade.domain.manga.model.Manga
import eu.kanade.domain.manga.repository.MangaRepository
import eu.kanade.tachiyomi.util.system.logcat
import kotlinx.coroutines.flow.Flow
import logcat.LogPriority
class GetMangaById(
private val mangaRepository: MangaRepository,
) {
suspend fun await(id: Long): Manga? {
return try {
mangaRepository.getMangaById(id)
} catch (e: Exception) {
logcat(LogPriority.ERROR, e)
null
}
}
suspend fun subscribe(id: Long): Flow<Manga> {
return mangaRepository.subscribeMangaById(id)
}
}

View File

@ -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 GetMangaBySource(
private val mangaRepository: MangaRepository,
) {
suspend fun await(sourceId: Long): List<Manga> {
return mangaRepository.getMangaBySource(sourceId)
}
}

View File

@ -0,0 +1,17 @@
package eu.kanade.domain.manga.interactor
import eu.kanade.domain.manga.repository.MangaMetadataRepository
import exh.metadata.sql.models.SearchMetadata
class GetSearchMetadata(
private val mangaMetadataRepository: MangaMetadataRepository,
) {
suspend fun await(mangaId: Long): SearchMetadata? {
return mangaMetadataRepository.getMetadataById(mangaId)
}
suspend fun await(): List<SearchMetadata> {
return mangaMetadataRepository.getSearchMetadata()
}
}

View File

@ -0,0 +1,13 @@
package eu.kanade.domain.manga.interactor
import eu.kanade.domain.manga.repository.MangaMetadataRepository
import exh.metadata.sql.models.SearchTag
class GetSearchTags(
private val mangaMetadataRepository: MangaMetadataRepository,
) {
suspend fun await(mangaId: Long): List<SearchTag> {
return mangaMetadataRepository.getTagsById(mangaId)
}
}

View File

@ -0,0 +1,13 @@
package eu.kanade.domain.manga.interactor
import eu.kanade.domain.manga.repository.MangaMetadataRepository
import exh.metadata.sql.models.SearchTitle
class GetSearchTitles(
private val mangaMetadataRepository: MangaMetadataRepository,
) {
suspend fun await(mangaId: Long): List<SearchTitle> {
return mangaMetadataRepository.getTitlesById(mangaId)
}
}

View File

@ -0,0 +1,13 @@
package eu.kanade.domain.manga.interactor
import eu.kanade.domain.manga.repository.FavoritesEntryRepository
import exh.favorites.sql.models.FavoriteEntry
class InsertFavoriteEntries(
private val favoriteEntryRepository: FavoritesEntryRepository,
) {
suspend fun await(entries: List<FavoriteEntry>) {
return favoriteEntryRepository.insertAll(entries)
}
}

View File

@ -0,0 +1,28 @@
package eu.kanade.domain.manga.interactor
import eu.kanade.domain.manga.repository.MangaMetadataRepository
import eu.kanade.tachiyomi.util.system.logcat
import exh.metadata.metadata.base.FlatMetadata
import exh.metadata.metadata.base.RaisedSearchMetadata
import logcat.LogPriority
class InsertFlatMetadata(
private val mangaMetadataRepository: MangaMetadataRepository,
) {
suspend fun await(flatMetadata: FlatMetadata) {
try {
mangaMetadataRepository.insertFlatMetadata(flatMetadata)
} catch (e: Exception) {
logcat(LogPriority.ERROR, e)
}
}
suspend fun await(metadata: RaisedSearchMetadata) {
try {
mangaMetadataRepository.insertMetadata(metadata)
} catch (e: Exception) {
logcat(LogPriority.ERROR, e)
}
}
}

View File

@ -0,0 +1,9 @@
package eu.kanade.domain.manga.model
data class MergeMangaSettingsUpdate(
val id: Long,
var isInfoManga: Boolean?,
var getChapterUpdates: Boolean?,
var chapterPriority: Int?,
var downloadChapters: Boolean?,
)

View File

@ -0,0 +1,11 @@
package eu.kanade.domain.manga.repository
import exh.favorites.sql.models.FavoriteEntry
interface FavoritesEntryRepository {
suspend fun deleteAll()
suspend fun insertAll(favoriteEntries: List<FavoriteEntry>)
suspend fun selectAll(): List<FavoriteEntry>
}

View File

@ -1,6 +1,7 @@
package eu.kanade.domain.manga.repository
import eu.kanade.domain.manga.model.Manga
import eu.kanade.domain.manga.model.MergeMangaSettingsUpdate
import exh.merged.sql.models.MergedMangaReference
import kotlinx.coroutines.flow.Flow
@ -16,4 +17,8 @@ interface MangaMergeRepository {
suspend fun getReferencesById(id: Long): List<MergedMangaReference>
suspend fun subscribeReferencesById(id: Long): Flow<List<MergedMangaReference>>
suspend fun updateSettings(update: MergeMangaSettingsUpdate): Boolean
suspend fun updateAllSettings(values: List<MergeMangaSettingsUpdate>): Boolean
}

View File

@ -1,5 +1,8 @@
package eu.kanade.domain.manga.repository
import eu.kanade.domain.manga.model.Manga
import exh.metadata.metadata.base.FlatMetadata
import exh.metadata.metadata.base.RaisedSearchMetadata
import exh.metadata.sql.models.SearchMetadata
import exh.metadata.sql.models.SearchTag
import exh.metadata.sql.models.SearchTitle
@ -17,4 +20,14 @@ interface MangaMetadataRepository {
suspend fun getTitlesById(id: Long): List<SearchTitle>
suspend fun subscribeTitlesById(id: Long): Flow<List<SearchTitle>>
suspend fun insertFlatMetadata(flatMetadata: FlatMetadata)
suspend fun insertMetadata(metadata: RaisedSearchMetadata) = insertFlatMetadata(metadata.flatten())
suspend fun getExhFavoriteMangaWithMetadata(): List<Manga>
suspend fun getIdsOfFavoriteMangaWithMetadata(): List<Long>
suspend fun getSearchMetadata(): List<SearchMetadata>
}

View File

@ -29,4 +29,8 @@ interface MangaRepository {
suspend fun update(update: MangaUpdate): Boolean
suspend fun updateAll(values: List<MangaUpdate>): Boolean
suspend fun getMangaBySource(sourceId: Long): List<Manga>
suspend fun getAll(): List<Manga>
}

View File

@ -14,31 +14,11 @@ 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.CategoryQueries
import eu.kanade.tachiyomi.data.database.queries.ChapterQueries
import eu.kanade.tachiyomi.data.database.queries.HistoryQueries
import eu.kanade.tachiyomi.data.database.queries.MangaCategoryQueries
import eu.kanade.tachiyomi.data.database.queries.MangaQueries
import eu.kanade.tachiyomi.data.database.queries.TrackQueries
import exh.favorites.sql.mappers.FavoriteEntryTypeMapping
import exh.favorites.sql.models.FavoriteEntry
import exh.favorites.sql.queries.FavoriteEntryQueries
import exh.merged.sql.mappers.MergedMangaTypeMapping
import exh.merged.sql.models.MergedMangaReference
import exh.merged.sql.queries.MergedQueries
import exh.metadata.sql.mappers.SearchMetadataTypeMapping
import exh.metadata.sql.mappers.SearchTagTypeMapping
import exh.metadata.sql.mappers.SearchTitleTypeMapping
import exh.metadata.sql.models.SearchMetadata
import exh.metadata.sql.models.SearchTag
import exh.metadata.sql.models.SearchTitle
import exh.metadata.sql.queries.SearchMetadataQueries
import exh.metadata.sql.queries.SearchTagQueries
import exh.metadata.sql.queries.SearchTitleQueries
import exh.savedsearches.mappers.FeedSavedSearchTypeMapping
import exh.savedsearches.mappers.SavedSearchTypeMapping
import exh.savedsearches.models.FeedSavedSearch
import exh.savedsearches.models.SavedSearch
/**
* This class provides operations to manage the database through its interfaces.
@ -48,16 +28,8 @@ class DatabaseHelper(
) :
MangaQueries,
ChapterQueries,
TrackQueries,
CategoryQueries,
MangaCategoryQueries,
HistoryQueries,
/* SY --> */
SearchMetadataQueries,
SearchTagQueries,
SearchTitleQueries,
MergedQueries,
FavoriteEntryQueries
MergedQueries
/* SY <-- */ {
override val db = DefaultStorIOSQLite.builder()
@ -69,13 +41,7 @@ class DatabaseHelper(
.addTypeMapping(MangaCategory::class.java, MangaCategoryTypeMapping())
.addTypeMapping(History::class.java, HistoryTypeMapping())
// SY -->
.addTypeMapping(SearchMetadata::class.java, SearchMetadataTypeMapping())
.addTypeMapping(SearchTag::class.java, SearchTagTypeMapping())
.addTypeMapping(SearchTitle::class.java, SearchTitleTypeMapping())
.addTypeMapping(MergedMangaReference::class.java, MergedMangaTypeMapping())
.addTypeMapping(FavoriteEntry::class.java, FavoriteEntryTypeMapping())
.addTypeMapping(SavedSearch::class.java, SavedSearchTypeMapping())
.addTypeMapping(FeedSavedSearch::class.java, FeedSavedSearchTypeMapping())
// SY <--
.build()

View File

@ -1,33 +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.Category
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.database.tables.CategoryTable
interface CategoryQueries : DbProvider {
fun getCategories() = db.get()
.listOfObjects(Category::class.java)
.withQuery(
Query.builder()
.table(CategoryTable.TABLE)
.orderBy(CategoryTable.COL_ORDER)
.build(),
)
.prepare()
fun getCategoriesForManga(manga: Manga) = db.get()
.listOfObjects(Category::class.java)
.withQuery(
RawQuery.builder()
.query(getCategoriesForMangaQuery())
.args(manga.id)
.build(),
)
.prepare()
fun insertCategories(categories: List<Category>) = db.put().objects(categories).prepare()
}

View File

@ -23,54 +23,6 @@ interface ChapterQueries : DbProvider {
.prepare()
// SY <--
fun getChapter(id: Long) = db.get()
.`object`(Chapter::class.java)
.withQuery(
Query.builder()
.table(ChapterTable.TABLE)
.where("${ChapterTable.COL_ID} = ?")
.whereArgs(id)
.build(),
)
.prepare()
fun getChapter(url: String, mangaId: Long) = db.get()
.`object`(Chapter::class.java)
.withQuery(
Query.builder()
.table(ChapterTable.TABLE)
.where("${ChapterTable.COL_URL} = ? AND ${ChapterTable.COL_MANGA_ID} = ?")
.whereArgs(url, mangaId)
.build(),
)
.prepare()
// SY -->
fun getChapters(url: String) = db.get()
.listOfObjects(Chapter::class.java)
.withQuery(
Query.builder()
.table(ChapterTable.TABLE)
.where("${ChapterTable.COL_URL} = ?")
.whereArgs(url)
.build(),
)
.prepare()
fun getChaptersReadByUrls(urls: List<String>) = db.get()
.listOfObjects(Chapter::class.java)
.withQuery(
Query.builder()
.table(ChapterTable.TABLE)
.where("${ChapterTable.COL_URL} IN (?) AND (${ChapterTable.COL_READ} = 1 OR ${ChapterTable.COL_LAST_PAGE_READ} != 0)")
.whereArgs(urls.joinToString { "\"$it\"" })
.build(),
)
.prepare()
// SY <--
fun insertChapters(chapters: List<Chapter>) = db.put().objects(chapters).prepare()
fun deleteChapters(chapters: List<Chapter>) = db.delete().objects(chapters).prepare()
fun updateChapterProgress(chapter: Chapter) = db.put()

View File

@ -1,50 +0,0 @@
package eu.kanade.tachiyomi.data.database.queries
import com.pushtorefresh.storio.sqlite.queries.DeleteQuery
import com.pushtorefresh.storio.sqlite.queries.RawQuery
import eu.kanade.tachiyomi.data.database.DbProvider
import eu.kanade.tachiyomi.data.database.models.History
import eu.kanade.tachiyomi.data.database.resolvers.HistoryChapterIdPutResolver
import eu.kanade.tachiyomi.data.database.resolvers.HistoryUpsertResolver
import eu.kanade.tachiyomi.data.database.tables.HistoryTable
interface HistoryQueries : DbProvider {
fun getHistoryByMangaId(mangaId: Long) = db.get()
.listOfObjects(History::class.java)
.withQuery(
RawQuery.builder()
.query(getHistoryByMangaId())
.args(mangaId)
.observesTables(HistoryTable.TABLE)
.build(),
)
.prepare()
/**
* Updates the history last read.
* Inserts history object if not yet in database
* @param historyList history object list
*/
fun upsertHistoryLastRead(historyList: List<History>) = db.put()
.objects(historyList)
.withPutResolver(HistoryUpsertResolver())
.prepare()
// SY -->
fun updateHistoryChapterIds(history: List<History>) = db.put()
.objects(history)
.withPutResolver(HistoryChapterIdPutResolver())
.prepare()
fun deleteHistoryIds(ids: List<Long>) = db.delete()
.byQuery(
DeleteQuery.builder()
.table(HistoryTable.TABLE)
.where("${HistoryTable.COL_ID} IN (?)")
.whereArgs(ids.joinToString())
.build(),
)
.prepare()
// SY <--
}

View File

@ -1,37 +0,0 @@
package eu.kanade.tachiyomi.data.database.queries
import com.pushtorefresh.storio.Queries
import com.pushtorefresh.storio.sqlite.queries.DeleteQuery
import eu.kanade.tachiyomi.data.database.DbProvider
import eu.kanade.tachiyomi.data.database.inTransaction
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.database.models.MangaCategory
import eu.kanade.tachiyomi.data.database.tables.MangaCategoryTable
interface MangaCategoryQueries : DbProvider {
fun insertMangasCategories(mangasCategories: List<MangaCategory>) = db.put().objects(mangasCategories).prepare()
fun deleteOldMangasCategories(mangas: List<Manga>) = db.delete()
.byQuery(
DeleteQuery.builder()
.table(MangaCategoryTable.TABLE)
.where("${MangaCategoryTable.COL_MANGA_ID} IN (${Queries.placeholders(mangas.size)})")
.whereArgs(*mangas.map { it.id }.toTypedArray())
.build(),
)
.prepare()
fun setMangaCategories(mangasCategories: List<MangaCategory>, mangas: List<Manga>) {
db.inTransaction {
// SY -->
mangas.chunked(100) { chunk ->
deleteOldMangasCategories(chunk).executeAsBlocking()
}
mangasCategories.chunked(100) { chunk ->
insertMangasCategories(chunk).executeAsBlocking()
}
// SY <--
}
}
}

View File

@ -6,17 +6,11 @@ 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.MangaFavoritePutResolver
import eu.kanade.tachiyomi.data.database.resolvers.MangaFilteredScanlatorsPutResolver
import eu.kanade.tachiyomi.data.database.resolvers.MangaFlagsPutResolver
import eu.kanade.tachiyomi.data.database.resolvers.MangaInfoPutResolver
import eu.kanade.tachiyomi.data.database.resolvers.MangaMigrationPutResolver
import eu.kanade.tachiyomi.data.database.resolvers.MangaThumbnailPutResolver
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
import exh.metadata.sql.tables.SearchMetadataTable
interface MangaQueries : DbProvider {
@ -64,50 +58,8 @@ interface MangaQueries : DbProvider {
)
.prepare()
// SY -->
fun getMangas() = db.get()
.listOfObjects(Manga::class.java)
.withQuery(
Query.builder()
.table(MangaTable.TABLE)
.build(),
)
.prepare()
fun getReadNotInLibraryMangas() = db.get()
.listOfObjects(Manga::class.java)
.withQuery(
RawQuery.builder()
.query(getReadMangaNotInLibraryQuery())
.build(),
)
.prepare()
fun updateMangaInfo(manga: Manga) = db.put()
.`object`(manga)
.withPutResolver(MangaInfoPutResolver())
.prepare()
fun resetMangaInfo(manga: Manga) = db.put()
.`object`(manga)
.withPutResolver(MangaInfoPutResolver(true))
.prepare()
fun updateMangaMigrate(manga: Manga) = db.put()
.`object`(manga)
.withPutResolver(MangaMigrationPutResolver())
.prepare()
fun updateMangaThumbnail(manga: Manga) = db.put()
.`object`(manga)
.withPutResolver(MangaThumbnailPutResolver())
.prepare()
// SY <--
fun insertManga(manga: Manga) = db.put().`object`(manga).prepare()
fun insertMangas(mangas: List<Manga>) = db.put().objects(mangas).prepare()
fun updateChapterFlags(manga: Manga) = db.put()
.`object`(manga)
.withPutResolver(MangaFlagsPutResolver(MangaTable.COL_CHAPTER_FLAGS, Manga::chapter_flags))
@ -123,69 +75,5 @@ interface MangaQueries : DbProvider {
.withPutResolver(MangaFlagsPutResolver(MangaTable.COL_VIEWER, Manga::viewer_flags))
.prepare()
fun updateMangaFavorite(manga: Manga) = db.put()
.`object`(manga)
.withPutResolver(MangaFavoritePutResolver())
.prepare()
// SY -->
fun updateMangaFilteredScanlators(manga: Manga) = db.put()
.`object`(manga)
.withPutResolver(MangaFilteredScanlatorsPutResolver())
.prepare()
// SY <--
fun deleteManga(manga: Manga) = db.delete().`object`(manga).prepare()
// SY -->
fun getMangaWithMetadata() = db.get()
.listOfObjects(Manga::class.java)
.withQuery(
RawQuery.builder()
.query(
"""
SELECT ${MangaTable.TABLE}.* FROM ${MangaTable.TABLE}
INNER JOIN ${SearchMetadataTable.TABLE}
ON ${MangaTable.TABLE}.${MangaTable.COL_ID} = ${SearchMetadataTable.TABLE}.${SearchMetadataTable.COL_MANGA_ID}
ORDER BY ${MangaTable.TABLE}.${MangaTable.COL_ID}
""".trimIndent(),
)
.build(),
)
.prepare()
fun getFavoriteMangaWithMetadata() = db.get()
.listOfObjects(Manga::class.java)
.withQuery(
RawQuery.builder()
.query(
"""
SELECT ${MangaTable.TABLE}.* FROM ${MangaTable.TABLE}
INNER JOIN ${SearchMetadataTable.TABLE}
ON ${MangaTable.TABLE}.${MangaTable.COL_ID} = ${SearchMetadataTable.TABLE}.${SearchMetadataTable.COL_MANGA_ID}
WHERE ${MangaTable.TABLE}.${MangaTable.COL_FAVORITE} = 1
ORDER BY ${MangaTable.TABLE}.${MangaTable.COL_ID}
""".trimIndent(),
)
.build(),
)
.prepare()
fun getIdsOfFavoriteMangaWithMetadata() = db.get()
.cursor()
.withQuery(
RawQuery.builder()
.query(
"""
SELECT ${MangaTable.TABLE}.${MangaTable.COL_ID} FROM ${MangaTable.TABLE}
INNER JOIN ${SearchMetadataTable.TABLE}
ON ${MangaTable.TABLE}.${MangaTable.COL_ID} = ${SearchMetadataTable.TABLE}.${SearchMetadataTable.COL_MANGA_ID}
WHERE ${MangaTable.TABLE}.${MangaTable.COL_FAVORITE} = 1
ORDER BY ${MangaTable.TABLE}.${MangaTable.COL_ID}
""".trimIndent(),
)
.build(),
)
.prepare()
// SY <--
}

View File

@ -1,9 +1,7 @@
package eu.kanade.tachiyomi.data.database.queries
import exh.source.MERGED_SOURCE_ID
import eu.kanade.tachiyomi.data.database.tables.CategoryTable as Category
import eu.kanade.tachiyomi.data.database.tables.ChapterTable as Chapter
import eu.kanade.tachiyomi.data.database.tables.HistoryTable as History
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
@ -74,18 +72,6 @@ fun getMergedChaptersQuery() =
ON ${Chapter.TABLE}.${Chapter.COL_MANGA_ID} = M.${Merged.COL_MANGA_ID}
"""
/**
* Query to get manga that are not in library, but have read chapters
*/
fun getReadMangaNotInLibraryQuery() =
"""
SELECT ${Manga.TABLE}.*
FROM ${Manga.TABLE}
WHERE ${Manga.COL_FAVORITE} = 0 AND ${Manga.COL_ID} IN(
SELECT ${Chapter.TABLE}.${Chapter.COL_MANGA_ID} FROM ${Chapter.TABLE} WHERE ${Chapter.COL_READ} = 1 OR ${Chapter.COL_LAST_PAGE_READ} != 0
)
"""
/**
* Query to get the manga from the library, with their categories, read and unread count.
*/
@ -142,24 +128,4 @@ val libraryQuery =
ON MC.${MangaCategory.COL_MANGA_ID} = M.${Manga.COL_ID};
"""
fun getHistoryByMangaId() =
"""
SELECT ${History.TABLE}.*
FROM ${History.TABLE}
JOIN ${Chapter.TABLE}
ON ${History.TABLE}.${History.COL_CHAPTER_ID} = ${Chapter.TABLE}.${Chapter.COL_ID}
WHERE ${Chapter.TABLE}.${Chapter.COL_MANGA_ID} = ? AND ${History.TABLE}.${History.COL_CHAPTER_ID} = ${Chapter.TABLE}.${Chapter.COL_ID}
"""
/**
* Query to get the categories for a manga.
*/
fun getCategoriesForMangaQuery() =
"""
SELECT ${Category.TABLE}.* FROM ${Category.TABLE}
JOIN ${MangaCategory.TABLE} ON ${Category.TABLE}.${Category.COL_ID} =
${MangaCategory.TABLE}.${MangaCategory.COL_CATEGORY_ID}
WHERE ${MangaCategory.COL_MANGA_ID} = ?
"""
// SY <--

View File

@ -1,33 +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.Track
import eu.kanade.tachiyomi.data.database.tables.TrackTable
interface TrackQueries : DbProvider {
fun getTracks() = db.get()
.listOfObjects(Track::class.java)
.withQuery(
Query.builder()
.table(TrackTable.TABLE)
.build(),
)
.prepare()
fun getTracks(mangaId: Long?) = db.get()
.listOfObjects(Track::class.java)
.withQuery(
Query.builder()
.table(TrackTable.TABLE)
.where("${TrackTable.COL_MANGA_ID} = ?")
.whereArgs(mangaId)
.build(),
)
.prepare()
fun insertTrack(track: Track) = db.put().`object`(track).prepare()
fun insertTracks(tracks: List<Track>) = db.put().objects(tracks).prepare()
}

View File

@ -4,7 +4,7 @@ import android.content.Context
import androidx.core.content.edit
import eu.kanade.domain.chapter.interactor.GetChapter
import eu.kanade.domain.chapter.model.toDbChapter
import eu.kanade.domain.manga.interactor.GetMangaById
import eu.kanade.domain.manga.interactor.GetManga
import eu.kanade.domain.manga.model.toDbManga
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.download.model.Download
@ -34,7 +34,7 @@ class DownloadStore(
private val json: Json by injectLazy()
private val getMangaById: GetMangaById by injectLazy()
private val getManga: GetManga by injectLazy()
private val getChapter: GetChapter by injectLazy()
/**
@ -96,7 +96,7 @@ class DownloadStore(
val cachedManga = mutableMapOf<Long, Manga?>()
for ((mangaId, chapterId) in objs) {
val manga = cachedManga.getOrPut(mangaId) {
runBlocking { getMangaById.await(mangaId)?.toDbManga() }
runBlocking { getManga.await(mangaId)?.toDbManga() }
} ?: continue
val source = sourceManager.get(manga.source) as? HttpSource ?: continue
val chapter = runBlocking { getChapter.await(chapterId) }?.toDbChapter() ?: continue

View File

@ -2,7 +2,7 @@ package eu.kanade.tachiyomi.data.download.model
import eu.kanade.domain.chapter.interactor.GetChapter
import eu.kanade.domain.chapter.model.toDbChapter
import eu.kanade.domain.manga.interactor.GetMangaById
import eu.kanade.domain.manga.interactor.GetManga
import eu.kanade.domain.manga.model.toDbManga
import eu.kanade.tachiyomi.data.database.models.Chapter
import eu.kanade.tachiyomi.data.database.models.Manga
@ -69,11 +69,11 @@ data class Download(
suspend fun fromChapterId(
chapterId: Long,
getChapter: GetChapter = Injekt.get(),
getMangaById: GetMangaById = Injekt.get(),
getManga: GetManga = Injekt.get(),
sourceManager: SourceManager = Injekt.get(),
): Download? {
val chapter = getChapter.await(chapterId) ?: return null
val manga = getMangaById.await(chapter.mangaId) ?: return null
val manga = getManga.await(chapter.mangaId) ?: return null
val source = sourceManager.get(manga.source) as? HttpSource ?: return null
return Download(source, manga.toDbManga(), chapter.toDbChapter())

View File

@ -13,7 +13,9 @@ import eu.kanade.domain.chapter.interactor.GetChapterByMangaId
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.GetMangaById
import eu.kanade.domain.manga.interactor.GetFavorites
import eu.kanade.domain.manga.interactor.GetManga
import eu.kanade.domain.manga.interactor.InsertFlatMetadata
import eu.kanade.domain.manga.interactor.UpdateManga
import eu.kanade.domain.manga.model.toDbManga
import eu.kanade.domain.manga.model.toMangaInfo
@ -61,7 +63,6 @@ import eu.kanade.tachiyomi.util.system.logcat
import exh.log.xLogE
import exh.md.utils.FollowStatus
import exh.md.utils.MdUtil
import exh.metadata.metadata.base.insertFlatMetadataAsync
import exh.source.LIBRARY_UPDATE_EXCLUDED_SOURCES
import exh.source.MERGED_SOURCE_ID
import exh.source.isMdBasedSource
@ -77,6 +78,7 @@ import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.supervisorScope
import kotlinx.coroutines.sync.Semaphore
import kotlinx.coroutines.sync.withPermit
@ -106,7 +108,7 @@ class LibraryUpdateService(
val downloadManager: DownloadManager = Injekt.get(),
val trackManager: TrackManager = Injekt.get(),
val coverCache: CoverCache = Injekt.get(),
private val getMangaById: GetMangaById = Injekt.get(),
private val getManga: GetManga = Injekt.get(),
private val updateManga: UpdateManga = Injekt.get(),
private val getChapterByMangaId: GetChapterByMangaId = Injekt.get(),
private val getCategories: GetCategories = Injekt.get(),
@ -114,6 +116,10 @@ class LibraryUpdateService(
private val getTracks: GetTracks = Injekt.get(),
private val insertTrack: InsertTrack = Injekt.get(),
private val syncChaptersWithTrackServiceTwoWay: SyncChaptersWithTrackServiceTwoWay = Injekt.get(),
// SY -->
private val getFavorites: GetFavorites = Injekt.get(),
private val insertFlatMetadata: InsertFlatMetadata = Injekt.get(),
// SY <--
) : Service() {
private lateinit var wakeLock: PowerManager.WakeLock
@ -327,11 +333,11 @@ class LibraryUpdateService(
when (group) {
LibraryGroup.BY_TRACK_STATUS -> {
val trackingExtra = groupExtra?.toIntOrNull() ?: -1
val tracks = db.getTracks().executeAsBlocking().groupBy { it.manga_id }
val tracks = runBlocking { getTracks.await() }.groupBy { it.mangaId }
libraryManga.filter { manga ->
val status = tracks[manga.id]?.firstNotNullOfOrNull { track ->
TrackStatus.parseTrackerStatus(track.sync_id.toLong(), track.status)
TrackStatus.parseTrackerStatus(track.syncId, track.status)
} ?: TrackStatus.OTHER
status.int == trackingExtra
}
@ -404,7 +410,7 @@ class LibraryUpdateService(
}
// Don't continue to update if manga not in library
manga.id?.let { getMangaById.await(it) } ?: return@forEach
manga.id?.let { getManga.await(it) } ?: return@forEach
withUpdateNotification(
currentlyUpdatingManga,
@ -536,7 +542,7 @@ class LibraryUpdateService(
val tracks = getTracks.await(manga.id)
if (tracks.isEmpty() || tracks.none { it.syncId == TrackManager.MDLIST }) {
val track = trackManager.mdList.createInitialTracker(manga.toDbManga())
db.insertTrack(trackManager.mdList.refresh(track)).executeAsBlocking()
insertTrack.await(trackManager.mdList.refresh(track).toDomainTrack(false)!!)
}
}
}
@ -550,7 +556,7 @@ class LibraryUpdateService(
.map { it.toSChapter() }
// Get manga from database to account for if it was removed during the update
val dbManga = getMangaById.await(manga.id)
val dbManga = getManga.await(manga.id)
?: return Pair(emptyList(), emptyList())
// [dbmanga] was used so that manga data doesn't get overwritten
@ -724,7 +730,7 @@ class LibraryUpdateService(
val id = db.insertManga(dbManga).executeOnIO().insertedId()
if (id != null) {
metadata.mangaId = id
db.insertFlatMetadataAsync(metadata.flatten()).await()
insertFlatMetadata.await(metadata)
}
}
@ -736,7 +742,7 @@ class LibraryUpdateService(
*/
private suspend fun pushFavorites() {
var count = 0
val listManga = db.getFavoriteMangas().executeAsBlocking().filter { it.source in mangaDexSourceIds }
val listManga = getFavorites.await().filter { it.source in mangaDexSourceIds }
// filter all follows from Mangadex and only add reading or rereading manga to library
if (trackManager.mdList.isLogged) {
@ -746,18 +752,18 @@ class LibraryUpdateService(
}
count++
notifier.showProgressNotification(listOf(manga), count, listManga.size)
notifier.showProgressNotification(listOf(manga.toDbManga()), count, listManga.size)
// Get this manga's trackers from the database
val dbTracks = getTracks.await(manga.id!!)
val dbTracks = getTracks.await(manga.id)
// find the mdlist entry if its unfollowed the follow it
val tracker = TrackItem(dbTracks.firstOrNull { it.syncId == TrackManager.MDLIST }?.toDbTrack() ?: trackManager.mdList.createInitialTracker(manga), trackManager.mdList)
val tracker = TrackItem(dbTracks.firstOrNull { it.syncId == TrackManager.MDLIST }?.toDbTrack() ?: trackManager.mdList.createInitialTracker(manga.toDbManga()), trackManager.mdList)
if (tracker.track?.status == FollowStatus.UNFOLLOWED.int) {
tracker.track.status = FollowStatus.READING.int
val updatedTrack = tracker.service.update(tracker.track)
db.insertTrack(updatedTrack).executeOnIO()
insertTrack.await(updatedTrack.toDomainTrack(false)!!)
}
}
}

View File

@ -11,7 +11,7 @@ import eu.kanade.domain.chapter.interactor.GetChapter
import eu.kanade.domain.chapter.interactor.UpdateChapter
import eu.kanade.domain.chapter.model.toChapterUpdate
import eu.kanade.domain.chapter.model.toDbChapter
import eu.kanade.domain.manga.interactor.GetMangaById
import eu.kanade.domain.manga.interactor.GetManga
import eu.kanade.domain.manga.model.toDbManga
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.backup.BackupRestoreService
@ -46,7 +46,7 @@ import eu.kanade.tachiyomi.BuildConfig.APPLICATION_ID as ID
*/
class NotificationReceiver : BroadcastReceiver() {
private val getMangaById: GetMangaById by injectLazy()
private val getManga: GetManga by injectLazy()
private val getChapter: GetChapter by injectLazy()
private val updateChapter: UpdateChapter by injectLazy()
private val downloadManager: DownloadManager by injectLazy()
@ -178,7 +178,7 @@ class NotificationReceiver : BroadcastReceiver() {
* @param chapterId id of chapter
*/
private fun openChapter(context: Context, mangaId: Long, chapterId: Long) {
val manga = runBlocking { getMangaById.await(mangaId) }
val manga = runBlocking { getManga.await(mangaId) }
val chapter = runBlocking { getChapter.await(chapterId) }
if (manga != null && chapter != null) {
val intent = ReaderActivity.newIntent(context, manga.id, chapter.id).apply {
@ -248,7 +248,7 @@ class NotificationReceiver : BroadcastReceiver() {
.map {
val chapter = it.copy(read = true)
if (preferences.removeAfterMarkedAsRead()) {
val manga = getMangaById.await(mangaId)
val manga = getManga.await(mangaId)
if (manga != null) {
val source = sourceManager.get(manga.source)
if (source != null) {
@ -270,7 +270,7 @@ class NotificationReceiver : BroadcastReceiver() {
*/
private fun downloadChapters(chapterUrls: Array<String>, mangaId: Long) {
launchIO {
val manga = getMangaById.await(mangaId)?.toDbManga()
val manga = getManga.await(mangaId)?.toDbManga()
val chapters = chapterUrls.mapNotNull { getChapter.await(it, mangaId)?.toDbChapter() }
if (manga != null && chapters.isNotEmpty()) {
downloadManager.downloadChapters(manga, chapters)

View File

@ -21,7 +21,8 @@ enum class TrackStatus(val int: Int, @StringRes val res: Int) {
OTHER(7, R.string.not_tracked);
companion object {
fun parseTrackerStatus(tracker: Long, status: Int): TrackStatus? {
fun parseTrackerStatus(tracker: Long, statusLong: Long): TrackStatus? {
val status = statusLong.toInt()
return when (tracker) {
TrackManager.MDLIST -> {
when (FollowStatus.fromInt(status)) {

View File

@ -9,7 +9,7 @@ import androidx.work.NetworkType
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager
import androidx.work.WorkerParameters
import eu.kanade.domain.manga.interactor.GetMangaById
import eu.kanade.domain.manga.interactor.GetManga
import eu.kanade.domain.track.interactor.GetTracks
import eu.kanade.domain.track.interactor.InsertTrack
import eu.kanade.domain.track.model.toDbTrack
@ -26,7 +26,7 @@ class DelayedTrackingUpdateJob(context: Context, workerParams: WorkerParameters)
CoroutineWorker(context, workerParams) {
override suspend fun doWork(): Result {
val getMangaById = Injekt.get<GetMangaById>()
val getManga = Injekt.get<GetManga>()
val getTracks = Injekt.get<GetTracks>()
val insertTrack = Injekt.get<InsertTrack>()
@ -35,7 +35,7 @@ class DelayedTrackingUpdateJob(context: Context, workerParams: WorkerParameters)
withContext(Dispatchers.IO) {
val tracks = delayedTrackingStore.getItems().mapNotNull {
val manga = getMangaById.await(it.mangaId) ?: return@withContext
val manga = getManga.await(it.mangaId) ?: return@withContext
getTracks.await(manga.id)
.find { track -> track.id == it.trackId }
?.copy(lastChapterRead = it.lastChapterRead.toDouble())

View File

@ -1,9 +1,9 @@
package eu.kanade.tachiyomi.source.online
import androidx.compose.runtime.Composable
import eu.kanade.data.DatabaseHandler
import eu.kanade.domain.manga.interactor.GetMangaByUrlAndSource
import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.domain.manga.interactor.GetFlatMetadataById
import eu.kanade.domain.manga.interactor.GetManga
import eu.kanade.domain.manga.interactor.InsertFlatMetadata
import eu.kanade.tachiyomi.data.database.models.Chapter
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.source.CatalogueSource
@ -14,8 +14,6 @@ import eu.kanade.tachiyomi.ui.manga.MangaScreenState
import eu.kanade.tachiyomi.util.lang.awaitSingle
import eu.kanade.tachiyomi.util.lang.runAsObservable
import exh.metadata.metadata.base.RaisedSearchMetadata
import exh.metadata.metadata.base.awaitFlatMetadataForManga
import exh.metadata.metadata.base.awaitInsertFlatMetadata
import rx.Completable
import rx.Single
import tachiyomi.source.model.MangaInfo
@ -27,9 +25,9 @@ import kotlin.reflect.KClass
* LEWD!
*/
interface MetadataSource<M : RaisedSearchMetadata, I> : CatalogueSource {
val db: DatabaseHelper get() = Injekt.get()
val handler: DatabaseHandler get() = Injekt.get()
val getMangaByUrlAndSource: GetMangaByUrlAndSource get() = Injekt.get()
val getManga: GetManga get() = Injekt.get()
val insertFlatMetadata: InsertFlatMetadata get() = Injekt.get()
val getFlatMetadataById: GetFlatMetadataById get() = Injekt.get()
/**
* The class of the metadata used by this source
@ -63,14 +61,14 @@ interface MetadataSource<M : RaisedSearchMetadata, I> : CatalogueSource {
suspend fun parseToManga(manga: MangaInfo, input: I): MangaInfo {
val mangaId = manga.id()
val metadata = if (mangaId != null) {
val flatMetadata = handler.awaitFlatMetadataForManga(mangaId)
val flatMetadata = getFlatMetadataById.await(mangaId)
flatMetadata?.raise(metaClass) ?: newMetaInstance()
} else newMetaInstance()
parseIntoMetadata(metadata, input)
if (mangaId != null) {
metadata.mangaId = mangaId
handler.awaitInsertFlatMetadata(metadata.flatten())
insertFlatMetadata.await(metadata)
}
return metadata.createMangaInfo(manga)
@ -99,7 +97,7 @@ interface MetadataSource<M : RaisedSearchMetadata, I> : CatalogueSource {
*/
suspend fun fetchOrLoadMetadata(mangaId: Long?, inputProducer: suspend () -> I): M {
val meta = if (mangaId != null) {
val flatMetadata = handler.awaitFlatMetadataForManga(mangaId)
val flatMetadata = getFlatMetadataById.await(mangaId)
flatMetadata?.raise(metaClass)
} else {
null
@ -110,7 +108,7 @@ interface MetadataSource<M : RaisedSearchMetadata, I> : CatalogueSource {
parseIntoMetadata(newMeta, input)
if (mangaId != null) {
newMeta.mangaId = mangaId
handler.awaitInsertFlatMetadata(newMeta.flatten())
insertFlatMetadata.await(newMeta)
}
newMeta
}
@ -119,7 +117,7 @@ interface MetadataSource<M : RaisedSearchMetadata, I> : CatalogueSource {
@Composable
fun DescriptionComposable(state: MangaScreenState.Success, openMetadataViewer: () -> Unit, search: (String) -> Unit)
suspend fun MangaInfo.id() = getMangaByUrlAndSource.await(key, id)?.id
suspend fun MangaInfo.id() = getManga.await(key, id)?.id
val SManga.id get() = (this as? Manga)?.id
val SChapter.mangaId get() = (this as? Chapter)?.manga_id
}

View File

@ -1,6 +1,6 @@
package eu.kanade.tachiyomi.ui.browse.migration.advanced.process
import eu.kanade.domain.manga.interactor.GetMangaById
import eu.kanade.domain.manga.interactor.GetManga
import eu.kanade.domain.manga.model.Manga
import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.source.SourceManager
@ -11,7 +11,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlin.coroutines.CoroutineContext
class MigratingManga(
private val getMangaById: GetMangaById,
private val getManga: GetManga,
private val sourceManager: SourceManager,
val mangaId: Long,
parentContext: CoroutineContext,
@ -28,7 +28,7 @@ class MigratingManga(
@Volatile
private var manga: Manga? = null
suspend fun manga(): Manga? {
if (manga == null) manga = getMangaById.await(mangaId)
if (manga == null) manga = getManga.await(mangaId)
return manga
}

View File

@ -16,7 +16,7 @@ import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import dev.chrisbanes.insetter.applyInsetter
import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource
import eu.kanade.domain.manga.interactor.GetMangaById
import eu.kanade.domain.manga.interactor.GetManga
import eu.kanade.domain.manga.interactor.UpdateManga
import eu.kanade.domain.manga.model.toDbManga
import eu.kanade.domain.manga.model.toMangaInfo
@ -75,7 +75,7 @@ class MigrationListController(bundle: Bundle? = null) :
private val smartSearchEngine = SmartSearchEngine(config?.extraSearchParams)
private val syncChaptersWithSource: SyncChaptersWithSource by injectLazy()
private val getMangaById: GetMangaById by injectLazy()
private val getManga: GetManga by injectLazy()
private val updateManga: UpdateManga by injectLazy()
private val migrationScope = CoroutineScope(Job() + Dispatchers.IO)
@ -109,7 +109,7 @@ class MigrationListController(bundle: Bundle? = null) :
val newMigratingManga = migratingManga ?: run {
val new = config.mangaIds.map {
MigratingManga(getMangaById, sourceManager, it, migrationScope.coroutineContext)
MigratingManga(getManga, sourceManager, it, migrationScope.coroutineContext)
}
migratingManga = new.toMutableList()
new
@ -409,7 +409,7 @@ class MigrationListController(bundle: Bundle? = null) :
val hasDetails = router.backstack.any { it.controller is MangaController }
if (hasDetails) {
val manga = migratingManga?.firstOrNull()?.searchResult?.get()?.let {
getMangaById.await(it)
getManga.await(it)
}
if (manga != null) {
val newStack = router.backstack.filter {

View File

@ -12,7 +12,7 @@ import eu.kanade.domain.chapter.model.Chapter
import eu.kanade.domain.chapter.model.ChapterUpdate
import eu.kanade.domain.history.interactor.UpsertHistory
import eu.kanade.domain.history.model.HistoryUpdate
import eu.kanade.domain.manga.interactor.GetMangaById
import eu.kanade.domain.manga.interactor.GetManga
import eu.kanade.domain.manga.interactor.UpdateManga
import eu.kanade.domain.manga.model.Manga
import eu.kanade.domain.manga.model.MangaUpdate
@ -35,7 +35,7 @@ class MigrationProcessAdapter(
private val handler: DatabaseHandler by injectLazy()
private val preferences: PreferencesHelper by injectLazy()
private val coverCache: CoverCache by injectLazy()
private val getMangaById: GetMangaById by injectLazy()
private val getManga: GetManga by injectLazy()
private val updateManga: UpdateManga by injectLazy()
private val updateChapter: UpdateChapter by injectLazy()
private val getChapterByMangaId: GetChapterByMangaId by injectLazy()
@ -81,7 +81,7 @@ class MigrationProcessAdapter(
currentItems.forEach { migratingManga ->
val manga = migratingManga.manga
if (manga.searchResult.initialized) {
val toMangaObj = getMangaById.await(manga.searchResult.get() ?: return@forEach)
val toMangaObj = getManga.await(manga.searchResult.get() ?: return@forEach)
?: return@forEach
migrateMangaInternal(
manga.manga() ?: return@forEach,
@ -97,7 +97,7 @@ class MigrationProcessAdapter(
launchUI {
val manga = getItem(position)?.manga ?: return@launchUI
val toMangaObj = getMangaById.await(manga.searchResult.get() ?: return@launchUI)
val toMangaObj = getManga.await(manga.searchResult.get() ?: return@launchUI)
?: return@launchUI
migrateMangaInternal(
manga.manga() ?: return@launchUI,

View File

@ -7,7 +7,7 @@ import androidx.core.view.isVisible
import coil.dispose
import eu.davidea.viewholders.FlexibleViewHolder
import eu.kanade.domain.chapter.interactor.GetChapterByMangaId
import eu.kanade.domain.manga.interactor.GetMangaById
import eu.kanade.domain.manga.interactor.GetManga
import eu.kanade.domain.manga.interactor.GetMergedReferencesById
import eu.kanade.domain.manga.model.Manga
import eu.kanade.tachiyomi.R
@ -32,7 +32,7 @@ class MigrationProcessHolder(
private val adapter: MigrationProcessAdapter,
) : FlexibleViewHolder(view, adapter) {
private val sourceManager: SourceManager by injectLazy()
private val getMangaById: GetMangaById by injectLazy()
private val getManga: GetManga by injectLazy()
private val getChapterByMangaId: GetChapterByMangaId by injectLazy()
private val getMergedReferencesById: GetMergedReferencesById by injectLazy()
@ -89,7 +89,7 @@ class MigrationProcessHolder(
}*/
val searchResult = item.manga.searchResult.get()?.let {
getMangaById.await(it)
getManga.await(it)
}
val resultSource = searchResult?.source?.let {
sourceManager.get(it)

View File

@ -5,9 +5,9 @@ import android.view.MenuInflater
import android.view.MenuItem
import androidx.compose.runtime.Composable
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
import eu.kanade.domain.manga.interactor.GetFavorites
import eu.kanade.presentation.browse.MigrateSourceScreen
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.ui.base.controller.ComposeController
import eu.kanade.tachiyomi.ui.base.controller.pushController
@ -54,10 +54,9 @@ class MigrationSourcesController : ComposeController<MigrationSourcesPresenter>(
onClickAll = { source ->
// TODO: Jay wtf, need to clean this up sometime
launchIO {
val manga = Injekt.get<DatabaseHelper>().getFavoriteMangas().executeAsBlocking()
val manga = Injekt.get<GetFavorites>().await()
val sourceMangas =
manga.asSequence().filter { it.source == source.id }.mapNotNull { it.id }
.toList()
manga.asSequence().filter { it.source == source.id }.map { it.id }.toList()
withUIContext {
PreMigrationController.navigateToMigration(
Injekt.get<PreferencesHelper>().skipPreMigration().get(),

View File

@ -1,11 +1,12 @@
package eu.kanade.tachiyomi.ui.library
import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.kanade.domain.manga.interactor.GetIdsOfFavoriteMangaWithMetadata
import eu.kanade.domain.manga.interactor.GetSearchTags
import eu.kanade.domain.manga.interactor.GetSearchTitles
import eu.kanade.domain.track.interactor.GetTracks
import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.LibraryManga
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.database.tables.MangaTable
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.track.TrackManager
import eu.kanade.tachiyomi.source.SourceManager
@ -21,7 +22,6 @@ import exh.search.SearchEngine
import exh.search.Text
import exh.source.isMetadataSource
import exh.util.cancellable
import exh.util.executeOnIO
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@ -41,7 +41,6 @@ import uy.kohesive.injekt.injectLazy
class LibraryCategoryAdapter(view: LibraryCategoryView, val controller: LibraryController) :
FlexibleAdapter<LibraryItem>(null, view, true) {
// EXH -->
private val db: DatabaseHelper by injectLazy()
private val searchEngine = SearchEngine()
private var lastFilterJob: Job? = null
private val sourceManager: SourceManager by injectLazy()
@ -50,8 +49,13 @@ class LibraryCategoryAdapter(view: LibraryCategoryView, val controller: LibraryC
private val hasLoggedServices by lazy {
trackManager.hasLoggedServices()
}
private val services = trackManager.services.map { service -> service.id to controller.activity!!.getString(service.nameRes()) }.toMap()
private val services = trackManager.services.associate { service ->
service.id to controller.activity!!.getString(service.nameRes())
}
private val getIdsOfFavoriteMangaWithMetadata: GetIdsOfFavoriteMangaWithMetadata by injectLazy()
private val getTracks: GetTracks by injectLazy()
private val getSearchTags: GetSearchTags by injectLazy()
private val getSearchTitles: GetSearchTitles by injectLazy()
// Keep compatibility as searchText field was replaced when we upgraded FlexibleAdapter
var searchText
@ -116,19 +120,7 @@ class LibraryCategoryAdapter(view: LibraryCategoryView, val controller: LibraryC
val newManga = try {
// Prepare filter object
val parsedQuery = searchEngine.parseQuery(savedSearchText)
val mangaWithMetaIdsQuery = db.getIdsOfFavoriteMangaWithMetadata().executeOnIO()
val mangaWithMetaIds = LongArray(mangaWithMetaIdsQuery.count)
if (mangaWithMetaIds.isNotEmpty()) {
val mangaIdCol = mangaWithMetaIdsQuery.getColumnIndex(MangaTable.COL_ID)
mangaWithMetaIdsQuery.moveToFirst()
while (!mangaWithMetaIdsQuery.isAfterLast) {
ensureActive() // Fail early when cancelled
mangaWithMetaIds[mangaWithMetaIdsQuery.position] = mangaWithMetaIdsQuery.getLong(mangaIdCol)
mangaWithMetaIdsQuery.moveToNext()
}
}
val mangaWithMetaIds = getIdsOfFavoriteMangaWithMetadata.await()
ensureActive() // Fail early when cancelled
@ -140,8 +132,8 @@ class LibraryCategoryAdapter(view: LibraryCategoryView, val controller: LibraryC
// No meta? Filter using title
filterManga(parsedQuery, item.manga)
} else {
val tags = db.getSearchTagsForManga(mangaId).executeAsBlocking()
val titles = db.getSearchTitlesForManga(mangaId).executeAsBlocking()
val tags = getSearchTags.await(mangaId)
val titles = getSearchTitles.await(mangaId)
filterManga(parsedQuery, item.manga, false, tags, titles)
}
} else {

View File

@ -934,7 +934,7 @@ class LibraryPresenter(
val tracks = runBlocking { getTracks.await() }.groupBy { it.mangaId }
libraryManga.forEach { libraryItem ->
val status = tracks[libraryItem.manga.id]?.firstNotNullOfOrNull { track ->
TrackStatus.parseTrackerStatus(track.syncId, track.status.toInt())
TrackStatus.parseTrackerStatus(track.syncId, track.status)
} ?: TrackStatus.OTHER
map.getOrPut(status.int.toLong()) { mutableListOf() } += libraryItem

View File

@ -13,7 +13,7 @@ import coil.transform.RoundedCornersTransformation
import com.google.android.material.chip.Chip
import com.google.android.material.chip.ChipGroup
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import eu.kanade.domain.manga.interactor.GetMangaById
import eu.kanade.domain.manga.interactor.GetManga
import eu.kanade.domain.manga.model.Manga
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.databinding.EditMangaDialogBinding
@ -52,7 +52,7 @@ class EditMangaDialog : DialogController {
@Suppress("unused")
constructor(bundle: Bundle) : super(bundle) {
manga = runBlocking { Injekt.get<GetMangaById>().await(bundle.getLong(KEY_MANGA))!! }
manga = runBlocking { Injekt.get<GetManga>().await(bundle.getLong(KEY_MANGA))!! }
}
override fun onCreateDialog(savedViewState: Bundle?): Dialog {

View File

@ -14,8 +14,7 @@ import eu.kanade.domain.chapter.model.ChapterUpdate
import eu.kanade.domain.chapter.model.toDbChapter
import eu.kanade.domain.manga.interactor.GetDuplicateLibraryManga
import eu.kanade.domain.manga.interactor.GetFlatMetadataById
import eu.kanade.domain.manga.interactor.GetMangaById
import eu.kanade.domain.manga.interactor.GetMangaByUrlAndSource
import eu.kanade.domain.manga.interactor.GetManga
import eu.kanade.domain.manga.interactor.GetMangaWithChapters
import eu.kanade.domain.manga.interactor.GetMergedMangaById
import eu.kanade.domain.manga.interactor.GetMergedReferencesById
@ -123,8 +122,7 @@ class MangaPresenter(
// SY <--
private val getMangaAndChapters: GetMangaWithChapters = Injekt.get(),
// SY -->
private val getMangaById: GetMangaById = Injekt.get(),
private val getMangaByUrlAndSource: GetMangaByUrlAndSource = Injekt.get(),
private val getManga: GetManga = Injekt.get(),
private val setMangaFilteredScanlators: SetMangaFilteredScanlators = Injekt.get(),
private val getMergedChapterByMangaId: GetMergedChapterByMangaId = Injekt.get(),
private val getMergedMangaById: GetMergedMangaById = Injekt.get(),
@ -435,7 +433,7 @@ class MangaPresenter(
suspend fun smartSearchMerge(context: Context, manga: DomainManga, originalMangaId: Long): DomainManga {
val db = Injekt.get<DatabaseHelper>()
val originalManga = getMangaById.await(originalMangaId)
val originalManga = getManga.await(originalMangaId)
?: throw IllegalArgumentException(context.getString(R.string.merge_unknown_manga, originalMangaId))
if (originalManga.source == MERGED_SOURCE_ID) {
val children = getMergedReferencesById.await(originalMangaId)
@ -490,7 +488,7 @@ class MangaPresenter(
date_added = System.currentTimeMillis()
}
var existingManga = getMangaByUrlAndSource.await(mergedManga.url, mergedManga.source)
var existingManga = getManga.await(mergedManga.url, mergedManga.source)
while (existingManga != null) {
if (existingManga.favorite) {
throw IllegalArgumentException(context.getString(R.string.merge_duplicate))
@ -500,7 +498,7 @@ class MangaPresenter(
db.deleteMangaForMergedManga(existingManga!!.id).executeAsBlocking()
}
}
existingManga = getMangaByUrlAndSource.await(mergedManga.url, mergedManga.source)
existingManga = getManga.await(mergedManga.url, mergedManga.source)
}
// Reload chapters immediately
@ -744,7 +742,7 @@ class MangaPresenter(
tracks
.filter { it.syncId in loggedServicesId }
// SY -->
.filterNot { it.syncId == TrackManager.MDLIST.toLong() && it.status == FollowStatus.UNFOLLOWED.int.toLong() }
.filterNot { it.syncId == TrackManager.MDLIST && it.status == FollowStatus.UNFOLLOWED.int.toLong() }
// SY <--
.size
}

View File

@ -20,7 +20,7 @@ import androidx.core.os.bundleOf
import coil.imageLoader
import coil.request.ImageRequest
import coil.size.Size
import eu.kanade.domain.manga.interactor.GetMangaById
import eu.kanade.domain.manga.interactor.GetManga
import eu.kanade.domain.manga.interactor.UpdateManga
import eu.kanade.domain.manga.model.Manga
import eu.kanade.domain.manga.model.hasCustomCover
@ -161,7 +161,7 @@ class MangaFullCoverDialog : FullComposeController<MangaFullCoverDialog.MangaFul
inner class MangaFullCoverPresenter(
private val mangaId: Long,
private val getMangaById: GetMangaById = Injekt.get(),
private val getManga: GetManga = Injekt.get(),
) : Presenter<MangaFullCoverDialog>() {
private var presenterScope: CoroutineScope = MainScope()
@ -176,7 +176,7 @@ class MangaFullCoverDialog : FullComposeController<MangaFullCoverDialog.MangaFul
override fun onCreate(savedState: Bundle?) {
super.onCreate(savedState)
presenterScope.launchIO {
getMangaById.subscribe(mangaId)
getManga.subscribe(mangaId)
.collect { _mangaFlow.value = it }
}
}

View File

@ -13,7 +13,7 @@ import eu.kanade.domain.chapter.model.toDbChapter
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.GetMangaById
import eu.kanade.domain.manga.interactor.GetManga
import eu.kanade.domain.manga.model.isLocal
import eu.kanade.domain.manga.model.toDbManga
import eu.kanade.domain.track.interactor.GetTracks
@ -91,7 +91,7 @@ class ReaderPresenter(
private val downloadManager: DownloadManager = Injekt.get(),
private val preferences: PreferencesHelper = Injekt.get(),
private val delayedTrackingStore: DelayedTrackingStore = Injekt.get(),
private val getMangaById: GetMangaById = Injekt.get(),
private val getManga: GetManga = Injekt.get(),
private val getChapterByMangaId: GetChapterByMangaId = Injekt.get(),
private val getTracks: GetTracks = Injekt.get(),
private val insertTrack: InsertTrack = Injekt.get(),
@ -282,7 +282,7 @@ class ReaderPresenter(
launchIO {
try {
// SY -->
val manga = getMangaById.await(mangaId) ?: return@launchIO
val manga = getManga.await(mangaId) ?: return@launchIO
val source = sourceManager.get(manga.source)?.getMainSource<MetadataSource<*, *>>()
val metadata = if (source != null) {
getFlatMetadataById.await(mangaId)?.raise(source.metaClass)

View File

@ -14,10 +14,13 @@ import androidx.core.net.toUri
import androidx.core.text.HtmlCompat
import androidx.preference.PreferenceScreen
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import eu.kanade.domain.chapter.interactor.GetChapterByMangaId
import eu.kanade.domain.chapter.model.toDbChapter
import eu.kanade.domain.manga.interactor.GetAllManga
import eu.kanade.domain.manga.model.toDbManga
import eu.kanade.domain.manga.repository.MangaRepository
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.cache.ChapterCache
import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.download.DownloadManager
import eu.kanade.tachiyomi.data.library.LibraryUpdateService
import eu.kanade.tachiyomi.data.library.LibraryUpdateService.Target
@ -82,7 +85,8 @@ class SettingsAdvancedController(
private val network: NetworkHelper by injectLazy()
private val chapterCache: ChapterCache by injectLazy()
private val trackManager: TrackManager by injectLazy()
private val db: DatabaseHelper by injectLazy()
private val getAllManga: GetAllManga by injectLazy()
private val getChapterByMangaId: GetChapterByMangaId by injectLazy()
@SuppressLint("BatteryLife")
override fun setupPreferenceScreen(screen: PreferenceScreen) = screen.apply {
@ -475,7 +479,7 @@ class SettingsAdvancedController(
if (job?.isActive == true) return
activity?.toast(R.string.starting_cleanup)
job = launchIO {
val mangaList = db.getMangas().executeAsBlocking()
val mangaList = getAllManga.await()
val downloadManager: DownloadManager = Injekt.get()
var foldersCleared = 0
Injekt.get<SourceManager>().getOnlineSources().forEach { source ->
@ -483,7 +487,7 @@ class SettingsAdvancedController(
val sourceManga = mangaList
.asSequence()
.filter { it.source == source.id }
.map { it to DiskUtil.buildValidFilename(it.originalTitle) }
.map { it to DiskUtil.buildValidFilename(it.ogTitle) }
.toList()
mangaFolders.forEach mangaFolder@{ mangaFolder ->
@ -493,8 +497,8 @@ class SettingsAdvancedController(
foldersCleared += 1 + (mangaFolder.listFiles().orEmpty().size)
mangaFolder.delete()
} else {
val chapterList = db.getChapters(manga).executeAsBlocking()
foldersCleared += downloadManager.cleanupChapters(chapterList, manga, source, removeRead, removeNonFavorite)
val chapterList = getChapterByMangaId.await(manga.id)
foldersCleared += downloadManager.cleanupChapters(chapterList.map { it.toDbChapter() }, manga.toDbManga(), source, removeRead, removeNonFavorite)
}
}
}

View File

@ -14,15 +14,19 @@ import androidx.core.widget.doAfterTextChanged
import androidx.preference.PreferenceScreen
import com.fredporciuncula.flow.preferences.Preference
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import eu.kanade.data.DatabaseHandler
import eu.kanade.data.manga.mangaMapper
import eu.kanade.domain.manga.interactor.DeleteFavoriteEntries
import eu.kanade.domain.manga.interactor.GetFlatMetadataById
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.preference.DEVICE_CHARGING
import eu.kanade.tachiyomi.data.preference.DEVICE_ONLY_ON_WIFI
import eu.kanade.tachiyomi.databinding.DialogStubTextinputBinding
import eu.kanade.tachiyomi.ui.setting.eh.FrontPageCategoriesDialog
import eu.kanade.tachiyomi.ui.setting.eh.LanguagesDialog
import eu.kanade.tachiyomi.ui.webview.WebViewActivity
import eu.kanade.tachiyomi.util.lang.launchIO
import eu.kanade.tachiyomi.util.lang.withUIContext
import eu.kanade.tachiyomi.util.preference.bindTo
import eu.kanade.tachiyomi.util.preference.entriesRes
import eu.kanade.tachiyomi.util.preference.intListPreference
@ -42,11 +46,10 @@ import exh.eh.EHentaiUpdaterStats
import exh.favorites.FavoritesIntroDialog
import exh.log.xLogD
import exh.metadata.metadata.EHentaiSearchMetadata
import exh.metadata.metadata.base.getFlatMetadataForManga
import exh.source.isEhBasedManga
import exh.source.EH_SOURCE_ID
import exh.source.EXH_SOURCE_ID
import exh.uconfig.WarnConfigureDialogController
import exh.ui.login.EhLoginActivity
import exh.util.executeOnIO
import exh.util.nullIfBlank
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.launchIn
@ -69,7 +72,9 @@ import kotlin.time.Duration.Companion.seconds
*/
class SettingsEhController : SettingsController() {
private val db: DatabaseHelper by injectLazy()
private val handler: DatabaseHandler by injectLazy()
private val getFlatMetadataById: GetFlatMetadataById by injectLazy()
private val deleteFavoriteEntries: DeleteFavoriteEntries by injectLazy()
fun Preference<*>.reconfigure(): Boolean {
// Listen for change commit
@ -360,10 +365,12 @@ class SettingsEhController : SettingsController() {
.setTitle(R.string.favorites_sync_reset)
.setMessage(R.string.favorites_sync_reset_message)
.setPositiveButton(android.R.string.ok) { _, _ ->
db.inTransaction {
db.deleteAllFavoriteEntries().executeAsBlocking()
launchIO {
deleteFavoriteEntries.await()
withUIContext {
activity.toast(context.getString(R.string.sync_state_reset), Toast.LENGTH_LONG)
}
}
activity.toast(context.getString(R.string.sync_state_reset), Toast.LENGTH_LONG)
}
.setNegativeButton(android.R.string.cancel, null)
.setCancelable(false)
@ -468,12 +475,12 @@ class SettingsEhController : SettingsController() {
context.getString(R.string.gallery_updater_stats_text, getRelativeTimeString(getRelativeTimeFromNow(stats.startTime.milliseconds), context), stats.updateCount, stats.possibleUpdates)
} else context.getString(R.string.gallery_updater_not_ran_yet)
val allMeta = db.getFavoriteMangaWithMetadata().executeOnIO()
.filter(Manga::isEhBasedManga)
val allMeta = handler
.awaitList { mangasQueries.getEhMangaWithMetadata(EH_SOURCE_ID, EXH_SOURCE_ID, mangaMapper) }
.mapNotNull {
db.getFlatMetadataForManga(it.id!!).executeOnIO()
getFlatMetadataById.await(it.id)
?.raise<EHentaiSearchMetadata>()
}.toList()
}
fun metaInRelativeDuration(duration: Duration): Int {
val durationMs = duration.inWholeMilliseconds

View File

@ -5,19 +5,18 @@ package exh
import android.content.Context
import androidx.core.content.edit
import androidx.preference.PreferenceManager
import com.pushtorefresh.storio.sqlite.queries.DeleteQuery
import com.pushtorefresh.storio.sqlite.queries.Query
import com.pushtorefresh.storio.sqlite.queries.RawQuery
import eu.kanade.data.DatabaseHandler
import eu.kanade.domain.manga.interactor.GetManga
import eu.kanade.domain.manga.interactor.GetMangaBySource
import eu.kanade.domain.manga.interactor.UpdateManga
import eu.kanade.domain.manga.model.MangaUpdate
import eu.kanade.tachiyomi.BuildConfig
import eu.kanade.tachiyomi.data.backup.BackupCreatorJob
import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.Chapter
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.database.resolvers.MangaUrlPutResolver
import eu.kanade.tachiyomi.data.database.tables.ChapterTable
import eu.kanade.tachiyomi.data.database.tables.MangaTable
import eu.kanade.tachiyomi.data.database.tables.TrackTable
import eu.kanade.tachiyomi.data.library.LibraryUpdateJob
import eu.kanade.tachiyomi.data.preference.MANGA_NON_COMPLETED
import eu.kanade.tachiyomi.data.preference.PreferenceKeys
@ -29,7 +28,6 @@ import eu.kanade.tachiyomi.extension.ExtensionUpdateJob
import eu.kanade.tachiyomi.network.PREF_DOH_CLOUDFLARE
import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.all.Hitomi
import eu.kanade.tachiyomi.source.online.all.NHentai
import eu.kanade.tachiyomi.ui.library.LibrarySort
@ -68,11 +66,15 @@ import uy.kohesive.injekt.injectLazy
import java.io.File
import java.net.URI
import java.net.URISyntaxException
import eu.kanade.domain.manga.model.Manga as DomainManga
object EXHMigrations {
private val db: DatabaseHelper by injectLazy()
private val database: DatabaseHandler by injectLazy()
private val handler: DatabaseHandler by injectLazy()
private val sourceManager: SourceManager by injectLazy()
private val getManga: GetManga by injectLazy()
private val getMangaBySource: GetMangaBySource by injectLazy()
private val updateManga: UpdateManga by injectLazy()
/**
* Performs a migration when the application is updated.
@ -102,68 +104,41 @@ object EXHMigrations {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
if (oldVersion under 4) {
db.inTransaction {
updateSourceId(HBROWSE_SOURCE_ID, 6912)
// Migrate BHrowse URLs
val hBrowseManga = db.db.get()
.listOfObjects(Manga::class.java)
.withQuery(
Query.builder()
.table(MangaTable.TABLE)
.where("${MangaTable.COL_SOURCE} = $HBROWSE_SOURCE_ID")
.build(),
)
.prepare()
.executeAsBlocking()
hBrowseManga.forEach {
it.url = it.url + "/c00001/"
}
updateSourceId(HBROWSE_SOURCE_ID, 6912)
// Migrate BHrowse URLs
val hBrowseManga = runBlocking { getMangaBySource.await(HBROWSE_SOURCE_ID) }
val mangaUpdates = hBrowseManga.map {
MangaUpdate(it.id, url = it.url + "/c00001/")
}
db.db.put()
.objects(hBrowseManga)
// Extremely slow without the resolver :/
.withPutResolver(MangaUrlPutResolver())
.prepare()
.executeAsBlocking()
runBlocking {
updateManga.awaitAll(mangaUpdates)
}
}
if (oldVersion under 5) {
db.inTransaction {
// Migrate Hitomi source IDs
updateSourceId(Hitomi.otherId, 6910)
}
// Migrate Hitomi source IDs
updateSourceId(Hitomi.otherId, 6910)
}
if (oldVersion under 6) {
db.inTransaction {
updateSourceId(PERV_EDEN_EN_SOURCE_ID, 6905)
updateSourceId(PERV_EDEN_IT_SOURCE_ID, 6906)
updateSourceId(NHentai.otherId, 6907)
}
updateSourceId(PERV_EDEN_EN_SOURCE_ID, 6905)
updateSourceId(PERV_EDEN_IT_SOURCE_ID, 6906)
updateSourceId(NHentai.otherId, 6907)
}
if (oldVersion under 7) {
db.inTransaction {
val mergedMangas = db.db.get()
.listOfObjects(Manga::class.java)
.withQuery(
Query.builder()
.table(MangaTable.TABLE)
.where("${MangaTable.COL_SOURCE} = $MERGED_SOURCE_ID")
.build(),
)
.prepare()
.executeAsBlocking()
val mergedMangas = runBlocking { getMangaBySource.await(MERGED_SOURCE_ID) }
if (mergedMangas.isNotEmpty()) {
val mangaConfigs = mergedMangas.mapNotNull { mergedManga -> readMangaConfig(mergedManga)?.let { mergedManga to it } }
if (mangaConfigs.isNotEmpty()) {
val mangaToUpdate = mutableListOf<Manga>()
val mangaToUpdate = mutableListOf<MangaUpdate>()
val mergedMangaReferences = mutableListOf<MergedMangaReference>()
mangaConfigs.onEach { mergedManga ->
mergedManga.second.children.firstOrNull()?.url?.let {
if (db.getManga(it, MERGED_SOURCE_ID).executeAsBlocking() != null) return@onEach
mergedManga.first.url = it
}
mangaToUpdate += mergedManga.first
val newFirst = mergedManga.second.children.firstOrNull()?.url?.let {
if (runBlocking { getManga.await(it, MERGED_SOURCE_ID) } != null) return@onEach
mangaToUpdate += MangaUpdate(id = mergedManga.first.id, url = it)
mergedManga.first.copy(url = it)
} ?: mergedManga.first
mergedMangaReferences += MergedMangaReference(
id = null,
isInfoManga = false,
@ -171,9 +146,9 @@ object EXHMigrations {
chapterSortMode = 0,
chapterPriority = 0,
downloadChapters = false,
mergeId = mergedManga.first.id!!,
mergeId = mergedManga.first.id,
mergeUrl = mergedManga.first.url,
mangaId = mergedManga.first.id!!,
mangaId = mergedManga.first.id,
mangaUrl = mergedManga.first.url,
mangaSourceId = MERGED_SOURCE_ID,
)
@ -186,7 +161,7 @@ object EXHMigrations {
chapterSortMode = 0,
chapterPriority = 0,
downloadChapters = true,
mergeId = mergedManga.first.id!!,
mergeId = mergedManga.first.id,
mergeUrl = mergedManga.first.url,
mangaId = load.manga.id!!,
mangaUrl = load.manga.url,
@ -194,12 +169,9 @@ object EXHMigrations {
)
}
}
db.db.put()
.objects(mangaToUpdate)
// Extremely slow without the resolver :/
.withPutResolver(MangaUrlPutResolver())
.prepare()
.executeAsBlocking()
runBlocking {
updateManga.awaitAll(mangaToUpdate)
}
db.insertMergedMangas(mergedMangaReferences).executeAsBlocking()
val loadedMangaList = mangaConfigs.map { it.second.children }.flatten().mapNotNull { it.load(db, sourceManager) }.distinct()
@ -208,7 +180,7 @@ object EXHMigrations {
.withQuery(
Query.builder()
.table(ChapterTable.TABLE)
.where("${ChapterTable.COL_MANGA_ID} IN (${mergedMangas.filter { it.id != null }.joinToString { it.id.toString() }})")
.where("${ChapterTable.COL_MANGA_ID} IN (${mergedMangas.joinToString { it.id.toString() }})")
.build(),
)
.prepare()
@ -289,13 +261,9 @@ object EXHMigrations {
}
// Delete old mangadex trackers
db.db.lowLevel().delete(
DeleteQuery.builder()
.table(TrackTable.TABLE)
.where("${TrackTable.COL_SYNC_ID} = ?")
.whereArgs(6)
.build(),
)
runBlocking {
handler.await { ehQueries.deleteBySyncId(6) }
}
}
if (oldVersion under 18) {
val readerTheme = preferences.readerTheme().get()
@ -407,7 +375,7 @@ object EXHMigrations {
}
if (oldVersion under 31) {
runBlocking {
database.await(true) {
handler.await(true) {
prefs.getStringSet("eh_saved_searches", emptySet())?.forEach {
kotlin.runCatching {
val content = Json.decodeFromString<JsonObject>(it.substringAfter(':'))
@ -421,7 +389,7 @@ object EXHMigrations {
}
}
}
database.await(true) {
handler.await(true) {
prefs.getStringSet("latest_tab_sources", emptySet())?.forEach {
feed_saved_searchQueries.insertFeedSavedSearch(
_id = null,
@ -557,7 +525,7 @@ object EXHMigrations {
}
}
private fun readMangaConfig(manga: SManga): MangaConfig? {
private fun readMangaConfig(manga: DomainManga): MangaConfig? {
return MangaConfig.readFromUrl(manga.url)
}
@ -586,17 +554,8 @@ object EXHMigrations {
private data class LoadedMangaSource(val source: Source, val manga: Manga)
private fun updateSourceId(newId: Long, oldId: Long) {
db.lowLevel().executeSQL(
RawQuery.builder()
.query(
"""
UPDATE ${MangaTable.TABLE}
SET ${MangaTable.COL_SOURCE} = $newId
WHERE ${MangaTable.COL_SOURCE} = $oldId
""".trimIndent(),
)
.affectsTables(MangaTable.TABLE)
.build(),
)
runBlocking {
handler.await { ehQueries.migrateSource(newId, oldId) }
}
}
}

View File

@ -7,8 +7,7 @@ import eu.kanade.data.chapter.chapterMapper
import eu.kanade.data.manga.mangaMapper
import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource
import eu.kanade.domain.chapter.model.Chapter
import eu.kanade.domain.manga.interactor.GetMangaById
import eu.kanade.domain.manga.interactor.GetMangaByUrlAndSource
import eu.kanade.domain.manga.interactor.GetManga
import eu.kanade.domain.manga.interactor.UpdateManga
import eu.kanade.domain.manga.model.Manga
import eu.kanade.domain.manga.model.toMangaInfo
@ -25,8 +24,7 @@ import uy.kohesive.injekt.api.get
class GalleryAdder(
private val handler: DatabaseHandler = Injekt.get(),
private val getMangaByUrlAndSource: GetMangaByUrlAndSource = Injekt.get(),
private val getMangaById: GetMangaById = Injekt.get(),
private val getManga: GetManga = Injekt.get(),
private val updateManga: UpdateManga = Injekt.get(),
private val syncChaptersWithSource: SyncChaptersWithSource = Injekt.get(),
private val sourceManager: SourceManager = Injekt.get(),
@ -120,7 +118,7 @@ class GalleryAdder(
} ?: return GalleryAddEvent.Fail.UnknownType(url, context)
// Use manga in DB if possible, otherwise, make a new manga
var manga = getMangaByUrlAndSource.await(cleanedMangaUrl, source.id)
var manga = getManga.await(cleanedMangaUrl, source.id)
?: handler.awaitOne(true) {
// Insert created manga if not in DB before fetching details
// This allows us to keep the metadata when fetching details
@ -135,7 +133,7 @@ class GalleryAdder(
// Fetch and copy details
val newManga = source.getMangaDetails(manga.toMangaInfo())
updateManga.awaitUpdateFromSource(manga, newManga, false, Injekt.get())
manga = getMangaById.await(manga.id)!!
manga = getManga.await(manga.id)!!
if (fav) {
updateManga.awaitUpdateFavorite(manga.id, true)

View File

@ -2,13 +2,16 @@ package exh.debug
import android.app.Application
import androidx.work.WorkManager
import com.pushtorefresh.storio.sqlite.queries.RawQuery
import eu.kanade.data.AndroidDatabaseHandler
import eu.kanade.data.DatabaseHandler
import eu.kanade.data.manga.mangaMapper
import eu.kanade.domain.manga.interactor.GetAllManga
import eu.kanade.domain.manga.interactor.GetExhFavoriteMangaWithMetadata
import eu.kanade.domain.manga.interactor.GetFavorites
import eu.kanade.domain.manga.interactor.GetFlatMetadataById
import eu.kanade.domain.manga.interactor.GetSearchMetadata
import eu.kanade.domain.manga.interactor.InsertFlatMetadata
import eu.kanade.domain.manga.interactor.UpdateManga
import eu.kanade.domain.manga.model.toMangaInfo
import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.tables.MangaTable
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.source.SourceManager
@ -17,18 +20,10 @@ import exh.EXHMigrations
import exh.eh.EHentaiThrottleManager
import exh.eh.EHentaiUpdateWorker
import exh.metadata.metadata.EHentaiSearchMetadata
import exh.metadata.metadata.base.awaitFlatMetadataForManga
import exh.metadata.metadata.base.awaitInsertFlatMetadata
import exh.source.EH_SOURCE_ID
import exh.source.EXH_SOURCE_ID
import exh.source.isEhBasedManga
import exh.source.nHentaiSourceIds
import exh.util.cancellable
import exh.util.executeOnIO
import exh.util.jobScheduler
import kotlinx.coroutines.flow.asFlow
import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.runBlocking
import uy.kohesive.injekt.injectLazy
import java.util.UUID
@ -36,12 +31,16 @@ import java.util.UUID
@Suppress("unused")
object DebugFunctions {
val app: Application by injectLazy()
val db: DatabaseHelper by injectLazy()
val handler: DatabaseHandler by injectLazy()
val prefs: PreferencesHelper by injectLazy()
val sourceManager: SourceManager by injectLazy()
val updateManga: UpdateManga by injectLazy()
val getFavorites: GetFavorites by injectLazy()
val getFlatMetadataById: GetFlatMetadataById by injectLazy()
val insertFlatMetadata: InsertFlatMetadata by injectLazy()
val getExhFavoriteMangaWithMetadata: GetExhFavoriteMangaWithMetadata by injectLazy()
val getSearchMetadata: GetSearchMetadata by injectLazy()
val getAllManga: GetAllManga by injectLazy()
fun forceUpgradeMigration() {
prefs.ehLastVersionCode().set(1)
@ -55,18 +54,11 @@ object DebugFunctions {
fun resetAgedFlagInEXHManga() {
runBlocking {
val metadataManga = db.getFavoriteMangaWithMetadata().executeOnIO()
val allManga = metadataManga.asFlow().cancellable().mapNotNull { manga ->
if (manga.isEhBasedManga()) manga
else null
}.toList()
allManga.forEach { manga ->
val meta = handler.awaitFlatMetadataForManga(manga.id!!)?.raise<EHentaiSearchMetadata>() ?: return@forEach
getExhFavoriteMangaWithMetadata.await().forEach { manga ->
val meta = getFlatMetadataById.await(manga.id)?.raise<EHentaiSearchMetadata>() ?: return@forEach
// remove age flag
meta.aged = false
handler.awaitInsertFlatMetadata(meta.flatten())
insertFlatMetadata.await(meta)
}
}
}
@ -77,8 +69,7 @@ object DebugFunctions {
fun resetEHGalleriesForUpdater() {
throttleManager.resetThrottle()
runBlocking {
val allManga = handler
.awaitList { mangasQueries.getEhMangaWithMetadata(EH_SOURCE_ID, EXH_SOURCE_ID, mangaMapper) }
val allManga = getExhFavoriteMangaWithMetadata.await()
val eh = sourceManager.get(EH_SOURCE_ID)
val ex = sourceManager.get(EXH_SOURCE_ID)
@ -99,11 +90,8 @@ object DebugFunctions {
fun getEHMangaListWithAgedFlagInfo(): String {
return runBlocking {
val allManga = handler
.awaitList { mangasQueries.getEhMangaWithMetadata(EH_SOURCE_ID, EXH_SOURCE_ID, mangaMapper) }
allManga.map { manga ->
val meta = handler.awaitFlatMetadataForManga(manga.id)?.raise<EHentaiSearchMetadata>() ?: return@map
getExhFavoriteMangaWithMetadata.await().map { manga ->
val meta = getFlatMetadataById.await(manga.id)?.raise<EHentaiSearchMetadata>() ?: return@map
"Aged: ${meta.aged}\t Title: ${manga.title}"
}
}.joinToString(",\n")
@ -111,10 +99,9 @@ object DebugFunctions {
fun countAgedFlagInEXHManga(): Int {
return runBlocking {
handler
.awaitList { mangasQueries.getEhMangaWithMetadata(EH_SOURCE_ID, EXH_SOURCE_ID, mangaMapper) }
getExhFavoriteMangaWithMetadata.await()
.count { manga ->
val meta = handler.awaitFlatMetadataForManga(manga.id)
val meta = getFlatMetadataById.await(manga.id)
?.raise<EHentaiSearchMetadata>()
?: return@count false
meta.aged
@ -123,31 +110,30 @@ object DebugFunctions {
}
fun addAllMangaInDatabaseToLibrary() {
db.inTransaction {
db.lowLevel().executeSQL(
RawQuery.builder()
.query(
"""
UPDATE ${MangaTable.TABLE}
SET ${MangaTable.COL_FAVORITE} = 1
""".trimIndent(),
)
.affectsTables(MangaTable.TABLE)
.build(),
(handler as AndroidDatabaseHandler).rawQuery {
it.execute(
null,
"""
UPDATE ${MangaTable.TABLE}
SET ${MangaTable.COL_FAVORITE} = 1
""".trimIndent(),
0,
)
}
}
fun countMangaInDatabaseInLibrary() = runBlocking { getFavorites.await().size }
fun countMangaInDatabaseNotInLibrary() = db.getMangas().executeAsBlocking().count { !it.favorite }
fun countMangaInDatabaseNotInLibrary() = runBlocking { getAllManga.await() }.count { !it.favorite }
fun countMangaInDatabase() = db.getMangas().executeAsBlocking().size
fun countMangaInDatabase() = runBlocking { getAllManga.await() }.size
fun countMetadataInDatabase() = db.getSearchMetadata().executeAsBlocking().size
fun countMetadataInDatabase() = runBlocking { getSearchMetadata.await().size }
fun countMangaInLibraryWithMissingMetadata() = db.getMangas().executeAsBlocking().count {
it.favorite && db.getSearchMetadataForManga(it.id!!).executeAsBlocking() == null
fun countMangaInLibraryWithMissingMetadata() = runBlocking {
runBlocking { getAllManga.await() }.count {
it.favorite && getSearchMetadata.await(it.id) == null
}
}
fun clearSavedSearches() = runBlocking { handler.await { saved_searchQueries.deleteAll() } }
@ -214,18 +200,17 @@ object DebugFunctions {
fun cancelAllScheduledJobs() = app.jobScheduler.cancelAll()
private fun convertSources(from: Long, to: Long) {
db.lowLevel().executeSQL(
RawQuery.builder()
.query(
"""
UPDATE ${MangaTable.TABLE}
SET ${MangaTable.COL_SOURCE} = $to
WHERE ${MangaTable.COL_SOURCE} = $from
""".trimIndent(),
)
.affectsTables(MangaTable.TABLE)
.build(),
)
(handler as AndroidDatabaseHandler).rawQuery {
it.execute(
null,
"""
UPDATE ${MangaTable.TABLE}
SET ${MangaTable.COL_SOURCE} = $to
WHERE ${MangaTable.COL_SOURCE} = $from
""".trimIndent(),
0,
)
}
}
/*fun copyEHentaiSavedSearchesToExhentai() {
@ -307,34 +292,28 @@ object DebugFunctions {
}*/
fun fixReaderViewerBackupBug() {
db.inTransaction {
db.lowLevel().executeSQL(
RawQuery.builder()
.query(
"""
UPDATE ${MangaTable.TABLE}
SET ${MangaTable.COL_VIEWER} = 0
WHERE ${MangaTable.COL_VIEWER} = -1
""".trimIndent(),
)
.affectsTables(MangaTable.TABLE)
.build(),
(handler as AndroidDatabaseHandler).rawQuery {
it.execute(
null,
"""
UPDATE ${MangaTable.TABLE}
SET ${MangaTable.COL_VIEWER} = 0
WHERE ${MangaTable.COL_VIEWER} = -1
""".trimIndent(),
0,
)
}
}
fun resetReaderViewerForAllManga() {
db.inTransaction {
db.lowLevel().executeSQL(
RawQuery.builder()
.query(
"""
UPDATE ${MangaTable.TABLE}
SET ${MangaTable.COL_VIEWER} = 0
""".trimIndent(),
)
.affectsTables(MangaTable.TABLE)
.build(),
(handler as AndroidDatabaseHandler).rawQuery {
it.execute(
null,
"""
UPDATE ${MangaTable.TABLE}
SET ${MangaTable.COL_VIEWER} = 0
""".trimIndent(),
0,
)
}
}
@ -344,34 +323,28 @@ object DebugFunctions {
.also { it.remove(NHentai.otherId) }
.joinToString(separator = ",")
db.inTransaction {
db.lowLevel().executeSQL(
RawQuery.builder()
.query(
"""
UPDATE ${MangaTable.TABLE}
SET ${MangaTable.COL_SOURCE} = ${NHentai.otherId}
WHERE ${MangaTable.COL_FAVORITE} = 1 AND ${MangaTable.COL_SOURCE} in ($sources)
""".trimIndent(),
)
.affectsTables(MangaTable.TABLE)
.build(),
(handler as AndroidDatabaseHandler).rawQuery {
it.execute(
null,
"""
UPDATE ${MangaTable.TABLE}
SET ${MangaTable.COL_SOURCE} = ${NHentai.otherId}
WHERE ${MangaTable.COL_FAVORITE} = 1 AND ${MangaTable.COL_SOURCE} in ($sources)
""".trimIndent(),
0,
)
}
}
fun resetFilteredScanlatorsForAllManga() {
db.inTransaction {
db.lowLevel().executeSQL(
RawQuery.builder()
.query(
"""
UPDATE ${MangaTable.TABLE}
SET ${MangaTable.COL_FILTERED_SCANLATORS} = NULL
""".trimIndent(),
)
.affectsTables(MangaTable.TABLE)
.build(),
(handler as AndroidDatabaseHandler).rawQuery {
it.execute(
null,
"""
UPDATE ${MangaTable.TABLE}
SET ${MangaTable.COL_FILTERED_SCANLATORS} = NULL
""".trimIndent(),
0,
)
}
}

View File

@ -14,7 +14,7 @@ import eu.kanade.domain.history.interactor.RemoveHistoryById
import eu.kanade.domain.history.interactor.UpsertHistory
import eu.kanade.domain.history.model.History
import eu.kanade.domain.history.model.HistoryUpdate
import eu.kanade.domain.manga.interactor.GetMangaById
import eu.kanade.domain.manga.interactor.GetManga
import eu.kanade.domain.manga.interactor.UpdateManga
import eu.kanade.domain.manga.model.Manga
import eu.kanade.domain.manga.model.MangaUpdate
@ -37,7 +37,7 @@ class EHentaiUpdateHelper(context: Context) {
)
private val handler: DatabaseHandler by injectLazy()
private val getChapterByMangaId: GetChapterByMangaId by injectLazy()
private val getMangaById: GetMangaById by injectLazy()
private val getManga: GetManga by injectLazy()
private val updateManga: UpdateManga by injectLazy()
private val setMangaCategories: SetMangaCategories by injectLazy()
private val getCategories: GetCategories by injectLazy()
@ -64,7 +64,7 @@ class EHentaiUpdateHelper(context: Context) {
.mapNotNull { mangaId ->
coroutineScope {
val manga = async(Dispatchers.IO) {
getMangaById.await(mangaId)
getManga.await(mangaId)
}
val chapterList = async(Dispatchers.IO) {
getChapterByMangaId.await(mangaId)

View File

@ -21,7 +21,6 @@ import eu.kanade.domain.manga.interactor.UpdateManga
import eu.kanade.domain.manga.model.Manga
import eu.kanade.domain.manga.model.toDbManga
import eu.kanade.domain.manga.model.toMangaInfo
import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.library.LibraryUpdateNotifier
import eu.kanade.tachiyomi.data.preference.DEVICE_CHARGING
import eu.kanade.tachiyomi.data.preference.DEVICE_ONLY_ON_WIFI
@ -35,7 +34,7 @@ import exh.eh.EHentaiUpdateWorkerConstants.UPDATES_PER_ITERATION
import exh.log.xLog
import exh.metadata.metadata.EHentaiSearchMetadata
import exh.metadata.metadata.base.awaitFlatMetadataForManga
import exh.metadata.metadata.base.insertFlatMetadataAsync
import exh.metadata.metadata.base.awaitInsertFlatMetadata
import exh.source.EH_SOURCE_ID
import exh.source.EXH_SOURCE_ID
import exh.source.isEhBasedManga
@ -54,7 +53,6 @@ import kotlin.time.Duration.Companion.days
class EHentaiUpdateWorker(private val context: Context, workerParams: WorkerParameters) :
CoroutineWorker(context, workerParams) {
private val db: DatabaseHelper by injectLazy()
private val handler: DatabaseHandler by injectLazy()
private val prefs: PreferencesHelper by injectLazy()
private val sourceManager: SourceManager by injectLazy()
@ -228,7 +226,7 @@ class EHentaiUpdateWorker(private val context: Context, workerParams: WorkerPara
// Age dead galleries
logger.d("Aged %s - notfound", manga.id)
meta.aged = true
db.insertFlatMetadataAsync(meta.flatten()).await()
handler.awaitInsertFlatMetadata(meta.flatten())
}
throw GalleryNotUpdatedException(false, t)
}

View File

@ -8,7 +8,7 @@ import eu.kanade.data.DatabaseHandler
import eu.kanade.domain.category.interactor.GetCategories
import eu.kanade.domain.category.interactor.SetMangaCategories
import eu.kanade.domain.category.model.Category
import eu.kanade.domain.manga.interactor.GetMangaByUrlAndSource
import eu.kanade.domain.manga.interactor.GetManga
import eu.kanade.domain.manga.interactor.UpdateManga
import eu.kanade.domain.manga.model.Manga
import eu.kanade.tachiyomi.R
@ -50,7 +50,7 @@ import kotlin.time.Duration.Companion.seconds
class FavoritesSyncHelper(val context: Context) {
private val handler: DatabaseHandler by injectLazy()
private val getCategories: GetCategories by injectLazy()
private val getMangaByUrlAndSource: GetMangaByUrlAndSource by injectLazy()
private val getManga: GetManga by injectLazy()
private val updateManga: UpdateManga by injectLazy()
private val setMangaCategories: SetMangaCategories by injectLazy()
@ -332,7 +332,7 @@ class FavoritesSyncHelper(val context: Context) {
EXH_SOURCE_ID,
EH_SOURCE_ID,
).forEach {
val manga = getMangaByUrlAndSource.await(url, it)
val manga = getManga.await(url, it)
if (manga?.favorite == true) {
updateManga.awaitUpdateFavorite(manga.id, false)

View File

@ -1,9 +1,10 @@
package exh.favorites
import eu.kanade.data.DatabaseHandler
import eu.kanade.data.exh.favoriteEntryMapper
import eu.kanade.domain.category.interactor.GetCategories
import eu.kanade.domain.manga.interactor.DeleteFavoriteEntries
import eu.kanade.domain.manga.interactor.GetFavoriteEntries
import eu.kanade.domain.manga.interactor.GetFavorites
import eu.kanade.domain.manga.interactor.InsertFavoriteEntries
import eu.kanade.domain.manga.model.Manga
import eu.kanade.tachiyomi.data.database.models.toDomainManga
import eu.kanade.tachiyomi.source.online.all.EHentai
@ -19,9 +20,11 @@ import kotlinx.coroutines.flow.toList
import uy.kohesive.injekt.injectLazy
class LocalFavoritesStorage {
private val handler: DatabaseHandler by injectLazy()
private val getFavorites: GetFavorites by injectLazy()
private val getCategories: GetCategories by injectLazy()
private val deleteFavoriteEntries: DeleteFavoriteEntries by injectLazy()
private val getFavoriteEntries: GetFavoriteEntries by injectLazy()
private val insertFavoriteEntries: InsertFavoriteEntries by injectLazy()
suspend fun getChangedDbEntries() = getFavorites.await()
.asFlow()
@ -48,30 +51,20 @@ class LocalFavoritesStorage {
.parseToFavoriteEntries()
// Delete old snapshot
handler.await { eh_favoritesQueries.deleteAll() }
deleteFavoriteEntries.await()
// Insert new snapshots
handler.await(true) {
dbMangas.toList().forEach {
eh_favoritesQueries.insertEhFavorites(
it.id,
it.title,
it.gid,
it.token,
it.category.toLong(),
)
}
}
insertFavoriteEntries.await(dbMangas.toList())
}
suspend fun clearSnapshots() {
handler.await { eh_favoritesQueries.deleteAll() }
deleteFavoriteEntries.await()
}
private suspend fun Flow<FavoriteEntry>.getChangedEntries(): ChangeSet {
val terminated = toList()
val databaseEntries = handler.awaitList { eh_favoritesQueries.selectAll(favoriteEntryMapper) }
val databaseEntries = getFavoriteEntries.await()
val added = terminated.filter {
queryListForEntry(databaseEntries, it) == null

View File

@ -1,65 +0,0 @@
package exh.favorites.sql.mappers
import android.database.Cursor
import androidx.core.content.contentValuesOf
import com.pushtorefresh.storio.sqlite.SQLiteTypeMapping
import com.pushtorefresh.storio.sqlite.operations.delete.DefaultDeleteResolver
import com.pushtorefresh.storio.sqlite.operations.get.DefaultGetResolver
import com.pushtorefresh.storio.sqlite.operations.put.DefaultPutResolver
import com.pushtorefresh.storio.sqlite.queries.DeleteQuery
import com.pushtorefresh.storio.sqlite.queries.InsertQuery
import com.pushtorefresh.storio.sqlite.queries.UpdateQuery
import exh.favorites.sql.models.FavoriteEntry
import exh.favorites.sql.tables.FavoriteEntryTable.COL_CATEGORY
import exh.favorites.sql.tables.FavoriteEntryTable.COL_GID
import exh.favorites.sql.tables.FavoriteEntryTable.COL_ID
import exh.favorites.sql.tables.FavoriteEntryTable.COL_TITLE
import exh.favorites.sql.tables.FavoriteEntryTable.COL_TOKEN
import exh.favorites.sql.tables.FavoriteEntryTable.TABLE
class FavoriteEntryTypeMapping : SQLiteTypeMapping<FavoriteEntry>(
FavoriteEntryPutResolver(),
FavoriteEntryGetResolver(),
FavoriteEntryDeleteResolver(),
)
class FavoriteEntryPutResolver : DefaultPutResolver<FavoriteEntry>() {
override fun mapToInsertQuery(obj: FavoriteEntry) = InsertQuery.builder()
.table(TABLE)
.build()
override fun mapToUpdateQuery(obj: FavoriteEntry) = UpdateQuery.builder()
.table(TABLE)
.where("$COL_ID = ?")
.whereArgs(obj.id)
.build()
override fun mapToContentValues(obj: FavoriteEntry) = contentValuesOf(
COL_ID to obj.id,
COL_TITLE to obj.title,
COL_GID to obj.gid,
COL_TOKEN to obj.token,
COL_CATEGORY to obj.category,
)
}
class FavoriteEntryGetResolver : DefaultGetResolver<FavoriteEntry>() {
override fun mapFromCursor(cursor: Cursor): FavoriteEntry = FavoriteEntry(
id = cursor.getLong(cursor.getColumnIndexOrThrow(COL_ID)),
title = cursor.getString(cursor.getColumnIndexOrThrow(COL_TITLE)),
gid = cursor.getString(cursor.getColumnIndexOrThrow(COL_GID)),
token = cursor.getString(cursor.getColumnIndexOrThrow(COL_TOKEN)),
category = cursor.getInt(cursor.getColumnIndexOrThrow(COL_CATEGORY)),
)
}
class FavoriteEntryDeleteResolver : DefaultDeleteResolver<FavoriteEntry>() {
override fun mapToDeleteQuery(obj: FavoriteEntry) = DeleteQuery.builder()
.table(TABLE)
.where("$COL_ID = ?")
.whereArgs(obj.id)
.build()
}

View File

@ -1,30 +0,0 @@
package exh.favorites.sql.queries
import com.pushtorefresh.storio.sqlite.queries.DeleteQuery
import com.pushtorefresh.storio.sqlite.queries.Query
import eu.kanade.tachiyomi.data.database.DbProvider
import exh.favorites.sql.models.FavoriteEntry
import exh.favorites.sql.tables.FavoriteEntryTable
interface FavoriteEntryQueries : DbProvider {
fun getFavoriteEntries() = db.get()
.listOfObjects(FavoriteEntry::class.java)
.withQuery(
Query.builder()
.table(FavoriteEntryTable.TABLE)
.build(),
)
.prepare()
fun insertFavoriteEntries(favoriteEntries: List<FavoriteEntry>) = db.put()
.objects(favoriteEntries)
.prepare()
fun deleteAllFavoriteEntries() = db.delete()
.byQuery(
DeleteQuery.builder()
.table(FavoriteEntryTable.TABLE)
.build(),
)
.prepare()
}

View File

@ -1,16 +0,0 @@
package exh.favorites.sql.tables
object FavoriteEntryTable {
const val TABLE = "eh_favorites"
const val COL_ID = "_id"
const val COL_TITLE = "title"
const val COL_GID = "gid"
const val COL_TOKEN = "token"
const val COL_CATEGORY = "category"
}

View File

@ -1,7 +1,8 @@
package exh.md.handlers
import eu.kanade.data.DatabaseHandler
import eu.kanade.domain.manga.interactor.GetMangaByUrlAndSource
import eu.kanade.domain.manga.interactor.GetFlatMetadataById
import eu.kanade.domain.manga.interactor.GetManga
import eu.kanade.domain.manga.interactor.InsertFlatMetadata
import eu.kanade.tachiyomi.source.model.SManga
import exh.log.xLogE
import exh.md.dto.ChapterDataDto
@ -13,8 +14,6 @@ import exh.md.utils.MdUtil
import exh.md.utils.asMdMap
import exh.metadata.metadata.MangaDexSearchMetadata
import exh.metadata.metadata.base.RaisedTag
import exh.metadata.metadata.base.awaitFlatMetadataForManga
import exh.metadata.metadata.base.awaitInsertFlatMetadata
import exh.util.capitalize
import exh.util.floor
import exh.util.nullIfEmpty
@ -26,8 +25,9 @@ import java.util.Locale
class ApiMangaParser(
private val lang: String,
) {
private val handler: DatabaseHandler by injectLazy()
private val getMangaByUrlAndSource: GetMangaByUrlAndSource by injectLazy()
private val getManga: GetManga by injectLazy()
private val insertFlatMetadata: InsertFlatMetadata by injectLazy()
private val getFlatMetadataById: GetFlatMetadataById by injectLazy()
val metaClass = MangaDexSearchMetadata::class
@ -46,16 +46,16 @@ class ApiMangaParser(
simpleChapters: List<String>,
statistics: StatisticsMangaDto?,
): MangaInfo {
val mangaId = getMangaByUrlAndSource.await(manga.key, sourceId)?.id
val mangaId = getManga.await(manga.key, sourceId)?.id
val metadata = if (mangaId != null) {
val flatMetadata = handler.awaitFlatMetadataForManga(mangaId)
val flatMetadata = getFlatMetadataById.await(mangaId)
flatMetadata?.raise(metaClass) ?: newMetaInstance()
} else newMetaInstance()
parseIntoMetadata(metadata, input, simpleChapters, statistics)
if (mangaId != null) {
metadata.mangaId = mangaId
handler.awaitInsertFlatMetadata(metadata.flatten())
insertFlatMetadata.await(metadata.flatten())
}
return metadata.createMangaInfo(manga)

View File

@ -1,6 +1,6 @@
package exh.md.similar
import eu.kanade.domain.manga.interactor.GetMangaById
import eu.kanade.domain.manga.interactor.GetManga
import eu.kanade.domain.manga.model.Manga
import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.online.all.MangaDex
@ -17,14 +17,14 @@ import uy.kohesive.injekt.api.get
class MangaDexSimilarPresenter(
val mangaId: Long,
sourceId: Long,
private val getMangaById: GetMangaById = Injekt.get(),
private val getManga: GetManga = Injekt.get(),
) : BrowseSourcePresenter(sourceId) {
var manga: Manga? = null
override fun createPager(query: String, filters: FilterList): Pager {
val sourceAsMangaDex = source.getMainSource() as MangaDex
this.manga = runBlocking { getMangaById.await(mangaId) }
this.manga = runBlocking { getManga.await(mangaId) }
return MangaDexSimilarPager(manga!!, sourceAsMangaDex)
}
}

View File

@ -4,15 +4,9 @@ import com.pushtorefresh.storio.sqlite.queries.DeleteQuery
import com.pushtorefresh.storio.sqlite.queries.Query
import com.pushtorefresh.storio.sqlite.queries.RawQuery
import eu.kanade.tachiyomi.data.database.DbProvider
import eu.kanade.tachiyomi.data.database.inTransaction
import eu.kanade.tachiyomi.data.database.models.Chapter
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.database.queries.getAllMergedMangaQuery
import eu.kanade.tachiyomi.data.database.queries.getMergedChaptersQuery
import eu.kanade.tachiyomi.data.database.queries.getMergedMangaForDownloadingQuery
import eu.kanade.tachiyomi.data.database.queries.getMergedMangaFromUrlQuery
import eu.kanade.tachiyomi.data.database.queries.getMergedMangaQuery
import eu.kanade.tachiyomi.data.database.tables.ChapterTable
import exh.merged.sql.models.MergedMangaReference
import exh.merged.sql.resolvers.MergeMangaSettingsPutResolver
import exh.merged.sql.resolvers.MergedMangaIdPutResolver
@ -31,17 +25,6 @@ interface MergedQueries : DbProvider {
)
.prepare()
fun getMergedMangaReferences(mergedMangaUrl: String) = db.get()
.listOfObjects(MergedMangaReference::class.java)
.withQuery(
Query.builder()
.table(MergedTable.TABLE)
.where("${MergedTable.COL_MERGE_URL} = ?")
.whereArgs(mergedMangaUrl)
.build(),
)
.prepare()
fun deleteMangaForMergedManga(mergedMangaId: Long) = db.delete()
.byQuery(
DeleteQuery.builder()
@ -72,56 +55,6 @@ interface MergedQueries : DbProvider {
)
.prepare()
fun getMergedMangas(mergedMangaUrl: String) = db.get()
.listOfObjects(Manga::class.java)
.withQuery(
RawQuery.builder()
.query(getMergedMangaFromUrlQuery())
.args(mergedMangaUrl)
.build(),
)
.prepare()
fun getMergedMangas() = db.get()
.listOfObjects(Manga::class.java)
.withQuery(
RawQuery.builder()
.query(getAllMergedMangaQuery())
.build(),
)
.prepare()
fun deleteMangaForMergedManga(mergedMangaUrl: String) = db.delete()
.byQuery(
DeleteQuery.builder()
.table(MergedTable.TABLE)
.where("${MergedTable.COL_MERGE_URL} = ?")
.whereArgs(mergedMangaUrl)
.build(),
)
.prepare()
fun getMergedMangaReferences() = db.get()
.listOfObjects(MergedMangaReference::class.java)
.withQuery(
Query.builder()
.table(MergedTable.TABLE)
.orderBy(MergedTable.COL_ID)
.build(),
)
.prepare()
fun getChaptersByMergedMangaId(mergedMangaId: Long) = db.get()
.listOfObjects(Chapter::class.java)
.withQuery(
RawQuery.builder()
.query(getMergedChaptersQuery())
.args(mergedMangaId)
.observesTables(ChapterTable.TABLE, MergedTable.TABLE)
.build(),
)
.prepare()
fun insertMergedManga(mergedManga: MergedMangaReference) = db.put().`object`(mergedManga).prepare()
fun insertNewMergedMangaId(mergedManga: MergedMangaReference) = db.put().`object`(mergedManga).withPutResolver(MergedMangaIdPutResolver()).prepare()
@ -133,20 +66,4 @@ interface MergedQueries : DbProvider {
fun updateMergeMangaSettings(mergeManga: MergedMangaReference) = db.put().`object`(mergeManga).withPutResolver(MergeMangaSettingsPutResolver()).prepare()
fun deleteMergedManga(mergedManga: MergedMangaReference) = db.delete().`object`(mergedManga).prepare()
fun deleteAllMergedManga() = db.delete().byQuery(
DeleteQuery.builder()
.table(MergedTable.TABLE)
.build(),
)
.prepare()
fun setMangasForMergedManga(mergedMangaId: Long, mergedMangas: List<MergedMangaReference>) {
db.inTransaction {
deleteMangaForMergedManga(mergedMangaId).executeAsBlocking()
mergedMangas.chunked(100) { chunk ->
insertMergedMangas(chunk).executeAsBlocking()
}
}
}
}

View File

@ -1,23 +1,15 @@
package exh.metadata.metadata.base
import com.pushtorefresh.storio.operations.PreparedOperation
import eu.kanade.data.AndroidDatabaseHandler
import eu.kanade.data.DatabaseHandler
import eu.kanade.data.exh.searchMetadataMapper
import eu.kanade.data.exh.searchTagMapper
import eu.kanade.data.exh.searchTitleMapper
import eu.kanade.tachiyomi.data.database.DatabaseHelper
import exh.metadata.sql.models.SearchMetadata
import exh.metadata.sql.models.SearchTag
import exh.metadata.sql.models.SearchTitle
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import kotlinx.serialization.InternalSerializationApi
import kotlinx.serialization.Serializable
import kotlinx.serialization.serializer
import rx.Completable
import rx.Single
import kotlin.reflect.KClass
@Serializable
@ -36,17 +28,7 @@ data class FlatMetadata(
}
}
fun DatabaseHandler.getFlatMetadataForManga(mangaId: Long): FlatMetadata? {
this as AndroidDatabaseHandler
val meta = db.search_metadataQueries.selectByMangaId(mangaId, searchMetadataMapper).executeAsOneOrNull()
return if (meta != null) {
val tags = db.search_tagsQueries.selectByMangaId(mangaId, searchTagMapper).executeAsList()
val titles = db.search_titlesQueries.selectByMangaId(mangaId, searchTitleMapper).executeAsList()
FlatMetadata(meta, tags, titles)
} else null
}
@Deprecated("Replace with GetFlatMetadataById")
suspend fun DatabaseHandler.awaitFlatMetadataForManga(mangaId: Long): FlatMetadata? {
return await {
val meta = search_metadataQueries.selectByMangaId(mangaId, searchMetadataMapper).executeAsOneOrNull()
@ -59,86 +41,7 @@ suspend fun DatabaseHandler.awaitFlatMetadataForManga(mangaId: Long): FlatMetada
}
}
fun DatabaseHelper.getFlatMetadataForManga(mangaId: Long): PreparedOperation<FlatMetadata?> {
// We have to use fromCallable because StorIO messes up the thread scheduling if we use their rx functions
val single = Single.fromCallable {
val meta = getSearchMetadataForManga(mangaId).executeAsBlocking()
if (meta != null) {
val tags = getSearchTagsForManga(mangaId).executeAsBlocking()
val titles = getSearchTitlesForManga(mangaId).executeAsBlocking()
FlatMetadata(meta, tags, titles)
} else null
}
return preparedOperationFromSingle(single)
}
private fun <T> preparedOperationFromSingle(single: Single<T>): PreparedOperation<T> {
return object : PreparedOperation<T> {
/**
* Creates [rx.Observable] that emits result of Operation.
*
*
* Observable may be "Hot" or "Cold", please read documentation of the concrete implementation.
*
* @return observable result of operation with only one [rx.Observer.onNext] call.
*/
override fun createObservable() = single.toObservable()
/**
* Executes operation synchronously in current thread.
*
*
* Notice: Blocking I/O operation should not be executed on the Main Thread,
* it can cause ANR (Activity Not Responding dialog), block the UI and drop animations frames.
* So please, execute blocking I/O operation only from background thread.
* See [androidx.annotation.WorkerThread].
*
* @return nullable result of operation.
*/
override fun executeAsBlocking() = single.toBlocking().value()
/**
* Creates [rx.Observable] that emits result of Operation.
*
*
* Observable may be "Hot" (usually "Warm") or "Cold", please read documentation of the concrete implementation.
*
* @return observable result of operation with only one [rx.Observer.onNext] call.
*/
override fun asRxObservable() = single.toObservable()
/**
* Creates [rx.Single] that emits result of Operation lazily when somebody subscribes to it.
*
*
*
* @return single result of operation.
*/
override fun asRxSingle() = single
}
}
fun DatabaseHandler.insertFlatMetadata(flatMetadata: FlatMetadata) {
require(flatMetadata.metadata.mangaId != -1L)
this as AndroidDatabaseHandler // todo remove when legacy backup is dead
db.transaction {
flatMetadata.metadata.let {
db.search_metadataQueries.upsert(it.mangaId, it.uploader, it.extra, it.indexedExtra, it.extraVersion)
}
db.search_tagsQueries.deleteByManga(flatMetadata.metadata.mangaId)
flatMetadata.tags.forEach {
db.search_tagsQueries.insert(it.mangaId, it.namespace, it.name, it.type)
}
db.search_titlesQueries.deleteByManga(flatMetadata.metadata.mangaId)
flatMetadata.titles.forEach {
db.search_titlesQueries.insert(it.mangaId, it.title, it.type)
}
}
}
@Deprecated("Replace with InsertFlatMetadata")
suspend fun DatabaseHandler.awaitInsertFlatMetadata(flatMetadata: FlatMetadata) {
require(flatMetadata.metadata.mangaId != -1L)
@ -156,29 +59,3 @@ suspend fun DatabaseHandler.awaitInsertFlatMetadata(flatMetadata: FlatMetadata)
}
}
}
fun DatabaseHelper.insertFlatMetadata(flatMetadata: FlatMetadata) {
require(flatMetadata.metadata.mangaId != -1L)
inTransaction {
insertSearchMetadata(flatMetadata.metadata).executeAsBlocking()
setSearchTagsForManga(flatMetadata.metadata.mangaId, flatMetadata.tags)
setSearchTitlesForManga(flatMetadata.metadata.mangaId, flatMetadata.titles)
}
}
fun DatabaseHelper.insertFlatMetadataCompletable(flatMetadata: FlatMetadata): Completable = Completable.fromCallable {
insertFlatMetadata(flatMetadata)
}
suspend fun DatabaseHelper.insertFlatMetadataAsync(flatMetadata: FlatMetadata): Deferred<Unit> = coroutineScope {
async {
require(flatMetadata.metadata.mangaId != -1L)
inTransaction {
insertSearchMetadata(flatMetadata.metadata).executeAsBlocking()
setSearchTagsForManga(flatMetadata.metadata.mangaId, flatMetadata.tags)
setSearchTitlesForManga(flatMetadata.metadata.mangaId, flatMetadata.titles)
}
}
}

View File

@ -1,66 +0,0 @@
package exh.metadata.sql.mappers
import android.database.Cursor
import androidx.core.content.contentValuesOf
import com.pushtorefresh.storio.sqlite.SQLiteTypeMapping
import com.pushtorefresh.storio.sqlite.operations.delete.DefaultDeleteResolver
import com.pushtorefresh.storio.sqlite.operations.get.DefaultGetResolver
import com.pushtorefresh.storio.sqlite.operations.put.DefaultPutResolver
import com.pushtorefresh.storio.sqlite.queries.DeleteQuery
import com.pushtorefresh.storio.sqlite.queries.InsertQuery
import com.pushtorefresh.storio.sqlite.queries.UpdateQuery
import exh.metadata.sql.models.SearchMetadata
import exh.metadata.sql.tables.SearchMetadataTable.COL_EXTRA
import exh.metadata.sql.tables.SearchMetadataTable.COL_EXTRA_VERSION
import exh.metadata.sql.tables.SearchMetadataTable.COL_INDEXED_EXTRA
import exh.metadata.sql.tables.SearchMetadataTable.COL_MANGA_ID
import exh.metadata.sql.tables.SearchMetadataTable.COL_UPLOADER
import exh.metadata.sql.tables.SearchMetadataTable.TABLE
class SearchMetadataTypeMapping : SQLiteTypeMapping<SearchMetadata>(
SearchMetadataPutResolver(),
SearchMetadataGetResolver(),
SearchMetadataDeleteResolver(),
)
class SearchMetadataPutResolver : DefaultPutResolver<SearchMetadata>() {
override fun mapToInsertQuery(obj: SearchMetadata) = InsertQuery.builder()
.table(TABLE)
.build()
override fun mapToUpdateQuery(obj: SearchMetadata) = UpdateQuery.builder()
.table(TABLE)
.where("$COL_MANGA_ID = ?")
.whereArgs(obj.mangaId)
.build()
override fun mapToContentValues(obj: SearchMetadata) = contentValuesOf(
COL_MANGA_ID to obj.mangaId,
COL_UPLOADER to obj.uploader,
COL_EXTRA to obj.extra,
COL_INDEXED_EXTRA to obj.indexedExtra,
COL_EXTRA_VERSION to obj.extraVersion,
)
}
class SearchMetadataGetResolver : DefaultGetResolver<SearchMetadata>() {
override fun mapFromCursor(cursor: Cursor): SearchMetadata =
SearchMetadata(
mangaId = cursor.getLong(cursor.getColumnIndexOrThrow(COL_MANGA_ID)),
uploader = cursor.getString(cursor.getColumnIndexOrThrow(COL_UPLOADER)),
extra = cursor.getString(cursor.getColumnIndexOrThrow(COL_EXTRA)),
indexedExtra = cursor.getString(cursor.getColumnIndexOrThrow(COL_INDEXED_EXTRA)),
extraVersion = cursor.getInt(cursor.getColumnIndexOrThrow(COL_EXTRA_VERSION)),
)
}
class SearchMetadataDeleteResolver : DefaultDeleteResolver<SearchMetadata>() {
override fun mapToDeleteQuery(obj: SearchMetadata) = DeleteQuery.builder()
.table(TABLE)
.where("$COL_MANGA_ID = ?")
.whereArgs(obj.mangaId)
.build()
}

View File

@ -1,65 +0,0 @@
package exh.metadata.sql.mappers
import android.database.Cursor
import androidx.core.content.contentValuesOf
import com.pushtorefresh.storio.sqlite.SQLiteTypeMapping
import com.pushtorefresh.storio.sqlite.operations.delete.DefaultDeleteResolver
import com.pushtorefresh.storio.sqlite.operations.get.DefaultGetResolver
import com.pushtorefresh.storio.sqlite.operations.put.DefaultPutResolver
import com.pushtorefresh.storio.sqlite.queries.DeleteQuery
import com.pushtorefresh.storio.sqlite.queries.InsertQuery
import com.pushtorefresh.storio.sqlite.queries.UpdateQuery
import exh.metadata.sql.models.SearchTag
import exh.metadata.sql.tables.SearchTagTable.COL_ID
import exh.metadata.sql.tables.SearchTagTable.COL_MANGA_ID
import exh.metadata.sql.tables.SearchTagTable.COL_NAME
import exh.metadata.sql.tables.SearchTagTable.COL_NAMESPACE
import exh.metadata.sql.tables.SearchTagTable.COL_TYPE
import exh.metadata.sql.tables.SearchTagTable.TABLE
class SearchTagTypeMapping : SQLiteTypeMapping<SearchTag>(
SearchTagPutResolver(),
SearchTagGetResolver(),
SearchTagDeleteResolver(),
)
class SearchTagPutResolver : DefaultPutResolver<SearchTag>() {
override fun mapToInsertQuery(obj: SearchTag) = InsertQuery.builder()
.table(TABLE)
.build()
override fun mapToUpdateQuery(obj: SearchTag) = UpdateQuery.builder()
.table(TABLE)
.where("$COL_ID = ?")
.whereArgs(obj.id)
.build()
override fun mapToContentValues(obj: SearchTag) = contentValuesOf(
COL_ID to obj.id,
COL_MANGA_ID to obj.mangaId,
COL_NAMESPACE to obj.namespace,
COL_NAME to obj.name,
COL_TYPE to obj.type,
)
}
class SearchTagGetResolver : DefaultGetResolver<SearchTag>() {
override fun mapFromCursor(cursor: Cursor): SearchTag = SearchTag(
id = cursor.getLong(cursor.getColumnIndexOrThrow(COL_ID)),
mangaId = cursor.getLong(cursor.getColumnIndexOrThrow(COL_MANGA_ID)),
namespace = cursor.getString(cursor.getColumnIndexOrThrow(COL_NAMESPACE)),
name = cursor.getString(cursor.getColumnIndexOrThrow(COL_NAME)),
type = cursor.getInt(cursor.getColumnIndexOrThrow(COL_TYPE)),
)
}
class SearchTagDeleteResolver : DefaultDeleteResolver<SearchTag>() {
override fun mapToDeleteQuery(obj: SearchTag) = DeleteQuery.builder()
.table(TABLE)
.where("$COL_ID = ?")
.whereArgs(obj.id)
.build()
}

View File

@ -1,62 +0,0 @@
package exh.metadata.sql.mappers
import android.database.Cursor
import androidx.core.content.contentValuesOf
import com.pushtorefresh.storio.sqlite.SQLiteTypeMapping
import com.pushtorefresh.storio.sqlite.operations.delete.DefaultDeleteResolver
import com.pushtorefresh.storio.sqlite.operations.get.DefaultGetResolver
import com.pushtorefresh.storio.sqlite.operations.put.DefaultPutResolver
import com.pushtorefresh.storio.sqlite.queries.DeleteQuery
import com.pushtorefresh.storio.sqlite.queries.InsertQuery
import com.pushtorefresh.storio.sqlite.queries.UpdateQuery
import exh.metadata.sql.models.SearchTitle
import exh.metadata.sql.tables.SearchTitleTable.COL_ID
import exh.metadata.sql.tables.SearchTitleTable.COL_MANGA_ID
import exh.metadata.sql.tables.SearchTitleTable.COL_TITLE
import exh.metadata.sql.tables.SearchTitleTable.COL_TYPE
import exh.metadata.sql.tables.SearchTitleTable.TABLE
class SearchTitleTypeMapping : SQLiteTypeMapping<SearchTitle>(
SearchTitlePutResolver(),
SearchTitleGetResolver(),
SearchTitleDeleteResolver(),
)
class SearchTitlePutResolver : DefaultPutResolver<SearchTitle>() {
override fun mapToInsertQuery(obj: SearchTitle) = InsertQuery.builder()
.table(TABLE)
.build()
override fun mapToUpdateQuery(obj: SearchTitle) = UpdateQuery.builder()
.table(TABLE)
.where("$COL_ID = ?")
.whereArgs(obj.id)
.build()
override fun mapToContentValues(obj: SearchTitle) = contentValuesOf(
COL_ID to obj.id,
COL_MANGA_ID to obj.mangaId,
COL_TITLE to obj.title,
COL_TYPE to obj.type,
)
}
class SearchTitleGetResolver : DefaultGetResolver<SearchTitle>() {
override fun mapFromCursor(cursor: Cursor): SearchTitle = SearchTitle(
id = cursor.getLong(cursor.getColumnIndexOrThrow(COL_ID)),
mangaId = cursor.getLong(cursor.getColumnIndexOrThrow(COL_MANGA_ID)),
title = cursor.getString(cursor.getColumnIndexOrThrow(COL_TITLE)),
type = cursor.getInt(cursor.getColumnIndexOrThrow(COL_TYPE)),
)
}
class SearchTitleDeleteResolver : DefaultDeleteResolver<SearchTitle>() {
override fun mapToDeleteQuery(obj: SearchTitle) = DeleteQuery.builder()
.table(TABLE)
.where("$COL_ID = ?")
.whereArgs(obj.id)
.build()
}

View File

@ -1,52 +0,0 @@
package exh.metadata.sql.queries
import com.pushtorefresh.storio.sqlite.queries.DeleteQuery
import com.pushtorefresh.storio.sqlite.queries.Query
import eu.kanade.tachiyomi.data.database.DbProvider
import exh.metadata.sql.models.SearchMetadata
import exh.metadata.sql.tables.SearchMetadataTable
interface SearchMetadataQueries : DbProvider {
fun getSearchMetadataForManga(mangaId: Long) = db.get()
.`object`(SearchMetadata::class.java)
.withQuery(
Query.builder()
.table(SearchMetadataTable.TABLE)
.where("${SearchMetadataTable.COL_MANGA_ID} = ?")
.whereArgs(mangaId)
.build(),
)
.prepare()
fun getSearchMetadata() = db.get()
.listOfObjects(SearchMetadata::class.java)
.withQuery(
Query.builder()
.table(SearchMetadataTable.TABLE)
.build(),
)
.prepare()
fun getSearchMetadataByIndexedExtra(extra: String) = db.get()
.listOfObjects(SearchMetadata::class.java)
.withQuery(
Query.builder()
.table(SearchMetadataTable.TABLE)
.where("${SearchMetadataTable.COL_INDEXED_EXTRA} = ?")
.whereArgs(extra)
.build(),
)
.prepare()
fun insertSearchMetadata(metadata: SearchMetadata) = db.put().`object`(metadata).prepare()
fun deleteSearchMetadata(metadata: SearchMetadata) = db.delete().`object`(metadata).prepare()
fun deleteAllSearchMetadata() = db.delete().byQuery(
DeleteQuery.builder()
.table(SearchMetadataTable.TABLE)
.build(),
)
.prepare()
}

View File

@ -1,53 +0,0 @@
package exh.metadata.sql.queries
import com.pushtorefresh.storio.sqlite.queries.DeleteQuery
import com.pushtorefresh.storio.sqlite.queries.Query
import eu.kanade.tachiyomi.data.database.DbProvider
import eu.kanade.tachiyomi.data.database.inTransaction
import exh.metadata.sql.models.SearchTag
import exh.metadata.sql.tables.SearchTagTable
interface SearchTagQueries : DbProvider {
fun getSearchTagsForManga(mangaId: Long) = db.get()
.listOfObjects(SearchTag::class.java)
.withQuery(
Query.builder()
.table(SearchTagTable.TABLE)
.where("${SearchTagTable.COL_MANGA_ID} = ?")
.whereArgs(mangaId)
.build(),
)
.prepare()
fun deleteSearchTagsForManga(mangaId: Long) = db.delete()
.byQuery(
DeleteQuery.builder()
.table(SearchTagTable.TABLE)
.where("${SearchTagTable.COL_MANGA_ID} = ?")
.whereArgs(mangaId)
.build(),
)
.prepare()
fun insertSearchTag(searchTag: SearchTag) = db.put().`object`(searchTag).prepare()
fun insertSearchTags(searchTags: List<SearchTag>) = db.put().objects(searchTags).prepare()
fun deleteSearchTag(searchTag: SearchTag) = db.delete().`object`(searchTag).prepare()
fun deleteAllSearchTags() = db.delete().byQuery(
DeleteQuery.builder()
.table(SearchTagTable.TABLE)
.build(),
)
.prepare()
fun setSearchTagsForManga(mangaId: Long, tags: List<SearchTag>) {
db.inTransaction {
deleteSearchTagsForManga(mangaId).executeAsBlocking()
tags.chunked(100) { chunk ->
insertSearchTags(chunk).executeAsBlocking()
}
}
}
}

View File

@ -1,53 +0,0 @@
package exh.metadata.sql.queries
import com.pushtorefresh.storio.sqlite.queries.DeleteQuery
import com.pushtorefresh.storio.sqlite.queries.Query
import eu.kanade.tachiyomi.data.database.DbProvider
import eu.kanade.tachiyomi.data.database.inTransaction
import exh.metadata.sql.models.SearchTitle
import exh.metadata.sql.tables.SearchTitleTable
interface SearchTitleQueries : DbProvider {
fun getSearchTitlesForManga(mangaId: Long) = db.get()
.listOfObjects(SearchTitle::class.java)
.withQuery(
Query.builder()
.table(SearchTitleTable.TABLE)
.where("${SearchTitleTable.COL_MANGA_ID} = ?")
.whereArgs(mangaId)
.build(),
)
.prepare()
fun deleteSearchTitlesForManga(mangaId: Long) = db.delete()
.byQuery(
DeleteQuery.builder()
.table(SearchTitleTable.TABLE)
.where("${SearchTitleTable.COL_MANGA_ID} = ?")
.whereArgs(mangaId)
.build(),
)
.prepare()
fun insertSearchTitle(searchTitle: SearchTitle) = db.put().`object`(searchTitle).prepare()
fun insertSearchTitles(searchTitles: List<SearchTitle>) = db.put().objects(searchTitles).prepare()
fun deleteSearchTitle(searchTitle: SearchTitle) = db.delete().`object`(searchTitle).prepare()
fun deleteAllSearchTitle() = db.delete().byQuery(
DeleteQuery.builder()
.table(SearchTitleTable.TABLE)
.build(),
)
.prepare()
fun setSearchTitlesForManga(mangaId: Long, titles: List<SearchTitle>) {
db.inTransaction {
deleteSearchTitlesForManga(mangaId).executeAsBlocking()
titles.chunked(100) { chunk ->
insertSearchTitles(chunk).executeAsBlocking()
}
}
}
}

View File

@ -1,15 +0,0 @@
package exh.metadata.sql.tables
object SearchMetadataTable {
const val TABLE = "search_metadata"
const val COL_MANGA_ID = "manga_id"
const val COL_UPLOADER = "uploader"
const val COL_EXTRA = "extra"
const val COL_INDEXED_EXTRA = "indexed_extra"
const val COL_EXTRA_VERSION = "extra_version"
}

View File

@ -1,15 +0,0 @@
package exh.metadata.sql.tables
object SearchTagTable {
const val TABLE = "search_tags"
const val COL_ID = "_id"
const val COL_MANGA_ID = "manga_id"
const val COL_NAMESPACE = "namespace"
const val COL_NAME = "name"
const val COL_TYPE = "type"
}

View File

@ -1,13 +0,0 @@
package exh.metadata.sql.tables
object SearchTitleTable {
const val TABLE = "search_titles"
const val COL_ID = "_id"
const val COL_MANGA_ID = "manga_id"
const val COL_TITLE = "title"
const val COL_TYPE = "type"
}

View File

@ -1,6 +1,6 @@
package exh.recs
import eu.kanade.domain.manga.interactor.GetMangaById
import eu.kanade.domain.manga.interactor.GetManga
import eu.kanade.domain.manga.model.Manga
import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourcePresenter
@ -15,13 +15,13 @@ import uy.kohesive.injekt.api.get
class RecommendsPresenter(
val mangaId: Long,
sourceId: Long,
private val getMangaById: GetMangaById = Injekt.get(),
private val getManga: GetManga = Injekt.get(),
) : BrowseSourcePresenter(sourceId) {
var manga: Manga? = null
override fun createPager(query: String, filters: FilterList): Pager {
this.manga = runBlocking { getMangaById.await(mangaId) }
this.manga = runBlocking { getManga.await(mangaId) }
return RecommendsPager(manga!!)
}
}

View File

@ -1,8 +1,5 @@
package exh.search
import exh.metadata.sql.tables.SearchMetadataTable
import exh.metadata.sql.tables.SearchTagTable
import exh.metadata.sql.tables.SearchTitleTable
import java.util.Locale
class SearchEngine {
@ -23,16 +20,16 @@ class SearchEngine {
val params = mutableListOf<String>()
it.joinToString(separator = " OR ", prefix = "(", postfix = ")") { q ->
params += q
"${SearchTagTable.TABLE}.${SearchTagTable.COL_NAME} LIKE ?"
"search_tags.name LIKE ?"
} to params
}
return when {
namespace != null -> {
var query =
"""
(SELECT ${SearchTagTable.COL_MANGA_ID} AS $COL_MANGA_ID FROM ${SearchTagTable.TABLE}
WHERE ${SearchTagTable.COL_NAMESPACE} IS NOT NULL
AND ${SearchTagTable.COL_NAMESPACE} LIKE ?
(SELECT ${"manga_id"} AS $COL_MANGA_ID FROM ${"search_tags"}
WHERE ${"namespace"} IS NOT NULL
AND ${"namespace"} LIKE ?
""".trimIndent()
val params = mutableListOf(escapeLike(namespace))
if (componentTagQuery != null) {
@ -46,14 +43,14 @@ class SearchEngine {
// Match title + tags
val tagQuery =
"""
SELECT ${SearchTagTable.COL_MANGA_ID} AS $COL_MANGA_ID FROM ${SearchTagTable.TABLE}
SELECT ${"manga_id"} AS $COL_MANGA_ID FROM ${"search_tags"}
WHERE ${componentTagQuery!!.first}
""".trimIndent() to componentTagQuery.second
val titleQuery =
"""
SELECT ${SearchTitleTable.COL_MANGA_ID} AS $COL_MANGA_ID FROM ${SearchTitleTable.TABLE}
WHERE ${SearchTitleTable.COL_TITLE} LIKE ?
SELECT ${"manga_id"} AS $COL_MANGA_ID FROM ${"search_titles"}
WHERE ${"title"} LIKE ?
""".trimIndent() to listOf(component.asLenientTitleQuery())
"(${tagQuery.first} UNION ${titleQuery.first})".trimIndent() to
@ -75,7 +72,7 @@ class SearchEngine {
textToSubQueries(null, component)
} else if (component is Namespace) {
if (component.namespace == "uploader") {
wheres += "meta.${SearchMetadataTable.COL_UPLOADER} LIKE ?"
wheres += "meta.uploader LIKE ?"
whereParams += component.tag!!.rawTextEscapedForLike()
null
} else {
@ -97,15 +94,15 @@ class SearchEngine {
val completeParams = mutableListOf<String>()
var baseQuery =
"""
SELECT ${SearchMetadataTable.COL_MANGA_ID}
FROM ${SearchMetadataTable.TABLE} meta
SELECT ${"manga_id"}
FROM ${"search_metadata"} meta
""".trimIndent()
include.forEachIndexed { index, pair ->
baseQuery += "\n" + (
"""
INNER JOIN ${pair.first} i$index
ON i$index.$COL_MANGA_ID = meta.${SearchMetadataTable.COL_MANGA_ID}
ON i$index.$COL_MANGA_ID = meta.${"manga_id"}
""".trimIndent()
)
completeParams += pair.second
@ -113,7 +110,7 @@ class SearchEngine {
exclude.forEach {
wheres += """
(meta.${SearchMetadataTable.COL_MANGA_ID} NOT IN ${it.first})
(meta.${"manga_id"} NOT IN ${it.first})
""".trimIndent()
whereParams += it.second
}
@ -122,7 +119,7 @@ class SearchEngine {
baseQuery += "\nWHERE\n"
baseQuery += wheres.joinToString("\nAND\n")
}
baseQuery += "\nORDER BY ${SearchMetadataTable.COL_MANGA_ID}"
baseQuery += "\nORDER BY manga_id"
return baseQuery to completeParams
}

View File

@ -1,5 +1,6 @@
package exh.smartsearch
import eu.kanade.data.DatabaseHandler
import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.source.CatalogueSource
@ -18,6 +19,7 @@ class SmartSearchEngine(
private val extraSearchParams: String? = null,
) {
private val db: DatabaseHelper by injectLazy()
private val handler: DatabaseHandler by injectLazy()
private val normalizedLevenshtein = NormalizedLevenshtein()

View File

@ -6,7 +6,7 @@ import android.view.View
import androidx.core.os.bundleOf
import androidx.recyclerview.widget.LinearLayoutManager
import dev.chrisbanes.insetter.applyInsetter
import eu.kanade.domain.manga.interactor.GetMangaById
import eu.kanade.domain.manga.interactor.GetManga
import eu.kanade.domain.manga.model.Manga
import eu.kanade.tachiyomi.databinding.MetadataViewControllerBinding
import eu.kanade.tachiyomi.source.Source
@ -29,7 +29,7 @@ class MetadataViewController : NucleusController<MetadataViewControllerBinding,
}
constructor(mangaId: Long) : this(
runBlocking { Injekt.get<GetMangaById>().await(mangaId)!! },
runBlocking { Injekt.get<GetManga>().await(mangaId)!! },
)
@Suppress("unused")

View File

@ -0,0 +1,7 @@
deleteBySyncId:
DELETE FROM manga_sync WHERE sync_id = :syncId;
migrateSource:
UPDATE mangas
SET source = :newId
WHERE source = :oldId;

View File

@ -196,6 +196,18 @@ INNER JOIN search_metadata
ON mangas._id = search_metadata.manga_id
WHERE mangas.favorite = 1 AND (mangas.source = :eh OR mangas.source = :exh);
getIdsOfFavoriteMangaWithMetadata:
SELECT mangas._id FROM mangas
INNER JOIN search_metadata
ON mangas._id = search_metadata.manga_id
WHERE mangas.favorite = 1;
getBySource:
SELECT * FROM mangas WHERE source = :sourceId;
getAll:
SELECT * FROM mangas;
selectLastInsertRow:
SELECT *
FROM mangas

View File

@ -80,11 +80,11 @@ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
updateSettingsById:
UPDATE merged
SET
get_chapter_updates = ?,
download_chapters = ?,
info_manga = ?,
chapter_priority = ?
WHERE _id = ?;
get_chapter_updates = coalesce(:getChapterUpdates, get_chapter_updates),
download_chapters = coalesce(:downloadChapters, download_chapters),
info_manga = coalesce(:infoManga, info_manga),
chapter_priority = coalesce(:chapterPriority, chapter_priority)
WHERE _id = :id;
deleteById:
DELETE FROM merged WHERE _id = ?;