Small cleanup and optimizations, add a coroutine version of insertFlatMetadata
This commit is contained in:
parent
e6d62dd1dc
commit
0a4fcb480d
@ -36,7 +36,7 @@ import eu.kanade.tachiyomi.source.online.MetadataSource
|
|||||||
import eu.kanade.tachiyomi.source.online.all.MergedSource
|
import eu.kanade.tachiyomi.source.online.all.MergedSource
|
||||||
import exh.MERGED_SOURCE_ID
|
import exh.MERGED_SOURCE_ID
|
||||||
import exh.metadata.metadata.base.getFlatMetadataForManga
|
import exh.metadata.metadata.base.getFlatMetadataForManga
|
||||||
import exh.metadata.metadata.base.insertFlatMetadata
|
import exh.metadata.metadata.base.insertFlatMetadataAsync
|
||||||
import exh.savedsearches.JsonSavedSearch
|
import exh.savedsearches.JsonSavedSearch
|
||||||
import exh.source.getMainSource
|
import exh.source.getMainSource
|
||||||
import kotlinx.serialization.ExperimentalSerializationApi
|
import kotlinx.serialization.ExperimentalSerializationApi
|
||||||
@ -527,12 +527,12 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun restoreFlatMetadata(manga: Manga, backupFlatMetadata: BackupFlatMetadata) {
|
internal suspend fun restoreFlatMetadata(manga: Manga, backupFlatMetadata: BackupFlatMetadata) {
|
||||||
manga.id?.let { mangaId ->
|
manga.id?.let { mangaId ->
|
||||||
databaseHelper.getFlatMetadataForManga(mangaId).executeAsBlocking().let {
|
databaseHelper.getFlatMetadataForManga(mangaId).executeAsBlocking().let {
|
||||||
if (it == null) {
|
if (it == null) {
|
||||||
val flatMetadata = backupFlatMetadata.getFlatMetadata(mangaId)
|
val flatMetadata = backupFlatMetadata.getFlatMetadata(mangaId)
|
||||||
databaseHelper.insertFlatMetadata(flatMetadata).await()
|
databaseHelper.insertFlatMetadataAsync(flatMetadata).await()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -223,7 +223,7 @@ class FullBackupRestore(context: Context, notifier: BackupNotifier, private val
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun restoreExtraForManga(manga: Manga, categories: List<Int>, history: List<BackupHistory>, tracks: List<Track>, backupCategories: List<BackupCategory>, mergedMangaReferences: List<BackupMergedMangaReference>, flatMetadata: BackupFlatMetadata?) {
|
private suspend fun restoreExtraForManga(manga: Manga, categories: List<Int>, history: List<BackupHistory>, tracks: List<Track>, backupCategories: List<BackupCategory>, mergedMangaReferences: List<BackupMergedMangaReference>, flatMetadata: BackupFlatMetadata?) {
|
||||||
// Restore categories
|
// Restore categories
|
||||||
backupManager.restoreCategoriesForManga(manga, categories, backupCategories)
|
backupManager.restoreCategoriesForManga(manga, categories, backupCategories)
|
||||||
|
|
||||||
|
@ -32,7 +32,6 @@ import eu.kanade.tachiyomi.ui.library.LibraryGroup
|
|||||||
import eu.kanade.tachiyomi.ui.manga.track.TrackItem
|
import eu.kanade.tachiyomi.ui.manga.track.TrackItem
|
||||||
import eu.kanade.tachiyomi.util.chapter.NoChaptersException
|
import eu.kanade.tachiyomi.util.chapter.NoChaptersException
|
||||||
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
|
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
|
||||||
import eu.kanade.tachiyomi.util.lang.await
|
|
||||||
import eu.kanade.tachiyomi.util.lang.runAsObservable
|
import eu.kanade.tachiyomi.util.lang.runAsObservable
|
||||||
import eu.kanade.tachiyomi.util.prepUpdateCover
|
import eu.kanade.tachiyomi.util.prepUpdateCover
|
||||||
import eu.kanade.tachiyomi.util.shouldDownloadNewChapters
|
import eu.kanade.tachiyomi.util.shouldDownloadNewChapters
|
||||||
|
@ -10,12 +10,11 @@ import eu.kanade.tachiyomi.data.track.TrackManager
|
|||||||
import eu.kanade.tachiyomi.data.track.TrackService
|
import eu.kanade.tachiyomi.data.track.TrackService
|
||||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import eu.kanade.tachiyomi.util.lang.await
|
|
||||||
import exh.md.utils.FollowStatus
|
import exh.md.utils.FollowStatus
|
||||||
import exh.md.utils.MdUtil
|
import exh.md.utils.MdUtil
|
||||||
import exh.metadata.metadata.MangaDexSearchMetadata
|
import exh.metadata.metadata.MangaDexSearchMetadata
|
||||||
import exh.metadata.metadata.base.getFlatMetadataForManga
|
import exh.metadata.metadata.base.getFlatMetadataForManga
|
||||||
import exh.metadata.metadata.base.insertFlatMetadata
|
import exh.metadata.metadata.base.insertFlatMetadataAsync
|
||||||
import exh.util.executeOnIO
|
import exh.util.executeOnIO
|
||||||
import exh.util.floor
|
import exh.util.floor
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
@ -59,7 +58,7 @@ class MdList(private val context: Context, id: Int) : TrackService(id) {
|
|||||||
if (mangaMetadata.follow_status != followStatus.int) {
|
if (mangaMetadata.follow_status != followStatus.int) {
|
||||||
mdex.updateFollowStatus(MdUtil.getMangaId(track.tracking_url), followStatus)
|
mdex.updateFollowStatus(MdUtil.getMangaId(track.tracking_url), followStatus)
|
||||||
mangaMetadata.follow_status = followStatus.int
|
mangaMetadata.follow_status = followStatus.int
|
||||||
db.insertFlatMetadata(mangaMetadata.flatten()).await()
|
db.insertFlatMetadataAsync(mangaMetadata.flatten()).await()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (track.score.toInt() > 0) {
|
if (track.score.toInt() > 0) {
|
||||||
@ -78,7 +77,7 @@ class MdList(private val context: Context, id: Int) : TrackService(id) {
|
|||||||
track.status = FollowStatus.READING.int
|
track.status = FollowStatus.READING.int
|
||||||
mdex.updateFollowStatus(MdUtil.getMangaId(track.tracking_url), newFollowStatus)
|
mdex.updateFollowStatus(MdUtil.getMangaId(track.tracking_url), newFollowStatus)
|
||||||
mangaMetadata.follow_status = newFollowStatus.int
|
mangaMetadata.follow_status = newFollowStatus.int
|
||||||
db.insertFlatMetadata(mangaMetadata.flatten()).await()
|
db.insertFlatMetadataAsync(mangaMetadata.flatten()).await()
|
||||||
}
|
}
|
||||||
|
|
||||||
mdex.updateReadingProgress(track)
|
mdex.updateReadingProgress(track)
|
||||||
|
@ -18,8 +18,7 @@ open class Page(
|
|||||||
// SY -->
|
// SY -->
|
||||||
var imageUrl = imageUrl
|
var imageUrl = imageUrl
|
||||||
get() {
|
get() {
|
||||||
if (field == null) return null
|
return field?.let { DataSaver.compress(it) }
|
||||||
return DataSaver().compress(field!!)
|
|
||||||
}
|
}
|
||||||
// SY <--
|
// SY <--
|
||||||
|
|
||||||
|
@ -11,7 +11,8 @@ import eu.kanade.tachiyomi.ui.manga.MangaController
|
|||||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||||
import exh.metadata.metadata.base.getFlatMetadataForManga
|
import exh.metadata.metadata.base.getFlatMetadataForManga
|
||||||
import exh.metadata.metadata.base.insertFlatMetadata
|
import exh.metadata.metadata.base.insertFlatMetadata
|
||||||
import exh.util.await
|
import exh.metadata.metadata.base.insertFlatMetadataAsync
|
||||||
|
import exh.util.executeOnIO
|
||||||
import rx.Completable
|
import rx.Completable
|
||||||
import rx.Single
|
import rx.Single
|
||||||
import tachiyomi.source.model.MangaInfo
|
import tachiyomi.source.model.MangaInfo
|
||||||
@ -79,14 +80,14 @@ interface MetadataSource<M : RaisedSearchMetadata, I> : CatalogueSource {
|
|||||||
suspend fun parseToManga(manga: MangaInfo, input: I): MangaInfo {
|
suspend fun parseToManga(manga: MangaInfo, input: I): MangaInfo {
|
||||||
val mangaId = manga.id()
|
val mangaId = manga.id()
|
||||||
val metadata = if (mangaId != null) {
|
val metadata = if (mangaId != null) {
|
||||||
val flatMetadata = db.getFlatMetadataForManga(mangaId).await()
|
val flatMetadata = db.getFlatMetadataForManga(mangaId).executeOnIO()
|
||||||
flatMetadata?.raise(metaClass) ?: newMetaInstance()
|
flatMetadata?.raise(metaClass) ?: newMetaInstance()
|
||||||
} else newMetaInstance()
|
} else newMetaInstance()
|
||||||
|
|
||||||
parseInfoIntoMetadata(metadata, input)
|
parseInfoIntoMetadata(metadata, input)
|
||||||
if (mangaId != null) {
|
if (mangaId != null) {
|
||||||
metadata.mangaId = mangaId
|
metadata.mangaId = mangaId
|
||||||
db.insertFlatMetadata(metadata.flatten()).await()
|
db.insertFlatMetadataAsync(metadata.flatten()).await()
|
||||||
}
|
}
|
||||||
|
|
||||||
return metadata.createMangaInfo(manga)
|
return metadata.createMangaInfo(manga)
|
||||||
@ -134,7 +135,7 @@ interface MetadataSource<M : RaisedSearchMetadata, I> : CatalogueSource {
|
|||||||
*/
|
*/
|
||||||
suspend fun fetchOrLoadMetadata(mangaId: Long?, inputProducer: suspend () -> I): M {
|
suspend fun fetchOrLoadMetadata(mangaId: Long?, inputProducer: suspend () -> I): M {
|
||||||
val meta = if (mangaId != null) {
|
val meta = if (mangaId != null) {
|
||||||
val flatMetadata = db.getFlatMetadataForManga(mangaId).await()
|
val flatMetadata = db.getFlatMetadataForManga(mangaId).executeOnIO()
|
||||||
flatMetadata?.raise(metaClass)
|
flatMetadata?.raise(metaClass)
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
@ -145,14 +146,14 @@ interface MetadataSource<M : RaisedSearchMetadata, I> : CatalogueSource {
|
|||||||
parseInfoIntoMetadata(newMeta, input)
|
parseInfoIntoMetadata(newMeta, input)
|
||||||
if (mangaId != null) {
|
if (mangaId != null) {
|
||||||
newMeta.mangaId = mangaId
|
newMeta.mangaId = mangaId
|
||||||
db.insertFlatMetadata(newMeta.flatten()).let { newMeta }
|
db.insertFlatMetadataAsync(newMeta.flatten()).await().let { newMeta }
|
||||||
} else newMeta
|
} else newMeta
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getDescriptionAdapter(controller: MangaController): RecyclerView.Adapter<*>?
|
fun getDescriptionAdapter(controller: MangaController): RecyclerView.Adapter<*>?
|
||||||
|
|
||||||
suspend fun MangaInfo.id() = db.getManga(key, id).await()?.id
|
suspend fun MangaInfo.id() = db.getManga(key, id).executeOnIO()?.id
|
||||||
val SManga.id get() = (this as? Manga)?.id
|
val SManga.id get() = (this as? Manga)?.id
|
||||||
val SChapter.mangaId get() = (this as? Chapter)?.manga_id
|
val SChapter.mangaId get() = (this as? Chapter)?.manga_id
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ import eu.kanade.tachiyomi.ui.browse.migration.advanced.design.PreMigrationContr
|
|||||||
import eu.kanade.tachiyomi.ui.browse.migration.search.SearchController
|
import eu.kanade.tachiyomi.ui.browse.migration.search.SearchController
|
||||||
import eu.kanade.tachiyomi.ui.manga.MangaController
|
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||||
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
|
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
|
||||||
import eu.kanade.tachiyomi.util.lang.await
|
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||||
import eu.kanade.tachiyomi.util.lang.launchUI
|
import eu.kanade.tachiyomi.util.lang.launchUI
|
||||||
import eu.kanade.tachiyomi.util.lang.withIOContext
|
import eu.kanade.tachiyomi.util.lang.withIOContext
|
||||||
import eu.kanade.tachiyomi.util.system.getResourceColor
|
import eu.kanade.tachiyomi.util.system.getResourceColor
|
||||||
@ -49,7 +49,6 @@ import kotlinx.coroutines.Dispatchers
|
|||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.isActive
|
import kotlinx.coroutines.isActive
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.coroutines.sync.Semaphore
|
import kotlinx.coroutines.sync.Semaphore
|
||||||
import kotlinx.coroutines.sync.withPermit
|
import kotlinx.coroutines.sync.withPermit
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
@ -115,7 +114,7 @@ class MigrationListController(bundle: Bundle? = null) :
|
|||||||
adapter?.updateDataSet(newMigratingManga.map { it.toModal() })
|
adapter?.updateDataSet(newMigratingManga.map { it.toModal() })
|
||||||
|
|
||||||
if (migrationsJob == null) {
|
if (migrationsJob == null) {
|
||||||
migrationsJob = viewScope.launch(Dispatchers.IO) {
|
migrationsJob = viewScope.launchIO {
|
||||||
runMigrations(newMigratingManga)
|
runMigrations(newMigratingManga)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -128,7 +127,7 @@ class MigrationListController(bundle: Bundle? = null) :
|
|||||||
val useSmartSearch = preferences.smartMigration().get()
|
val useSmartSearch = preferences.smartMigration().get()
|
||||||
|
|
||||||
val sources = preferences.migrationSources().get().split("/").mapNotNull {
|
val sources = preferences.migrationSources().get().split("/").mapNotNull {
|
||||||
val value = it.toLongOrNull() ?: return
|
val value = it.toLongOrNull() ?: return@mapNotNull null
|
||||||
sourceManager.get(value) as? CatalogueSource
|
sourceManager.get(value) as? CatalogueSource
|
||||||
}
|
}
|
||||||
for (manga in mangas) {
|
for (manga in mangas) {
|
||||||
|
@ -17,11 +17,10 @@ import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
|||||||
import eu.kanade.tachiyomi.ui.browse.BrowseController
|
import eu.kanade.tachiyomi.ui.browse.BrowseController
|
||||||
import eu.kanade.tachiyomi.ui.browse.migration.advanced.design.PreMigrationController
|
import eu.kanade.tachiyomi.ui.browse.migration.advanced.design.PreMigrationController
|
||||||
import eu.kanade.tachiyomi.ui.browse.migration.manga.MigrationMangaController
|
import eu.kanade.tachiyomi.ui.browse.migration.manga.MigrationMangaController
|
||||||
import eu.kanade.tachiyomi.util.lang.await
|
|
||||||
import eu.kanade.tachiyomi.util.lang.launchUI
|
import eu.kanade.tachiyomi.util.lang.launchUI
|
||||||
import eu.kanade.tachiyomi.util.lang.withUIContext
|
import eu.kanade.tachiyomi.util.lang.withUIContext
|
||||||
import eu.kanade.tachiyomi.util.system.openInBrowser
|
import eu.kanade.tachiyomi.util.system.openInBrowser
|
||||||
import rx.schedulers.Schedulers
|
import exh.util.executeOnIO
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
@ -84,8 +83,9 @@ class MigrationSourcesController :
|
|||||||
override fun onItemClick(view: View?, position: Int): Boolean {
|
override fun onItemClick(view: View?, position: Int): Boolean {
|
||||||
val item = adapter?.getItem(position) as? SourceItem ?: return false
|
val item = adapter?.getItem(position) as? SourceItem ?: return false
|
||||||
val controller = MigrationMangaController(item.source.id, item.source.name)
|
val controller = MigrationMangaController(item.source.id, item.source.name)
|
||||||
|
val parentController = parentController
|
||||||
if (parentController is BrowseController) {
|
if (parentController is BrowseController) {
|
||||||
parentController!!.router.pushController(controller.withFadeTransaction())
|
parentController.router.pushController(controller.withFadeTransaction())
|
||||||
} else {
|
} else {
|
||||||
router.pushController(controller.withFadeTransaction())
|
router.pushController(controller.withFadeTransaction())
|
||||||
}
|
}
|
||||||
@ -97,15 +97,18 @@ class MigrationSourcesController :
|
|||||||
val item = adapter?.getItem(position) as? SourceItem ?: return
|
val item = adapter?.getItem(position) as? SourceItem ?: return
|
||||||
|
|
||||||
launchUI {
|
launchUI {
|
||||||
val manga = Injekt.get<DatabaseHelper>().getFavoriteMangas().asRxSingle().await(Schedulers.io())
|
val manga = Injekt.get<DatabaseHelper>().getFavoriteMangas().executeOnIO()
|
||||||
val sourceMangas = manga.asSequence().filter { it.source == item.source.id }.map { it.id!! }.toList()
|
val sourceMangas = manga.asSequence().filter { it.source == item.source.id }.mapNotNull { it.id }.toList()
|
||||||
withUIContext {
|
withUIContext {
|
||||||
PreMigrationController.navigateToMigration(
|
PreMigrationController.navigateToMigration(
|
||||||
Injekt.get<PreferencesHelper>().skipPreMigration().get(),
|
Injekt.get<PreferencesHelper>().skipPreMigration().get(),
|
||||||
if (parentController is BrowseController) {
|
run {
|
||||||
parentController!!.router
|
val parentController = parentController
|
||||||
} else {
|
if (parentController is BrowseController) {
|
||||||
router
|
parentController.router
|
||||||
|
} else {
|
||||||
|
router
|
||||||
|
}
|
||||||
},
|
},
|
||||||
sourceMangas
|
sourceMangas
|
||||||
)
|
)
|
||||||
|
@ -208,7 +208,7 @@ class EditMangaDialog : DialogController {
|
|||||||
addView(addTagChip)
|
addView(addTagChip)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ChipGroup.getTextStrings(): List<String>? = children.mapNotNull {
|
private fun ChipGroup.getTextStrings(): List<String> = children.mapNotNull {
|
||||||
if (it is Chip && !it.text.toString().contains(context.getString(R.string.add_tag), ignoreCase = true)) {
|
if (it is Chip && !it.text.toString().contains(context.getString(R.string.add_tag), ignoreCase = true)) {
|
||||||
it.text.toString()
|
it.text.toString()
|
||||||
} else null
|
} else null
|
||||||
|
@ -52,7 +52,7 @@ import exh.merged.sql.models.MergedMangaReference
|
|||||||
import exh.metadata.metadata.base.FlatMetadata
|
import exh.metadata.metadata.base.FlatMetadata
|
||||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||||
import exh.metadata.metadata.base.getFlatMetadataForManga
|
import exh.metadata.metadata.base.getFlatMetadataForManga
|
||||||
import exh.metadata.metadata.base.insertFlatMetadata
|
import exh.metadata.metadata.base.insertFlatMetadataAsync
|
||||||
import exh.source.getMainSource
|
import exh.source.getMainSource
|
||||||
import exh.util.shouldDeleteChapters
|
import exh.util.shouldDeleteChapters
|
||||||
import exh.util.trimOrNull
|
import exh.util.trimOrNull
|
||||||
@ -1002,11 +1002,11 @@ class MangaPresenter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SY -->
|
// SY -->
|
||||||
fun setScanlatorFilter(filteredScanlators: Set<String>) {
|
suspend fun setScanlatorFilter(filteredScanlators: Set<String>) {
|
||||||
val meta = meta ?: return
|
val meta = meta ?: return
|
||||||
meta.filteredScanlators = if (filteredScanlators.size == allChapterScanlators.size) null else MdUtil.getScanlatorString(filteredScanlators)
|
meta.filteredScanlators = if (filteredScanlators.size == allChapterScanlators.size) null else MdUtil.getScanlatorString(filteredScanlators)
|
||||||
meta.flatten().let {
|
meta.flatten().let {
|
||||||
db.insertFlatMetadata(it).await()
|
db.insertFlatMetadataAsync(it).await()
|
||||||
}
|
}
|
||||||
refreshChapters()
|
refreshChapters()
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,8 @@ import eu.kanade.tachiyomi.R
|
|||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.source.online.MetadataSource
|
import eu.kanade.tachiyomi.source.online.MetadataSource
|
||||||
import eu.kanade.tachiyomi.ui.manga.MangaPresenter
|
import eu.kanade.tachiyomi.ui.manga.MangaPresenter
|
||||||
|
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||||
|
import eu.kanade.tachiyomi.util.lang.withUIContext
|
||||||
import eu.kanade.tachiyomi.util.system.toast
|
import eu.kanade.tachiyomi.util.system.toast
|
||||||
import eu.kanade.tachiyomi.util.view.popupMenu
|
import eu.kanade.tachiyomi.util.view.popupMenu
|
||||||
import eu.kanade.tachiyomi.widget.ExtendedNavigationView
|
import eu.kanade.tachiyomi.widget.ExtendedNavigationView
|
||||||
@ -19,6 +21,7 @@ import eu.kanade.tachiyomi.widget.TabbedBottomSheetDialog
|
|||||||
import exh.md.utils.MdUtil
|
import exh.md.utils.MdUtil
|
||||||
import exh.metadata.metadata.MangaDexSearchMetadata
|
import exh.metadata.metadata.MangaDexSearchMetadata
|
||||||
import exh.source.getMainSource
|
import exh.source.getMainSource
|
||||||
|
import kotlinx.coroutines.supervisorScope
|
||||||
|
|
||||||
class ChaptersSettingsSheet(
|
class ChaptersSettingsSheet(
|
||||||
private val router: Router,
|
private val router: Router,
|
||||||
@ -132,13 +135,21 @@ class ChaptersSettingsSheet(
|
|||||||
MaterialDialog(context)
|
MaterialDialog(context)
|
||||||
.title(R.string.select_scanlators)
|
.title(R.string.select_scanlators)
|
||||||
.listItemsMultiChoice(items = presenter.allChapterScanlators.toList(), initialSelection = preselected) { _, selections, _ ->
|
.listItemsMultiChoice(items = presenter.allChapterScanlators.toList(), initialSelection = preselected) { _, selections, _ ->
|
||||||
val selected = selections.map { scanlators[it] }.toSet()
|
launchIO {
|
||||||
presenter.setScanlatorFilter(selected)
|
supervisorScope {
|
||||||
onGroupClicked(this)
|
val selected = selections.map { scanlators[it] }.toSet()
|
||||||
|
presenter.setScanlatorFilter(selected)
|
||||||
|
withUIContext { onGroupClicked(this@FilterGroup) }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.negativeButton(R.string.action_reset) {
|
.negativeButton(R.string.action_reset) {
|
||||||
presenter.setScanlatorFilter(presenter.allChapterScanlators)
|
launchIO {
|
||||||
onGroupClicked(this)
|
supervisorScope {
|
||||||
|
presenter.setScanlatorFilter(presenter.allChapterScanlators)
|
||||||
|
withUIContext { onGroupClicked(this@FilterGroup) }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.positiveButton(android.R.string.ok)
|
.positiveButton(android.R.string.ok)
|
||||||
.show()
|
.show()
|
||||||
|
@ -71,6 +71,7 @@ import eu.kanade.tachiyomi.widget.SimpleAnimationListener
|
|||||||
import eu.kanade.tachiyomi.widget.SimpleSeekBarListener
|
import eu.kanade.tachiyomi.widget.SimpleSeekBarListener
|
||||||
import exh.isEhBasedSource
|
import exh.isEhBasedSource
|
||||||
import exh.util.defaultReaderType
|
import exh.util.defaultReaderType
|
||||||
|
import exh.util.mangaType
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
@ -729,7 +730,7 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
|
|||||||
binding.viewerContainer.addView(newViewer.getView())
|
binding.viewerContainer.addView(newViewer.getView())
|
||||||
|
|
||||||
// SY -->
|
// SY -->
|
||||||
val defaultReaderType = manga.defaultReaderType()
|
val defaultReaderType = manga.defaultReaderType(manga.mangaType(sourceName = sourceManager.getOrStub(manga.source).name))
|
||||||
if (preferences.useAutoWebtoon().get() && manga.viewer == 0 && defaultReaderType != null && defaultReaderType == WEBTOON) {
|
if (preferences.useAutoWebtoon().get() && manga.viewer == 0 && defaultReaderType != null && defaultReaderType == WEBTOON) {
|
||||||
binding.root.snack(resources.getString(R.string.eh_auto_webtoon_snack), Snackbar.LENGTH_LONG)
|
binding.root.snack(resources.getString(R.string.eh_auto_webtoon_snack), Snackbar.LENGTH_LONG)
|
||||||
} else if (preferences.showReadingMode()) {
|
} else if (preferences.showReadingMode()) {
|
||||||
|
@ -44,6 +44,7 @@ import exh.metadata.metadata.base.RaisedSearchMetadata
|
|||||||
import exh.metadata.metadata.base.getFlatMetadataForManga
|
import exh.metadata.metadata.base.getFlatMetadataForManga
|
||||||
import exh.source.getMainSource
|
import exh.source.getMainSource
|
||||||
import exh.util.defaultReaderType
|
import exh.util.defaultReaderType
|
||||||
|
import exh.util.mangaType
|
||||||
import exh.util.shouldDeleteChapters
|
import exh.util.shouldDeleteChapters
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.awaitAll
|
import kotlinx.coroutines.awaitAll
|
||||||
@ -598,7 +599,7 @@ class ReaderPresenter(
|
|||||||
val manga = manga ?: return preferences.defaultViewer()
|
val manga = manga ?: return preferences.defaultViewer()
|
||||||
// SY -->
|
// SY -->
|
||||||
return if (manga.viewer == 0 && preferences.useAutoWebtoon().get()) {
|
return if (manga.viewer == 0 && preferences.useAutoWebtoon().get()) {
|
||||||
manga.defaultReaderType() ?: if (manga.viewer == 0) preferences.defaultViewer() else manga.viewer
|
manga.defaultReaderType(manga.mangaType(sourceName = sourceManager.getOrStub(manga.source).name)) ?: if (manga.viewer == 0) preferences.defaultViewer() else manga.viewer
|
||||||
} else if (manga.viewer == 0) {
|
} else if (manga.viewer == 0) {
|
||||||
preferences.defaultViewer()
|
preferences.defaultViewer()
|
||||||
} else {
|
} else {
|
||||||
|
@ -10,7 +10,6 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
|||||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||||
import eu.kanade.tachiyomi.source.SourceManager
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
import eu.kanade.tachiyomi.source.model.toSManga
|
import eu.kanade.tachiyomi.source.model.toSManga
|
||||||
import eu.kanade.tachiyomi.util.lang.await
|
|
||||||
import exh.EH_SOURCE_ID
|
import exh.EH_SOURCE_ID
|
||||||
import exh.EXHMigrations
|
import exh.EXHMigrations
|
||||||
import exh.EXH_SOURCE_ID
|
import exh.EXH_SOURCE_ID
|
||||||
@ -18,7 +17,7 @@ import exh.eh.EHentaiThrottleManager
|
|||||||
import exh.eh.EHentaiUpdateWorker
|
import exh.eh.EHentaiUpdateWorker
|
||||||
import exh.metadata.metadata.EHentaiSearchMetadata
|
import exh.metadata.metadata.EHentaiSearchMetadata
|
||||||
import exh.metadata.metadata.base.getFlatMetadataForManga
|
import exh.metadata.metadata.base.getFlatMetadataForManga
|
||||||
import exh.metadata.metadata.base.insertFlatMetadata
|
import exh.metadata.metadata.base.insertFlatMetadataAsync
|
||||||
import exh.savedsearches.JsonSavedSearch
|
import exh.savedsearches.JsonSavedSearch
|
||||||
import exh.util.cancellable
|
import exh.util.cancellable
|
||||||
import exh.util.executeOnIO
|
import exh.util.executeOnIO
|
||||||
@ -64,7 +63,7 @@ object DebugFunctions {
|
|||||||
val meta = db.getFlatMetadataForManga(manga.id!!).executeAsBlocking()?.raise<EHentaiSearchMetadata>() ?: return@forEach
|
val meta = db.getFlatMetadataForManga(manga.id!!).executeAsBlocking()?.raise<EHentaiSearchMetadata>() ?: return@forEach
|
||||||
// remove age flag
|
// remove age flag
|
||||||
meta.aged = false
|
meta.aged = false
|
||||||
db.insertFlatMetadata(meta.flatten()).await()
|
db.insertFlatMetadataAsync(meta.flatten()).await()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,14 +19,13 @@ import eu.kanade.tachiyomi.source.model.toSChapter
|
|||||||
import eu.kanade.tachiyomi.source.model.toSManga
|
import eu.kanade.tachiyomi.source.model.toSManga
|
||||||
import eu.kanade.tachiyomi.source.online.all.EHentai
|
import eu.kanade.tachiyomi.source.online.all.EHentai
|
||||||
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
|
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
|
||||||
import eu.kanade.tachiyomi.util.lang.await
|
|
||||||
import exh.EH_SOURCE_ID
|
import exh.EH_SOURCE_ID
|
||||||
import exh.EXH_SOURCE_ID
|
import exh.EXH_SOURCE_ID
|
||||||
import exh.debug.DebugToggles
|
import exh.debug.DebugToggles
|
||||||
import exh.eh.EHentaiUpdateWorkerConstants.UPDATES_PER_ITERATION
|
import exh.eh.EHentaiUpdateWorkerConstants.UPDATES_PER_ITERATION
|
||||||
import exh.metadata.metadata.EHentaiSearchMetadata
|
import exh.metadata.metadata.EHentaiSearchMetadata
|
||||||
import exh.metadata.metadata.base.getFlatMetadataForManga
|
import exh.metadata.metadata.base.getFlatMetadataForManga
|
||||||
import exh.metadata.metadata.base.insertFlatMetadata
|
import exh.metadata.metadata.base.insertFlatMetadataAsync
|
||||||
import exh.util.cancellable
|
import exh.util.cancellable
|
||||||
import exh.util.executeOnIO
|
import exh.util.executeOnIO
|
||||||
import exh.util.jobScheduler
|
import exh.util.jobScheduler
|
||||||
@ -280,7 +279,7 @@ class EHentaiUpdateWorker : JobService(), CoroutineScope {
|
|||||||
// Age dead galleries
|
// Age dead galleries
|
||||||
logger.d("Aged %s - notfound", manga.id)
|
logger.d("Aged %s - notfound", manga.id)
|
||||||
meta.aged = true
|
meta.aged = true
|
||||||
db.insertFlatMetadata(meta.flatten()).await()
|
db.insertFlatMetadataAsync(meta.flatten()).await()
|
||||||
}
|
}
|
||||||
throw GalleryNotUpdatedException(false, t)
|
throw GalleryNotUpdatedException(false, t)
|
||||||
}
|
}
|
||||||
|
@ -10,10 +10,10 @@ import eu.kanade.tachiyomi.data.database.models.Category
|
|||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.data.database.models.MangaCategory
|
import eu.kanade.tachiyomi.data.database.models.MangaCategory
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
|
import eu.kanade.tachiyomi.network.POST
|
||||||
import eu.kanade.tachiyomi.network.await
|
import eu.kanade.tachiyomi.network.await
|
||||||
import eu.kanade.tachiyomi.source.SourceManager
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
import eu.kanade.tachiyomi.source.online.all.EHentai
|
import eu.kanade.tachiyomi.source.online.all.EHentai
|
||||||
import eu.kanade.tachiyomi.util.lang.await
|
|
||||||
import eu.kanade.tachiyomi.util.lang.launchUI
|
import eu.kanade.tachiyomi.util.lang.launchUI
|
||||||
import eu.kanade.tachiyomi.util.system.powerManager
|
import eu.kanade.tachiyomi.util.system.powerManager
|
||||||
import eu.kanade.tachiyomi.util.system.toast
|
import eu.kanade.tachiyomi.util.system.toast
|
||||||
@ -239,17 +239,15 @@ class FavoritesSyncHelper(val context: Context) {
|
|||||||
private suspend fun addGalleryRemote(errorList: MutableList<String>, gallery: FavoriteEntry) {
|
private suspend fun addGalleryRemote(errorList: MutableList<String>, gallery: FavoriteEntry) {
|
||||||
val url = "${exh.baseUrl}/gallerypopups.php?gid=${gallery.gid}&t=${gallery.token}&act=addfav"
|
val url = "${exh.baseUrl}/gallerypopups.php?gid=${gallery.gid}&t=${gallery.token}&act=addfav"
|
||||||
|
|
||||||
val request = Request.Builder()
|
val request = POST(
|
||||||
.url(url)
|
url = url,
|
||||||
.post(
|
body = FormBody.Builder()
|
||||||
FormBody.Builder()
|
.add("favcat", gallery.category.toString())
|
||||||
.add("favcat", gallery.category.toString())
|
.add("favnote", "")
|
||||||
.add("favnote", "")
|
.add("apply", "Add to Favorites")
|
||||||
.add("apply", "Add to Favorites")
|
.add("update", "1")
|
||||||
.add("update", "1")
|
.build()
|
||||||
.build()
|
)
|
||||||
)
|
|
||||||
.build()
|
|
||||||
|
|
||||||
if (!explicitlyRetryExhRequest(10, request)) {
|
if (!explicitlyRetryExhRequest(10, request)) {
|
||||||
val errorString = "Unable to add gallery to remote server: '${gallery.title}' (GID: ${gallery.gid})!"
|
val errorString = "Unable to add gallery to remote server: '${gallery.title}' (GID: ${gallery.gid})!"
|
||||||
@ -296,10 +294,10 @@ class FavoritesSyncHelper(val context: Context) {
|
|||||||
formBody.add("modifygids[]", it.gid)
|
formBody.add("modifygids[]", it.gid)
|
||||||
}
|
}
|
||||||
|
|
||||||
val request = Request.Builder()
|
val request = POST(
|
||||||
.url("https://exhentai.org/favorites.php")
|
url = "https://exhentai.org/favorites.php",
|
||||||
.post(formBody.build())
|
body = formBody.build()
|
||||||
.build()
|
)
|
||||||
|
|
||||||
if (!explicitlyRetryExhRequest(10, request)) {
|
if (!explicitlyRetryExhRequest(10, request)) {
|
||||||
val errorString = context.getString(R.string.favorites_sync_unable_to_delete)
|
val errorString = context.getString(R.string.favorites_sync_unable_to_delete)
|
||||||
@ -408,8 +406,8 @@ class FavoritesSyncHelper(val context: Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Can't do too many DB OPs in one go
|
// Can't do too many DB OPs in one go
|
||||||
insertedMangaCategories.chunked(10).map {
|
insertedMangaCategories.chunked(10).map { mangaCategories ->
|
||||||
Pair(it.map { it.first }, it.map { it.second })
|
mangaCategories.map { it.first } to mangaCategories.map { it.second }
|
||||||
}.forEach {
|
}.forEach {
|
||||||
db.setMangaCategories(it.first, it.second)
|
db.setMangaCategories(it.first, it.second)
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,8 @@ import exh.metadata.metadata.MangaDexSearchMetadata
|
|||||||
import exh.metadata.metadata.base.RaisedTag
|
import exh.metadata.metadata.base.RaisedTag
|
||||||
import exh.metadata.metadata.base.getFlatMetadataForManga
|
import exh.metadata.metadata.base.getFlatMetadataForManga
|
||||||
import exh.metadata.metadata.base.insertFlatMetadata
|
import exh.metadata.metadata.base.insertFlatMetadata
|
||||||
import exh.util.await
|
import exh.metadata.metadata.base.insertFlatMetadataAsync
|
||||||
|
import exh.util.executeOnIO
|
||||||
import exh.util.floor
|
import exh.util.floor
|
||||||
import exh.util.nullIfZero
|
import exh.util.nullIfZero
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
@ -70,16 +71,16 @@ class ApiMangaParser(private val lang: String) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
suspend fun parseToManga(manga: MangaInfo, input: Response, coverUrls: List<String>, sourceId: Long): MangaInfo {
|
suspend fun parseToManga(manga: MangaInfo, input: Response, coverUrls: List<String>, sourceId: Long): MangaInfo {
|
||||||
val mangaId = db.getManga(manga.key, sourceId).await()?.id
|
val mangaId = db.getManga(manga.key, sourceId).executeOnIO()?.id
|
||||||
val metadata = if (mangaId != null) {
|
val metadata = if (mangaId != null) {
|
||||||
val flatMetadata = db.getFlatMetadataForManga(mangaId).await()
|
val flatMetadata = db.getFlatMetadataForManga(mangaId).executeOnIO()
|
||||||
flatMetadata?.raise(metaClass) ?: newMetaInstance()
|
flatMetadata?.raise(metaClass) ?: newMetaInstance()
|
||||||
} else newMetaInstance()
|
} else newMetaInstance()
|
||||||
|
|
||||||
parseInfoIntoMetadata(metadata, input, coverUrls)
|
parseInfoIntoMetadata(metadata, input, coverUrls)
|
||||||
if (mangaId != null) {
|
if (mangaId != null) {
|
||||||
metadata.mangaId = mangaId
|
metadata.mangaId = mangaId
|
||||||
db.insertFlatMetadata(metadata.flatten()).await()
|
db.insertFlatMetadataAsync(metadata.flatten()).await()
|
||||||
}
|
}
|
||||||
|
|
||||||
return metadata.createMangaInfo(manga)
|
return metadata.createMangaInfo(manga)
|
||||||
|
@ -5,9 +5,12 @@ import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
|||||||
import exh.metadata.sql.models.SearchMetadata
|
import exh.metadata.sql.models.SearchMetadata
|
||||||
import exh.metadata.sql.models.SearchTag
|
import exh.metadata.sql.models.SearchTag
|
||||||
import exh.metadata.sql.models.SearchTitle
|
import exh.metadata.sql.models.SearchTitle
|
||||||
|
import exh.util.executeOnIO
|
||||||
|
import kotlinx.coroutines.Deferred
|
||||||
|
import kotlinx.coroutines.async
|
||||||
|
import kotlinx.coroutines.coroutineScope
|
||||||
import kotlinx.serialization.InternalSerializationApi
|
import kotlinx.serialization.InternalSerializationApi
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.decodeFromString
|
|
||||||
import kotlinx.serialization.serializer
|
import kotlinx.serialization.serializer
|
||||||
import rx.Completable
|
import rx.Completable
|
||||||
import rx.Single
|
import rx.Single
|
||||||
@ -99,3 +102,15 @@ fun DatabaseHelper.insertFlatMetadata(flatMetadata: FlatMetadata): Completable =
|
|||||||
setSearchTitlesForManga(flatMetadata.metadata.mangaId, flatMetadata.titles)
|
setSearchTitlesForManga(flatMetadata.metadata.mangaId, flatMetadata.titles)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun DatabaseHelper.insertFlatMetadataAsync(flatMetadata: FlatMetadata): Deferred<Unit> = coroutineScope {
|
||||||
|
async {
|
||||||
|
require(flatMetadata.metadata.mangaId != -1L)
|
||||||
|
|
||||||
|
inTransaction {
|
||||||
|
insertSearchMetadata(flatMetadata.metadata).executeOnIO()
|
||||||
|
setSearchTagsForManga(flatMetadata.metadata.mangaId, flatMetadata.tags)
|
||||||
|
setSearchTitlesForManga(flatMetadata.metadata.mangaId, flatMetadata.titles)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -5,7 +5,6 @@ import eu.kanade.tachiyomi.data.database.models.Manga
|
|||||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||||
import eu.kanade.tachiyomi.source.model.FilterList
|
import eu.kanade.tachiyomi.source.model.FilterList
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import eu.kanade.tachiyomi.util.lang.await
|
|
||||||
import eu.kanade.tachiyomi.util.lang.awaitSingle
|
import eu.kanade.tachiyomi.util.lang.awaitSingle
|
||||||
import exh.util.executeOnIO
|
import exh.util.executeOnIO
|
||||||
import info.debatty.java.stringsimilarity.NormalizedLevenshtein
|
import info.debatty.java.stringsimilarity.NormalizedLevenshtein
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
package exh.util
|
package exh.util
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.injectLazy
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
|
|
||||||
class DataSaver {
|
object DataSaver {
|
||||||
private val preferences: PreferencesHelper = Injekt.get()
|
private val preferences: PreferencesHelper by injectLazy()
|
||||||
|
|
||||||
fun compress(imageUrl: String): String {
|
fun compress(imageUrl: String): String {
|
||||||
return if (preferences.dataSaver().get() && preferences.dataSaverServer().get().isNotBlank() && !imageUrl.contains(preferences.dataSaverServer().get() + "/?")) {
|
return if (preferences.dataSaver().get() && preferences.dataSaverServer().get().isNotBlank() && !imageUrl.contains(preferences.dataSaverServer().get() + "/?")) {
|
||||||
@ -20,10 +19,10 @@ class DataSaver {
|
|||||||
private fun getUrl(imageUrl: String): String {
|
private fun getUrl(imageUrl: String): String {
|
||||||
val server = preferences.dataSaverServer().get() + "/?"
|
val server = preferences.dataSaverServer().get() + "/?"
|
||||||
val format = "jpg=${if (preferences.dataSaverImageFormatJpeg().get()) "1" else "0"}"
|
val format = "jpg=${if (preferences.dataSaverImageFormatJpeg().get()) "1" else "0"}"
|
||||||
val quality = "&l=${preferences.dataSaverImageQuality().get()}"
|
val quality = "l=${preferences.dataSaverImageQuality().get()}"
|
||||||
val colorBW = "&bw=${if (preferences.dataSaverColorBW().get()) "1" else "0"}"
|
val colorBW = "bw=${if (preferences.dataSaverColorBW().get()) "1" else "0"}"
|
||||||
val url = "$server$format$quality$colorBW&url="
|
val url = "url=$imageUrl"
|
||||||
|
|
||||||
return url + imageUrl
|
return "$server&$format&$quality&$colorBW&$url"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package exh.util
|
package exh.util
|
||||||
|
|
||||||
|
import com.pushtorefresh.storio.operations.PreparedOperation
|
||||||
import com.pushtorefresh.storio.sqlite.operations.get.PreparedGetListOfObjects
|
import com.pushtorefresh.storio.sqlite.operations.get.PreparedGetListOfObjects
|
||||||
import com.pushtorefresh.storio.sqlite.operations.get.PreparedGetObject
|
import com.pushtorefresh.storio.sqlite.operations.get.PreparedGetObject
|
||||||
import com.pushtorefresh.storio.sqlite.operations.put.PreparedPutCollectionOfObjects
|
import com.pushtorefresh.storio.sqlite.operations.put.PreparedPutCollectionOfObjects
|
||||||
@ -16,3 +17,5 @@ suspend fun <T> PreparedGetObject<T>.executeOnIO(): T? = withContext(Dispatchers
|
|||||||
suspend fun <T> PreparedPutObject<T>.executeOnIO(): PutResult = withContext(Dispatchers.IO) { executeAsBlocking() }
|
suspend fun <T> PreparedPutObject<T>.executeOnIO(): PutResult = withContext(Dispatchers.IO) { executeAsBlocking() }
|
||||||
|
|
||||||
suspend fun <T> PreparedPutCollectionOfObjects<T>.executeOnIO(): PutResults<T> = withContext(Dispatchers.IO) { executeAsBlocking() }
|
suspend fun <T> PreparedPutCollectionOfObjects<T>.executeOnIO(): PutResults<T> = withContext(Dispatchers.IO) { executeAsBlocking() }
|
||||||
|
|
||||||
|
suspend fun <T> PreparedOperation<T>.executeOnIO(): T? = withContext(Dispatchers.IO) { executeAsBlocking() }
|
||||||
|
@ -1,176 +0,0 @@
|
|||||||
package exh.util
|
|
||||||
|
|
||||||
// Zero-allocation-overhead mutable collection shims
|
|
||||||
|
|
||||||
private inline class CollectionShim<E>(private val coll: Collection<E>) : FakeMutableCollection<E> {
|
|
||||||
override val size: Int get() = coll.size
|
|
||||||
|
|
||||||
override fun contains(element: E) = coll.contains(element)
|
|
||||||
|
|
||||||
override fun containsAll(elements: Collection<E>) = coll.containsAll(elements)
|
|
||||||
|
|
||||||
override fun isEmpty() = coll.isEmpty()
|
|
||||||
|
|
||||||
override fun fakeIterator() = coll.iterator()
|
|
||||||
}
|
|
||||||
|
|
||||||
interface FakeMutableCollection<E> : MutableCollection<E>, FakeMutableIterable<E> {
|
|
||||||
override fun add(element: E): Boolean {
|
|
||||||
throw UnsupportedOperationException("This collection is immutable!")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun addAll(elements: Collection<E>): Boolean {
|
|
||||||
throw UnsupportedOperationException("This collection is immutable!")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun clear() {
|
|
||||||
throw UnsupportedOperationException("This collection is immutable!")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun remove(element: E): Boolean {
|
|
||||||
throw UnsupportedOperationException("This collection is immutable!")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun removeAll(elements: Collection<E>): Boolean {
|
|
||||||
throw UnsupportedOperationException("This collection is immutable!")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun retainAll(elements: Collection<E>): Boolean {
|
|
||||||
throw UnsupportedOperationException("This collection is immutable!")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun iterator(): MutableIterator<E> = super.iterator()
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun <E> fromCollection(coll: Collection<E>): FakeMutableCollection<E> = CollectionShim(coll)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private inline class SetShim<E>(private val set: Set<E>) : FakeMutableSet<E> {
|
|
||||||
override val size: Int get() = set.size
|
|
||||||
|
|
||||||
override fun contains(element: E) = set.contains(element)
|
|
||||||
|
|
||||||
override fun containsAll(elements: Collection<E>) = set.containsAll(elements)
|
|
||||||
|
|
||||||
override fun isEmpty() = set.isEmpty()
|
|
||||||
|
|
||||||
override fun fakeIterator() = set.iterator()
|
|
||||||
}
|
|
||||||
|
|
||||||
interface FakeMutableSet<E> : MutableSet<E>, FakeMutableCollection<E> {
|
|
||||||
/**
|
|
||||||
* Adds the specified element to the set.
|
|
||||||
*
|
|
||||||
* @return `true` if the element has been added, `false` if the element is already contained in the set.
|
|
||||||
*/
|
|
||||||
override fun add(element: E): Boolean = super.add(element)
|
|
||||||
|
|
||||||
override fun addAll(elements: Collection<E>): Boolean = super.addAll(elements)
|
|
||||||
|
|
||||||
override fun clear() = super.clear()
|
|
||||||
|
|
||||||
override fun remove(element: E): Boolean = super.remove(element)
|
|
||||||
|
|
||||||
override fun removeAll(elements: Collection<E>): Boolean = super.removeAll(elements)
|
|
||||||
|
|
||||||
override fun retainAll(elements: Collection<E>): Boolean = super.retainAll(elements)
|
|
||||||
|
|
||||||
override fun iterator(): MutableIterator<E> = super.iterator()
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun <E> fromSet(set: Set<E>): FakeMutableSet<E> = SetShim(set)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private inline class IterableShim<E>(private val iterable: Iterable<E>) : FakeMutableIterable<E> {
|
|
||||||
override fun fakeIterator() = iterable.iterator()
|
|
||||||
}
|
|
||||||
|
|
||||||
interface FakeMutableIterable<E> : MutableIterable<E> {
|
|
||||||
/**
|
|
||||||
* Returns an iterator over the elements of this sequence that supports removing elements during iteration.
|
|
||||||
*/
|
|
||||||
override fun iterator(): MutableIterator<E> = FakeMutableIterator.fromIterator(fakeIterator())
|
|
||||||
|
|
||||||
fun fakeIterator(): Iterator<E>
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun <E> fromIterable(iterable: Iterable<E>): FakeMutableIterable<E> = IterableShim(iterable)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private inline class IteratorShim<E>(private val iterator: Iterator<E>) : FakeMutableIterator<E> {
|
|
||||||
/**
|
|
||||||
* Returns `true` if the iteration has more elements.
|
|
||||||
*/
|
|
||||||
override fun hasNext() = iterator.hasNext()
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the next element in the iteration.
|
|
||||||
*/
|
|
||||||
override fun next() = iterator.next()
|
|
||||||
}
|
|
||||||
|
|
||||||
interface FakeMutableIterator<E> : MutableIterator<E> {
|
|
||||||
/**
|
|
||||||
* Removes from the underlying collection the last element returned by this iterator.
|
|
||||||
*/
|
|
||||||
override fun remove() {
|
|
||||||
throw UnsupportedOperationException("This set is immutable!")
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun <E> fromIterator(iterator: Iterator<E>): FakeMutableIterator<E> = IteratorShim(iterator)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private inline class EntryShim<K, V>(private val entry: Map.Entry<K, V>) : FakeMutableEntry<K, V> {
|
|
||||||
/**
|
|
||||||
* Returns the key of this key/value pair.
|
|
||||||
*/
|
|
||||||
override val key: K
|
|
||||||
get() = entry.key
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the value of this key/value pair.
|
|
||||||
*/
|
|
||||||
override val value: V
|
|
||||||
get() = entry.value
|
|
||||||
}
|
|
||||||
|
|
||||||
private inline class PairShim<K, V>(private val pair: Pair<K, V>) : FakeMutableEntry<K, V> {
|
|
||||||
/**
|
|
||||||
* Returns the key of this key/value pair.
|
|
||||||
*/
|
|
||||||
override val key: K get() = pair.first
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the value of this key/value pair.
|
|
||||||
*/
|
|
||||||
override val value: V get() = pair.second
|
|
||||||
}
|
|
||||||
|
|
||||||
interface FakeMutableEntry<K, V> : MutableMap.MutableEntry<K, V> {
|
|
||||||
override fun setValue(newValue: V): V {
|
|
||||||
throw UnsupportedOperationException("This entry is immutable!")
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun <K, V> fromEntry(entry: Map.Entry<K, V>): FakeMutableEntry<K, V> = EntryShim(entry)
|
|
||||||
|
|
||||||
fun <K, V> fromPair(pair: Pair<K, V>): FakeMutableEntry<K, V> = PairShim(pair)
|
|
||||||
|
|
||||||
fun <K, V> fromPair(key: K, value: V) = object : FakeMutableEntry<K, V> {
|
|
||||||
/**
|
|
||||||
* Returns the key of this key/value pair.
|
|
||||||
*/
|
|
||||||
override val key: K = key
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the value of this key/value pair.
|
|
||||||
*/
|
|
||||||
override val value: V = value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -24,21 +24,27 @@ fun Manga.mangaType(context: Context): String {
|
|||||||
/**
|
/**
|
||||||
* The type of comic the manga is (ie. manga, manhwa, manhua)
|
* The type of comic the manga is (ie. manga, manhwa, manhua)
|
||||||
*/
|
*/
|
||||||
fun Manga.mangaType(): MangaType {
|
fun Manga.mangaType(sourceName: String = Injekt.get<SourceManager>().getOrStub(source).name): MangaType {
|
||||||
val sourceName = Injekt.get<SourceManager>().getOrStub(source).name
|
|
||||||
val currentTags = getGenres().orEmpty()
|
val currentTags = getGenres().orEmpty()
|
||||||
return if (currentTags.any { tag -> isMangaTag(tag) }) {
|
return when {
|
||||||
MangaType.TYPE_MANGA
|
currentTags.any { tag -> isMangaTag(tag) } -> {
|
||||||
} else if (currentTags.any { tag -> isWebtoonTag(tag) } || isWebtoonSource(sourceName)) {
|
MangaType.TYPE_MANGA
|
||||||
MangaType.TYPE_WEBTOON
|
}
|
||||||
} else if (currentTags.any { tag -> isComicTag(tag) } || isComicSource(sourceName)) {
|
currentTags.any { tag -> isWebtoonTag(tag) } || isWebtoonSource(sourceName) -> {
|
||||||
MangaType.TYPE_COMIC
|
MangaType.TYPE_WEBTOON
|
||||||
} else if (currentTags.any { tag -> isManhuaTag(tag) } || isManhuaSource(sourceName)) {
|
}
|
||||||
MangaType.TYPE_MANHUA
|
currentTags.any { tag -> isComicTag(tag) } || isComicSource(sourceName) -> {
|
||||||
} else if (currentTags.any { tag -> isManhwaTag(tag) } || isManhwaSource(sourceName)) {
|
MangaType.TYPE_COMIC
|
||||||
MangaType.TYPE_MANHWA
|
}
|
||||||
} else {
|
currentTags.any { tag -> isManhuaTag(tag) } || isManhuaSource(sourceName) -> {
|
||||||
MangaType.TYPE_MANGA
|
MangaType.TYPE_MANHUA
|
||||||
|
}
|
||||||
|
currentTags.any { tag -> isManhwaTag(tag) } || isManhwaSource(sourceName) -> {
|
||||||
|
MangaType.TYPE_MANHWA
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
MangaType.TYPE_MANGA
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,8 +52,7 @@ fun Manga.mangaType(): MangaType {
|
|||||||
* The type the reader should use. Different from manga type as certain manga has different
|
* The type the reader should use. Different from manga type as certain manga has different
|
||||||
* read types
|
* read types
|
||||||
*/
|
*/
|
||||||
fun Manga.defaultReaderType(): Int? {
|
fun Manga.defaultReaderType(type: MangaType = mangaType()): Int? {
|
||||||
val type = mangaType()
|
|
||||||
return if (type == MangaType.TYPE_MANHWA || type == MangaType.TYPE_WEBTOON) {
|
return if (type == MangaType.TYPE_MANHWA || type == MangaType.TYPE_WEBTOON) {
|
||||||
ReaderActivity.WEBTOON
|
ReaderActivity.WEBTOON
|
||||||
} else null
|
} else null
|
||||||
|
@ -1,32 +1,8 @@
|
|||||||
package exh.util
|
package exh.util
|
||||||
|
|
||||||
import com.pushtorefresh.storio.operations.PreparedOperation
|
|
||||||
import com.pushtorefresh.storio.sqlite.operations.get.PreparedGetObject
|
|
||||||
import kotlinx.coroutines.CancellableContinuation
|
|
||||||
import kotlinx.coroutines.CancellationException
|
|
||||||
import kotlinx.coroutines.CoroutineStart
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.GlobalScope
|
|
||||||
import kotlinx.coroutines.InternalCoroutinesApi
|
|
||||||
import kotlinx.coroutines.channels.awaitClose
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
|
||||||
import kotlinx.coroutines.flow.callbackFlow
|
|
||||||
import kotlinx.coroutines.flow.collect
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
|
||||||
import rx.Completable
|
|
||||||
import rx.CompletableSubscriber
|
|
||||||
import rx.Emitter
|
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import rx.Observer
|
|
||||||
import rx.Scheduler
|
|
||||||
import rx.Single
|
import rx.Single
|
||||||
import rx.SingleSubscriber
|
|
||||||
import rx.Subscriber
|
|
||||||
import rx.Subscription
|
|
||||||
import rx.subjects.ReplaySubject
|
import rx.subjects.ReplaySubject
|
||||||
import kotlin.coroutines.resume
|
|
||||||
import kotlin.coroutines.resumeWithException
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transform a cold single to a hot single
|
* Transform a cold single to a hot single
|
||||||
@ -49,7 +25,7 @@ fun <T> Observable<T>.melt(): Observable<T> {
|
|||||||
subscribe(rs)
|
subscribe(rs)
|
||||||
return rs
|
return rs
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
suspend fun <T> Single<T>.await(subscribeOn: Scheduler? = null): T {
|
suspend fun <T> Single<T>.await(subscribeOn: Scheduler? = null): T {
|
||||||
return suspendCancellableCoroutine { continuation ->
|
return suspendCancellableCoroutine { continuation ->
|
||||||
val self = if (subscribeOn != null) subscribeOn(subscribeOn) else this
|
val self = if (subscribeOn != null) subscribeOn(subscribeOn) else this
|
||||||
@ -181,11 +157,11 @@ private suspend fun <T> Observable<T>.awaitOne(): T = suspendCancellableCoroutin
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onError(e: Throwable) {
|
override fun onError(e: Throwable) {
|
||||||
/*
|
*//*
|
||||||
* Rx1 observable throws NoSuchElementException if cancellation happened before
|
* Rx1 observable throws NoSuchElementException if cancellation happened before
|
||||||
* element emission. To mitigate this we try to atomically resume continuation with exception:
|
* element emission. To mitigate this we try to atomically resume continuation with exception:
|
||||||
* if resume failed, then we know that continuation successfully cancelled itself
|
* if resume failed, then we know that continuation successfully cancelled itself
|
||||||
*/
|
*//*
|
||||||
val token = cont.tryResumeWithException(e)
|
val token = cont.tryResumeWithException(e)
|
||||||
if (token != null) {
|
if (token != null) {
|
||||||
cont.completeResume(token)
|
cont.completeResume(token)
|
||||||
@ -220,10 +196,10 @@ fun <T : Any> Observable<T>.asFlow(): Flow<T> = callbackFlow {
|
|||||||
fun <T : Any> Flow<T>.asObservable(backpressureMode: Emitter.BackpressureMode = Emitter.BackpressureMode.NONE): Observable<T> {
|
fun <T : Any> Flow<T>.asObservable(backpressureMode: Emitter.BackpressureMode = Emitter.BackpressureMode.NONE): Observable<T> {
|
||||||
return Observable.create(
|
return Observable.create(
|
||||||
{ emitter ->
|
{ emitter ->
|
||||||
/*
|
*//*
|
||||||
* ATOMIC is used here to provide stable behaviour of subscribe+dispose pair even if
|
* ATOMIC is used here to provide stable behaviour of subscribe+dispose pair even if
|
||||||
* asObservable is already invoked from unconfined
|
* asObservable is already invoked from unconfined
|
||||||
*/
|
*//*
|
||||||
val job = GlobalScope.launch(Dispatchers.Unconfined, start = CoroutineStart.ATOMIC) {
|
val job = GlobalScope.launch(Dispatchers.Unconfined, start = CoroutineStart.ATOMIC) {
|
||||||
try {
|
try {
|
||||||
collect { emitter.onNext(it) }
|
collect { emitter.onNext(it) }
|
||||||
@ -241,4 +217,4 @@ fun <T : Any> Flow<T>.asObservable(backpressureMode: Emitter.BackpressureMode =
|
|||||||
},
|
},
|
||||||
backpressureMode
|
backpressureMode
|
||||||
)
|
)
|
||||||
}
|
}*/
|
||||||
|
@ -23,13 +23,11 @@ fun UrlImportableSource.urlImportFetchSearchManga(context: Context, query: Strin
|
|||||||
})
|
})
|
||||||
.map { res ->
|
.map { res ->
|
||||||
MangasPage(
|
MangasPage(
|
||||||
(
|
if (res is GalleryAddEvent.Success) {
|
||||||
if (res is GalleryAddEvent.Success) {
|
listOf(res.manga)
|
||||||
listOf(res.manga)
|
} else {
|
||||||
} else {
|
emptyList()
|
||||||
emptyList()
|
},
|
||||||
}
|
|
||||||
),
|
|
||||||
false
|
false
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user