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