mirror of
https://github.com/mihonapp/mihon.git
synced 2025-06-30 04:57:50 +02:00
Finish auto-migration feature
This commit is contained in:
@ -165,6 +165,16 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
|
||||
|
||||
subscriptions += controller.selectionRelay
|
||||
.subscribe { onSelectionChanged(it) }
|
||||
|
||||
subscriptions += controller.selectAllRelay
|
||||
.subscribe {
|
||||
if (it == category.id) {
|
||||
adapter.currentItems.forEach { item ->
|
||||
controller.setSelection(item.manga, true)
|
||||
}
|
||||
controller.invalidateActionMode()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun onRecycle() {
|
||||
|
@ -99,6 +99,8 @@ class LibraryController(
|
||||
*/
|
||||
val libraryMangaRelay: BehaviorRelay<LibraryMangaEvent> = BehaviorRelay.create()
|
||||
|
||||
val selectAllRelay: PublishRelay<Int> = PublishRelay.create()
|
||||
|
||||
/**
|
||||
* Number of manga per row in grid mode.
|
||||
*/
|
||||
@ -436,6 +438,9 @@ class LibraryController(
|
||||
}
|
||||
R.id.action_move_to_category -> showChangeMangaCategoriesDialog()
|
||||
R.id.action_delete -> showDeleteMangaDialog()
|
||||
R.id.action_select_all -> {
|
||||
selectAllRelay.call(activeCategory)
|
||||
}
|
||||
R.id.action_auto_source_migration -> {
|
||||
router.pushController(MigrationDesignController.create(
|
||||
selectedMangas.mapNotNull { it.id }
|
||||
|
@ -13,7 +13,8 @@ import rx.schedulers.Schedulers
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class SmartSearchEngine(parentContext: CoroutineContext): CoroutineScope {
|
||||
class SmartSearchEngine(parentContext: CoroutineContext,
|
||||
val extraSearchParams: String? = null): CoroutineScope {
|
||||
override val coroutineContext: CoroutineContext = parentContext + Job() + Dispatchers.Default
|
||||
|
||||
private val db: DatabaseHelper by injectLazy()
|
||||
@ -26,7 +27,11 @@ class SmartSearchEngine(parentContext: CoroutineContext): CoroutineScope {
|
||||
val eligibleManga = supervisorScope {
|
||||
queries.map { query ->
|
||||
async(Dispatchers.Default) {
|
||||
val searchResults = source.fetchSearchManga(1, query, FilterList()).toSingle().await(Schedulers.io())
|
||||
val builtQuery = if(extraSearchParams != null) {
|
||||
"$query ${extraSearchParams.trim()}"
|
||||
} else title
|
||||
|
||||
val searchResults = source.fetchSearchManga(1, builtQuery, FilterList()).toSingle().await(Schedulers.io())
|
||||
|
||||
searchResults.mangas.map {
|
||||
val cleanedMangaTitle = cleanSmartSearchTitle(it.title)
|
||||
@ -44,7 +49,10 @@ class SmartSearchEngine(parentContext: CoroutineContext): CoroutineScope {
|
||||
|
||||
suspend fun normalSearch(source: CatalogueSource, title: String): SManga? {
|
||||
val eligibleManga = supervisorScope {
|
||||
val searchResults = source.fetchSearchManga(1, title, FilterList()).toSingle().await(Schedulers.io())
|
||||
val searchQuery = if(extraSearchParams != null) {
|
||||
"$title ${extraSearchParams.trim()}"
|
||||
} else title
|
||||
val searchResults = source.fetchSearchManga(1, searchQuery, FilterList()).toSingle().await(Schedulers.io())
|
||||
|
||||
searchResults.mangas.map {
|
||||
val normalizedDistance = NormalizedLevenshtein().similarity(title, it.title)
|
||||
@ -80,7 +88,7 @@ class SmartSearchEngine(parentContext: CoroutineContext): CoroutineScope {
|
||||
)
|
||||
|
||||
return searchQueries.map {
|
||||
it.joinToString().trim()
|
||||
it.joinToString(" ").trim()
|
||||
}.distinct()
|
||||
}
|
||||
|
||||
@ -167,8 +175,8 @@ class SmartSearchEngine(parentContext: CoroutineContext): CoroutineScope {
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val MIN_SMART_ELIGIBLE_THRESHOLD = 0.7
|
||||
const val MIN_NORMAL_ELIGIBLE_THRESHOLD = 0.5
|
||||
const val MIN_SMART_ELIGIBLE_THRESHOLD = 0.4
|
||||
const val MIN_NORMAL_ELIGIBLE_THRESHOLD = 0.4
|
||||
|
||||
private val titleRegex = Regex("[^a-zA-Z0-9- ]")
|
||||
private val consecutiveSpacesRegex = Regex(" +")
|
||||
|
@ -11,13 +11,14 @@ import eu.kanade.tachiyomi.source.SourceManager
|
||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
||||
import eu.kanade.tachiyomi.ui.migration.MigrationFlags
|
||||
import eu.kanade.tachiyomi.util.gone
|
||||
import eu.kanade.tachiyomi.util.visible
|
||||
import exh.ui.base.BaseExhController
|
||||
import exh.ui.migration.manga.process.MigrationProcedureConfig
|
||||
import exh.ui.migration.manga.process.MigrationProcedureController
|
||||
import kotlinx.android.synthetic.main.eh_migration_design.*
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
// TODO Handle config changes
|
||||
// TODO Select all in library
|
||||
class MigrationDesignController(bundle: Bundle? = null) : BaseExhController(bundle), FlexibleAdapter.OnItemClickListener {
|
||||
private val sourceManager: SourceManager by injectLazy()
|
||||
@ -29,6 +30,8 @@ class MigrationDesignController(bundle: Bundle? = null) : BaseExhController(bund
|
||||
|
||||
private val config: LongArray = args.getLongArray(MANGA_IDS_EXTRA) ?: LongArray(0)
|
||||
|
||||
private var showingOptions = false
|
||||
|
||||
override fun getTitle() = "Select target sources"
|
||||
|
||||
override fun onViewCreated(view: View) {
|
||||
@ -53,13 +56,33 @@ class MigrationDesignController(bundle: Bundle? = null) : BaseExhController(bund
|
||||
use_smart_search.toggle()
|
||||
}
|
||||
|
||||
copy_manga_desc.setOnClickListener {
|
||||
copy_manga.toggle()
|
||||
}
|
||||
|
||||
extra_search_param_desc.setOnClickListener {
|
||||
extra_search_param.toggle()
|
||||
}
|
||||
|
||||
prioritize_chapter_count.setOnCheckedChangeListener { _, b ->
|
||||
updatePrioritizeChapterCount(b)
|
||||
}
|
||||
|
||||
extra_search_param.setOnCheckedChangeListener { _, b ->
|
||||
updateOptionsState()
|
||||
}
|
||||
|
||||
updatePrioritizeChapterCount(prioritize_chapter_count.isChecked)
|
||||
|
||||
updateOptionsState()
|
||||
|
||||
begin_migration_btn.setOnClickListener {
|
||||
if(!showingOptions) {
|
||||
showingOptions = true
|
||||
updateOptionsState()
|
||||
return@setOnClickListener
|
||||
}
|
||||
|
||||
var flags = 0
|
||||
if(mig_chapters.isChecked) flags = flags or MigrationFlags.CHAPTERS
|
||||
if(mig_categories.isChecked) flags = flags or MigrationFlags.CATEGORIES
|
||||
@ -73,12 +96,41 @@ class MigrationDesignController(bundle: Bundle? = null) : BaseExhController(bund
|
||||
}.map { it.source.id },
|
||||
useSourceWithMostChapters = prioritize_chapter_count.isChecked,
|
||||
enableLenientSearch = use_smart_search.isChecked,
|
||||
migrationFlags = flags
|
||||
migrationFlags = flags,
|
||||
copy = copy_manga.isChecked,
|
||||
extraSearchParams = if(extra_search_param.isChecked && extra_search_param_text.text.isNotBlank()) {
|
||||
extra_search_param_text.text.toString()
|
||||
} else null
|
||||
)
|
||||
).withFadeTransaction())
|
||||
}
|
||||
}
|
||||
|
||||
fun updateOptionsState() {
|
||||
if (showingOptions) {
|
||||
begin_migration_btn.text = "Begin migration"
|
||||
options_group.visible()
|
||||
if(extra_search_param.isChecked) {
|
||||
extra_search_param_text.visible()
|
||||
} else {
|
||||
extra_search_param_text.gone()
|
||||
}
|
||||
} else {
|
||||
begin_migration_btn.text = "Next step"
|
||||
options_group.gone()
|
||||
extra_search_param_text.gone()
|
||||
}
|
||||
}
|
||||
|
||||
override fun handleBack(): Boolean {
|
||||
if(showingOptions) {
|
||||
showingOptions = false
|
||||
updateOptionsState()
|
||||
return true
|
||||
}
|
||||
return super.handleBack()
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
super.onSaveInstanceState(outState)
|
||||
adapter?.onSaveInstanceState(outState)
|
||||
@ -92,9 +144,9 @@ class MigrationDesignController(bundle: Bundle? = null) : BaseExhController(bund
|
||||
|
||||
private fun updatePrioritizeChapterCount(migrationMode: Boolean) {
|
||||
migration_mode.text = if(migrationMode) {
|
||||
"Use the source with the most chapters and use the above list to break ties (slow with many sources or smart search)"
|
||||
"Currently using the source with the most chapters and the above list to break ties (slow with many sources or smart search)"
|
||||
} else {
|
||||
"Use the first source in the list that has the manga"
|
||||
"Currently using the first source in the list that has the manga"
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,11 +7,7 @@ import eu.kanade.tachiyomi.source.SourceManager
|
||||
import exh.util.DeferredField
|
||||
import exh.util.await
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.channels.BroadcastChannel
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.channels.ConflatedBroadcastChannel
|
||||
import kotlinx.coroutines.channels.ReceiveChannel
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class MigratingManga(private val db: DatabaseHelper,
|
||||
|
@ -4,28 +4,22 @@ import android.support.v4.view.PagerAdapter
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
||||
import com.elvishew.xlog.XLog
|
||||
import com.google.gson.Gson
|
||||
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.database.models.MangaCategory
|
||||
import eu.kanade.tachiyomi.data.glide.GlideApp
|
||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.source.online.all.MergedSource
|
||||
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||
import eu.kanade.tachiyomi.ui.manga.info.MangaInfoController
|
||||
import eu.kanade.tachiyomi.ui.migration.MigrationFlags
|
||||
import eu.kanade.tachiyomi.util.gone
|
||||
import eu.kanade.tachiyomi.util.inflate
|
||||
import eu.kanade.tachiyomi.util.syncChaptersWithSource
|
||||
import eu.kanade.tachiyomi.util.visible
|
||||
import eu.kanade.tachiyomi.util.*
|
||||
import exh.MERGED_SOURCE_ID
|
||||
import exh.debug.DebugFunctions.sourceManager
|
||||
import exh.util.await
|
||||
import kotlinx.android.synthetic.main.eh_manga_card.view.*
|
||||
import kotlinx.android.synthetic.main.eh_migration_process_item.view.*
|
||||
@ -33,6 +27,9 @@ import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.asFlow
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.text.DateFormat
|
||||
import java.text.DecimalFormat
|
||||
import java.util.*
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class MigrationProcedureAdapter(val controller: MigrationProcedureController,
|
||||
@ -42,6 +39,8 @@ class MigrationProcedureAdapter(val controller: MigrationProcedureController,
|
||||
private val gson: Gson by injectLazy()
|
||||
private val sourceManager: SourceManager by injectLazy()
|
||||
|
||||
private val logger = XLog.tag(this::class.simpleName)
|
||||
|
||||
override fun isViewFromObject(p0: View, p1: Any): Boolean {
|
||||
return p0 == p1
|
||||
}
|
||||
@ -57,34 +56,51 @@ class MigrationProcedureAdapter(val controller: MigrationProcedureController,
|
||||
controller.nextMigration()
|
||||
}
|
||||
|
||||
view.accept_migration.setOnClickListener {
|
||||
view.migrating_frame.visible()
|
||||
}
|
||||
|
||||
val viewTag = ViewTag(coroutineContext)
|
||||
view.tag = viewTag
|
||||
view.setupView(viewTag, item)
|
||||
|
||||
view.accept_migration.setOnClickListener {
|
||||
viewTag.launch(Dispatchers.Main) {
|
||||
view.migrating_frame.visible()
|
||||
try {
|
||||
withContext(Dispatchers.Default) {
|
||||
performMigration(item)
|
||||
}
|
||||
controller.nextMigration()
|
||||
} catch(e: Exception) {
|
||||
logger.e("Migration failure!", e)
|
||||
controller.migrationFailure()
|
||||
}
|
||||
view.migrating_frame.gone()
|
||||
}
|
||||
}
|
||||
|
||||
return view
|
||||
}
|
||||
|
||||
fun performMigration() {
|
||||
suspend fun performMigration(manga: MigratingManga) {
|
||||
if(!manga.searchResult.initialized) {
|
||||
return
|
||||
}
|
||||
|
||||
val toMangaObj = db.getManga(manga.searchResult.get() ?: return).await() ?: return
|
||||
|
||||
withContext(Dispatchers.IO) {
|
||||
migrateMangaInternal(
|
||||
manga.manga() ?: return@withContext,
|
||||
toMangaObj,
|
||||
!controller.config.copy
|
||||
)
|
||||
}
|
||||
}
|
||||
private fun migrateMangaInternal(source: Source,
|
||||
sourceChapters: List<SChapter>,
|
||||
prevManga: Manga,
|
||||
|
||||
private fun migrateMangaInternal(prevManga: Manga,
|
||||
manga: Manga,
|
||||
replace: Boolean) {
|
||||
db.inTransaction {
|
||||
// Update chapters read
|
||||
if (migrateChapters) {
|
||||
try {
|
||||
syncChaptersWithSource(db, sourceChapters, manga, source)
|
||||
} catch (e: Exception) {
|
||||
// Worst case, chapters won't be synced
|
||||
}
|
||||
|
||||
if (MigrationFlags.hasChapters(controller.config.migrationFlags)) {
|
||||
val prevMangaChapters = db.getChapters(prevManga).executeAsBlocking()
|
||||
val maxChapterRead = prevMangaChapters.filter { it.read }
|
||||
.maxBy { it.chapter_number }?.chapter_number
|
||||
@ -99,13 +115,13 @@ class MigrationProcedureAdapter(val controller: MigrationProcedureController,
|
||||
}
|
||||
}
|
||||
// Update categories
|
||||
if (migrateCategories) {
|
||||
if (MigrationFlags.hasCategories(controller.config.migrationFlags)) {
|
||||
val categories = db.getCategoriesForManga(prevManga).executeAsBlocking()
|
||||
val mangaCategories = categories.map { MangaCategory.create(manga, it) }
|
||||
db.setMangaCategories(mangaCategories, listOf(manga))
|
||||
}
|
||||
// Update track
|
||||
if (migrateTracks) {
|
||||
if (MigrationFlags.hasTracks(controller.config.migrationFlags)) {
|
||||
val tracks = db.getTracks(prevManga).executeAsBlocking()
|
||||
for (track in tracks) {
|
||||
track.id = null
|
||||
@ -174,7 +190,7 @@ class MigrationProcedureAdapter(val controller: MigrationProcedureController,
|
||||
}
|
||||
}
|
||||
|
||||
fun View.attachManga(tag: ViewTag, manga: Manga, source: Source) {
|
||||
suspend fun View.attachManga(tag: ViewTag, manga: Manga, source: Source) {
|
||||
// TODO Duplicated in MangaInfoController
|
||||
|
||||
GlideApp.with(context)
|
||||
@ -221,6 +237,23 @@ class MigrationProcedureAdapter(val controller: MigrationProcedureController,
|
||||
SManga.LICENSED -> R.string.licensed
|
||||
else -> R.string.unknown
|
||||
})
|
||||
|
||||
val mangaChapters = db.getChapters(manga).await()
|
||||
manga_chapters.text = mangaChapters.size.toString()
|
||||
val latestChapter = mangaChapters.maxBy { it.chapter_number }?.chapter_number ?: -1f
|
||||
val lastUpdate = Date(mangaChapters.maxBy { it.date_upload }?.date_upload ?: 0)
|
||||
|
||||
if (latestChapter > 0f) {
|
||||
manga_last_chapter.text = DecimalFormat("#.#").format(count)
|
||||
} else {
|
||||
manga_last_chapter.setText(R.string.unknown)
|
||||
}
|
||||
|
||||
if (lastUpdate.time != 0L) {
|
||||
manga_last_update.text = DateFormat.getDateInstance(DateFormat.SHORT).format(lastUpdate)
|
||||
} else {
|
||||
manga_last_update.setText(R.string.unknown)
|
||||
}
|
||||
}
|
||||
|
||||
override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) {
|
||||
|
@ -9,5 +9,7 @@ data class MigrationProcedureConfig(
|
||||
val targetSourceIds: List<Long>,
|
||||
val useSourceWithMostChapters: Boolean,
|
||||
val enableLenientSearch: Boolean,
|
||||
val migrationFlags: Int
|
||||
val migrationFlags: Int,
|
||||
val copy: Boolean,
|
||||
val extraSearchParams: String?
|
||||
): Parcelable
|
@ -4,12 +4,13 @@ import android.content.pm.ActivityInfo
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.elvishew.xlog.XLog
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
import eu.kanade.tachiyomi.util.syncChaptersWithSource
|
||||
import eu.kanade.tachiyomi.util.toast
|
||||
import exh.smartsearch.SmartSearchEngine
|
||||
import exh.ui.base.BaseExhController
|
||||
@ -22,6 +23,7 @@ import rx.schedulers.Schedulers
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
|
||||
// TODO Will probably implode if activity is fully destroyed
|
||||
class MigrationProcedureController(bundle: Bundle? = null) : BaseExhController(bundle), CoroutineScope {
|
||||
override val layoutId = R.layout.eh_migration_process
|
||||
|
||||
@ -29,12 +31,12 @@ class MigrationProcedureController(bundle: Bundle? = null) : BaseExhController(b
|
||||
|
||||
private var adapter: MigrationProcedureAdapter? = null
|
||||
|
||||
private val config: MigrationProcedureConfig = args.getParcelable(CONFIG_EXTRA)
|
||||
val config: MigrationProcedureConfig = args.getParcelable(CONFIG_EXTRA)
|
||||
|
||||
private val db: DatabaseHelper by injectLazy()
|
||||
private val sourceManager: SourceManager by injectLazy()
|
||||
|
||||
private val smartSearchEngine = SmartSearchEngine(coroutineContext)
|
||||
private val smartSearchEngine = SmartSearchEngine(coroutineContext, config.extraSearchParams)
|
||||
|
||||
private val logger = XLog.tag("MigrationProcedureController")
|
||||
|
||||
@ -74,11 +76,15 @@ class MigrationProcedureController(bundle: Bundle? = null) : BaseExhController(b
|
||||
}
|
||||
}
|
||||
|
||||
updateTitle()
|
||||
pager.post {
|
||||
// pager.currentItem doesn't appear to be valid if we don't do this in a post
|
||||
updateTitle()
|
||||
}
|
||||
}
|
||||
|
||||
fun updateTitle() {
|
||||
titleText = "Migrate manga (${pager.currentItem + 1}/${adapter?.count ?: 0})"
|
||||
setTitle()
|
||||
}
|
||||
|
||||
fun nextMigration() {
|
||||
@ -88,14 +94,23 @@ class MigrationProcedureController(bundle: Bundle? = null) : BaseExhController(b
|
||||
router.popCurrentController()
|
||||
} else {
|
||||
pager.setCurrentItem(pager.currentItem + 1, true)
|
||||
updateTitle()
|
||||
launch(Dispatchers.Main) {
|
||||
setTitle()
|
||||
updateTitle()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun migrationFailure() {
|
||||
activity?.let {
|
||||
MaterialDialog.Builder(it)
|
||||
.title("Migration failure")
|
||||
.content("An unknown error occured while migrating this manga!")
|
||||
.positiveText("Ok")
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun runMigrations(mangas: List<MigratingManga>) {
|
||||
val sources = config.targetSourceIds.mapNotNull { sourceManager.get(it) as? CatalogueSource }
|
||||
|
||||
@ -123,21 +138,22 @@ class MigrationProcedureController(bundle: Bundle? = null) : BaseExhController(b
|
||||
async {
|
||||
sourceSemaphore.withPermit {
|
||||
try {
|
||||
supervisorScope {
|
||||
val searchResult = if (config.enableLenientSearch) {
|
||||
smartSearchEngine.smartSearch(source, mangaObj.title)
|
||||
} else {
|
||||
smartSearchEngine.normalSearch(source, mangaObj.title)
|
||||
}
|
||||
val searchResult = if (config.enableLenientSearch) {
|
||||
smartSearchEngine.smartSearch(source, mangaObj.title)
|
||||
} else {
|
||||
smartSearchEngine.normalSearch(source, mangaObj.title)
|
||||
}
|
||||
|
||||
if(searchResult != null) {
|
||||
val localManga = smartSearchEngine.networkToLocalManga(searchResult, source.id)
|
||||
val chapters = source.fetchChapterList(localManga).toSingle().await(Schedulers.io())
|
||||
manga.progress.send(validSources.size to processedSources.incrementAndGet())
|
||||
localManga to chapters.size
|
||||
} else {
|
||||
null
|
||||
if(searchResult != null) {
|
||||
val localManga = smartSearchEngine.networkToLocalManga(searchResult, source.id)
|
||||
val chapters = source.fetchChapterList(localManga).toSingle().await(Schedulers.io())
|
||||
withContext(Dispatchers.IO) {
|
||||
syncChaptersWithSource(db, chapters, localManga, source)
|
||||
}
|
||||
manga.progress.send(validSources.size to processedSources.incrementAndGet())
|
||||
localManga to chapters.size
|
||||
} else {
|
||||
null
|
||||
}
|
||||
} catch(e: Exception) {
|
||||
logger.e("Failed to search in source: ${source.id}!", e)
|
||||
@ -149,17 +165,20 @@ class MigrationProcedureController(bundle: Bundle? = null) : BaseExhController(b
|
||||
} else {
|
||||
validSources.forEachIndexed { index, source ->
|
||||
val searchResult = try {
|
||||
supervisorScope {
|
||||
val searchResult = if (config.enableLenientSearch) {
|
||||
smartSearchEngine.smartSearch(source, mangaObj.title)
|
||||
} else {
|
||||
smartSearchEngine.normalSearch(source, mangaObj.title)
|
||||
}
|
||||
|
||||
if (searchResult != null) {
|
||||
smartSearchEngine.networkToLocalManga(searchResult, source.id)
|
||||
} else null
|
||||
val searchResult = if (config.enableLenientSearch) {
|
||||
smartSearchEngine.smartSearch(source, mangaObj.title)
|
||||
} else {
|
||||
smartSearchEngine.normalSearch(source, mangaObj.title)
|
||||
}
|
||||
|
||||
if (searchResult != null) {
|
||||
val localManga = smartSearchEngine.networkToLocalManga(searchResult, source.id)
|
||||
val chapters = source.fetchChapterList(localManga).toSingle().await(Schedulers.io())
|
||||
withContext(Dispatchers.IO) {
|
||||
syncChaptersWithSource(db, chapters, localManga, source)
|
||||
}
|
||||
localManga
|
||||
} else null
|
||||
} catch(e: Exception) {
|
||||
logger.e("Failed to search in source: ${source.id}!", e)
|
||||
null
|
||||
@ -180,15 +199,13 @@ class MigrationProcedureController(bundle: Bundle? = null) : BaseExhController(b
|
||||
|
||||
if(result != null && result.thumbnail_url == null) {
|
||||
try {
|
||||
supervisorScope {
|
||||
val newManga = sourceManager.getOrStub(result.source)
|
||||
.fetchMangaDetails(result)
|
||||
.toSingle()
|
||||
.await()
|
||||
result.copyFrom(newManga)
|
||||
val newManga = sourceManager.getOrStub(result.source)
|
||||
.fetchMangaDetails(result)
|
||||
.toSingle()
|
||||
.await()
|
||||
result.copyFrom(newManga)
|
||||
|
||||
db.insertManga(result).await()
|
||||
}
|
||||
db.insertManga(result).await()
|
||||
} catch(e: Exception) {
|
||||
logger.e("Could not load search manga details", e)
|
||||
}
|
||||
|
@ -41,6 +41,6 @@ class DeferredField<T> {
|
||||
mutex.withLock {}
|
||||
|
||||
// Field is initialized, return value
|
||||
return content!!
|
||||
return content as T
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user