diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/all/MangaDex.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/all/MangaDex.kt index b55992235..5251df4cf 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/source/online/all/MangaDex.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/online/all/MangaDex.kt @@ -51,7 +51,7 @@ class MangaDex(delegate: HttpSource, val context: Context) : val lcFirstPathSegment = uri.pathSegments.firstOrNull()?.toLowerCase() ?: return null return if (lcFirstPathSegment == "title" || lcFirstPathSegment == "manga") { - "/manga/${uri.pathSegments[1]}" + "/manga/${uri.pathSegments[1]}/" } else { null } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/advanced/process/MigratingManga.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/advanced/process/MigratingManga.kt index 0146a6fab..55fecdf1f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/advanced/process/MigratingManga.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/advanced/process/MigratingManga.kt @@ -5,6 +5,7 @@ import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.SourceManager import exh.util.DeferredField +import exh.util.await import kotlin.coroutines.CoroutineContext import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob @@ -28,7 +29,7 @@ class MigratingManga( @Volatile private var manga: Manga? = null suspend fun manga(): Manga? { - if (manga == null) manga = db.getManga(mangaId).executeAsBlocking() + if (manga == null) manga = db.getManga(mangaId).await() return manga } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/advanced/process/MigrationListController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/advanced/process/MigrationListController.kt index c4361ec5e..65a69d770 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/advanced/process/MigrationListController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/advanced/process/MigrationListController.kt @@ -23,7 +23,6 @@ import eu.kanade.tachiyomi.databinding.MigrationListControllerBinding import eu.kanade.tachiyomi.source.CatalogueSource import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.SourceManager -import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.ui.base.controller.BaseController import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction import eu.kanade.tachiyomi.ui.browse.migration.MigrationMangaDialog @@ -39,7 +38,6 @@ import exh.util.RecyclerWindowInsetsListener import exh.util.await import exh.util.executeOnIO import java.util.concurrent.atomic.AtomicInteger -import kotlin.coroutines.CoroutineContext import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -56,8 +54,7 @@ import uy.kohesive.injekt.injectLazy class MigrationListController(bundle: Bundle? = null) : BaseController(bundle), - MigrationProcessAdapter.MigrationProcessInterface, - CoroutineScope { + MigrationProcessAdapter.MigrationProcessInterface { init { setHasOptionsMenu(true) @@ -65,7 +62,7 @@ class MigrationListController(bundle: Bundle? = null) : private var adapter: MigrationProcessAdapter? = null - override val coroutineContext: CoroutineContext = Job() + Dispatchers.Default + val scope = CoroutineScope(Job() + Dispatchers.Default) val config: MigrationProcedureConfig? = args.getParcelable(CONFIG_EXTRA) @@ -73,7 +70,7 @@ class MigrationListController(bundle: Bundle? = null) : private val preferences: PreferencesHelper by injectLazy() private val sourceManager: SourceManager by injectLazy() - private val smartSearchEngine = SmartSearchEngine(coroutineContext, config?.extraSearchParams) + private val smartSearchEngine = SmartSearchEngine(config?.extraSearchParams) var migrationsJob: Job? = null private set @@ -99,7 +96,7 @@ class MigrationListController(bundle: Bundle? = null) : val newMigratingManga = migratingManga ?: run { val new = config.mangaIds.map { - MigratingManga(db, sourceManager, it, coroutineContext) + MigratingManga(db, sourceManager, it, scope.coroutineContext) } migratingManga = new.toMutableList() new @@ -115,13 +112,14 @@ class MigrationListController(bundle: Bundle? = null) : adapter?.updateDataSet(newMigratingManga.map { it.toModal() }) if (migrationsJob == null) { - migrationsJob = launch { + migrationsJob = scope.launch { runMigrations(newMigratingManga) } } } private suspend fun runMigrations(mangas: List) { + if (config == null) return val useSourceWithMost = preferences.useSourceWithMost().get() val useSmartSearch = preferences.smartMigration().get() @@ -129,7 +127,6 @@ class MigrationListController(bundle: Bundle? = null) : val value = it.toLongOrNull() ?: return sourceManager.get(value) as? CatalogueSource } - if (config == null) return for (manga in mangas) { if (migrationsJob?.isCancelled == true) { break @@ -164,40 +161,20 @@ class MigrationListController(bundle: Bundle? = null) : sourceSemaphore.withPermit { try { val searchResult = if (useSmartSearch) { - smartSearchEngine.smartSearch( - source, - mangaObj.originalTitle - ) + smartSearchEngine.smartSearch(source, mangaObj.originalTitle) } else { - smartSearchEngine.normalSearch( - source, - mangaObj.originalTitle - ) + smartSearchEngine.normalSearch(source, mangaObj.originalTitle) } - if (searchResult != null && - !( - searchResult.url == mangaObj.url && - source.id == mangaObj.source - ) - ) { + if (searchResult != null && (searchResult.url == mangaObj.url && source.id == mangaObj.source)) { val localManga = smartSearchEngine.networkToLocalManga( searchResult, source.id ) - val chapters = - source.fetchChapterList(localManga).toSingle() - .await( - Schedulers.io() - ) + val chapters = source.fetchChapterList(localManga).toSingle().await(Schedulers.io()) try { - syncChaptersWithSource( - db, - chapters, - localManga, - source - ) + syncChaptersWithSource(db, chapters, localManga, source) } catch (e: Exception) { return@async null } @@ -214,34 +191,24 @@ class MigrationListController(bundle: Bundle? = null) : } } } - }.mapNotNull { it.await() }.maxBy { it.second }?.first + }.mapNotNull { it.await() }.maxByOrNull { it.second }?.first } else { validSources.forEachIndexed { index, source -> val searchResult = try { val searchResult = if (useSmartSearch) { - smartSearchEngine.smartSearch( - source, - mangaObj.originalTitle - ) + smartSearchEngine.smartSearch(source, mangaObj.originalTitle) } else { - smartSearchEngine.normalSearch( - source, - mangaObj.originalTitle - ) + smartSearchEngine.normalSearch(source, mangaObj.originalTitle) } if (searchResult != null) { - val localManga = smartSearchEngine.networkToLocalManga( - searchResult, - source.id - ) + val localManga = smartSearchEngine.networkToLocalManga(searchResult, source.id) val chapters = try { - source.fetchChapterList(localManga).toSingle() - .await(Schedulers.io()) + source.fetchChapterList(localManga).toSingle().await(Schedulers.io()) ?: emptyList() } catch (e: java.lang.Exception) { Timber.e(e) - emptyList() - } ?: emptyList() + emptyList() + } withContext(Dispatchers.IO) { syncChaptersWithSource(db, chapters, localManga, source) } @@ -253,9 +220,7 @@ class MigrationListController(bundle: Bundle? = null) : } catch (e: Exception) { null } - manga.progress.send(validSources.size to (index + 1)) - if (searchResult != null) return@async searchResult } @@ -269,12 +234,10 @@ class MigrationListController(bundle: Bundle? = null) : if (result != null && result.thumbnail_url == null) { try { - val newManga = - sourceManager.getOrStub(result.source).fetchMangaDetails(result) - .toSingle().await() + val newManga = sourceManager.getOrStub(result.source).fetchMangaDetails(result).toSingle().await() result.copyFrom(newManga) - db.insertManga(result).executeAsBlocking() + db.insertManga(result).await() } catch (e: CancellationException) { // Ignore cancellations throw e @@ -282,8 +245,7 @@ class MigrationListController(bundle: Bundle? = null) : } } - manga.migrationStatus = - if (result == null) MigrationStatus.MANGA_NOT_FOUND else MigrationStatus.MANGA_FOUND + manga.migrationStatus = if (result == null) MigrationStatus.MANGA_NOT_FOUND else MigrationStatus.MANGA_FOUND adapter?.sourceFinished() manga.searchResult.initialize(result?.id) } @@ -374,9 +336,7 @@ class MigrationListController(bundle: Bundle? = null) : val result = CoroutineScope(migratingManga.manga.migrationJob).async { val localManga = smartSearchEngine.networkToLocalManga(manga, source.id) try { - val chapters = source.fetchChapterList(localManga).toSingle().await( - Schedulers.io() - ) + val chapters = source.fetchChapterList(localManga).toSingle().await(Schedulers.io()) syncChaptersWithSource(db, chapters, localManga, source) } catch (e: Exception) { return@async null @@ -386,12 +346,10 @@ class MigrationListController(bundle: Bundle? = null) : if (result != null) { try { - val newManga = - sourceManager.getOrStub(result.source).fetchMangaDetails(result).toSingle() - .await() + val newManga = sourceManager.getOrStub(result.source).fetchMangaDetails(result).toSingle().await() result.copyFrom(newManga) - db.insertManga(result).executeAsBlocking() + db.insertManga(result).await() } catch (e: CancellationException) { // Ignore cancellations throw e diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/advanced/process/MigrationProcessAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/advanced/process/MigrationProcessAdapter.kt index 20d9ec11e..f1d054d90 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/advanced/process/MigrationProcessAdapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/advanced/process/MigrationProcessAdapter.kt @@ -107,7 +107,7 @@ class MigrationProcessAdapter( if (MigrationFlags.hasChapters(flags)) { val prevMangaChapters = db.getChapters(prevManga).executeAsBlocking() val maxChapterRead = - prevMangaChapters.filter { it.read }.maxBy { it.chapter_number }?.chapter_number + prevMangaChapters.filter { it.read }.maxByOrNull { it.chapter_number }?.chapter_number if (maxChapterRead != null) { val dbChapters = db.getChapters(manga).executeAsBlocking() for (chapter in dbChapters) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/advanced/process/MigrationProcessHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/advanced/process/MigrationProcessHolder.kt index 7cb616398..05fec10c9 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/advanced/process/MigrationProcessHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/advanced/process/MigrationProcessHolder.kt @@ -181,7 +181,7 @@ class MigrationProcessHolder( val mangaChapters = db.getChapters(manga).executeAsBlocking() manga_chapters.isVisible = true manga_chapters.text = mangaChapters.size.toString() - val latestChapter = mangaChapters.maxBy { it.chapter_number }?.chapter_number ?: -1f + val latestChapter = mangaChapters.maxByOrNull { it.chapter_number }?.chapter_number ?: -1f if (latestChapter > 0f) { manga_last_chapter_label.text = context.getString( diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/manga/MigrationMangaPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/manga/MigrationMangaPresenter.kt index ca0e929e9..27393ce52 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/manga/MigrationMangaPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/manga/MigrationMangaPresenter.kt @@ -73,7 +73,7 @@ class MigrationMangaPresenter( val prevMangaChapters = db.getChapters(prevManga).executeAsBlocking() val maxChapterRead = - prevMangaChapters.filter { it.read }.maxBy { it.chapter_number }?.chapter_number + prevMangaChapters.filter { it.read }.maxByOrNull { it.chapter_number }?.chapter_number if (maxChapterRead != null) { val dbChapters = db.getChapters(manga).executeAsBlocking() for (chapter in dbChapters) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourceFilterController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourceFilterController.kt index 2adce416a..272ceb55d 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourceFilterController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourceFilterController.kt @@ -62,8 +62,6 @@ class SourceFilterController : SettingsController() { sourcesByLang.keys.filterNot { it in activeLangsCodes } orderedLangs.forEach { lang -> - val sources = sourcesByLang[lang].orEmpty().sortedBy { it.name } - // Create a preference group and set initial state and change listener langPrefs.add( Pair( diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/filter/AutoComplete.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/filter/AutoComplete.kt index 0bad95fd0..4fd9b6bff 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/filter/AutoComplete.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/filter/AutoComplete.kt @@ -7,6 +7,7 @@ import android.widget.AutoCompleteTextView import android.widget.TextView import androidx.core.widget.addTextChangedListener import androidx.recyclerview.widget.RecyclerView +import com.elvishew.xlog.XLog import com.google.android.material.chip.Chip import com.google.android.material.chip.ChipGroup import eu.davidea.flexibleadapter.FlexibleAdapter @@ -16,7 +17,6 @@ import eu.davidea.viewholders.FlexibleViewHolder import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.source.model.Filter import eu.kanade.tachiyomi.widget.AutoCompleteAdapter -import timber.log.Timber open class AutoComplete(val filter: Filter.AutoComplete) : AbstractFlexibleItem() { @@ -43,8 +43,6 @@ open class AutoComplete(val filter: Filter.AutoComplete) : AbstractFlexibleItem< ) holder.autoComplete.threshold = 3 - var text: String = "" - // select from auto complete holder.autoComplete.setOnItemClickListener { adapterView, _, chipPosition, _ -> val name = adapterView.getItemAtPosition(chipPosition) as String @@ -55,7 +53,7 @@ open class AutoComplete(val filter: Filter.AutoComplete) : AbstractFlexibleItem< } // done keyboard button is pressed - holder.autoComplete.setOnEditorActionListener { textView, actionId, keyEvent -> + holder.autoComplete.setOnEditorActionListener { textView, actionId, _ -> if (actionId == EditorInfo.IME_ACTION_DONE && textView.text.toString() !in if (filter.excludePrefix != null && textView.text.toString().startsWith(filter.excludePrefix)) filter.skipAutoFillTags.map { filter.excludePrefix + it } else filter.skipAutoFillTags) { textView.text = null addTag(textView.text.toString(), holder) @@ -69,14 +67,12 @@ open class AutoComplete(val filter: Filter.AutoComplete) : AbstractFlexibleItem< if (it == null || it.isEmpty()) { return@addTextChangedListener } - text = it.toString() if (it.last() == ',') { val name = it.substring(0, it.length - 1) addTag(name, holder) holder.autoComplete.text = null - // mainTagAutoCompleteTextView.removeTextChangedListener(this) } } @@ -101,7 +97,7 @@ open class AutoComplete(val filter: Filter.AutoComplete) : AbstractFlexibleItem< addChipToGroup(name, holder) filter.state += name } else { - Timber.d("Invalid tag: $name") + XLog.d("Invalid tag: $name") } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt index ae4419e06..afc31cc76 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt @@ -455,7 +455,7 @@ class LibraryPresenter( mangas.forEach { manga -> launchIO { /* SY --> */ val chapters = if (manga.source == EH_SOURCE_ID || manga.source == EXH_SOURCE_ID) { - val chapter = db.getChapters(manga).executeAsBlocking().minBy { it.source_order } + val chapter = db.getChapters(manga).executeAsBlocking().minByOrNull { it.source_order } if (chapter != null && !chapter.read) listOf(chapter) else emptyList() } else /* SY <-- */ db.getChapters(manga).executeAsBlocking() .filter { !it.read } diff --git a/app/src/main/java/exh/eh/EHentaiUpdateHelper.kt b/app/src/main/java/exh/eh/EHentaiUpdateHelper.kt index 7ff7498b8..d7ae5887b 100644 --- a/app/src/main/java/exh/eh/EHentaiUpdateHelper.kt +++ b/app/src/main/java/exh/eh/EHentaiUpdateHelper.kt @@ -54,7 +54,7 @@ class EHentaiUpdateHelper(context: Context) { // Accept oldest chain val chainsWithAccepted = chainsObservable.map { chains -> - val acceptedChain = chains.minBy { it.manga.id!! }!! + val acceptedChain = chains.minByOrNull { it.manga.id!! }!! acceptedChain to chains } @@ -91,7 +91,7 @@ class EHentaiUpdateHelper(context: Context) { .fold(accepted.chapters) { curChapters, chapter -> val existing = curChapters.find { it.url == chapter.url } - val newLastPageRead = chainsAsChapters.maxBy { it.last_page_read }?.last_page_read + val newLastPageRead = chainsAsChapters.maxByOrNull { it.last_page_read }?.last_page_read when { existing != null -> { diff --git a/app/src/main/java/exh/eh/EHentaiUpdateWorker.kt b/app/src/main/java/exh/eh/EHentaiUpdateWorker.kt index b041226f3..e8e419562 100644 --- a/app/src/main/java/exh/eh/EHentaiUpdateWorker.kt +++ b/app/src/main/java/exh/eh/EHentaiUpdateWorker.kt @@ -151,7 +151,7 @@ class EHentaiUpdateWorker : JobService(), CoroutineScope { return@mapNotNull null } - val chapter = db.getChaptersByMangaId(manga.id!!).asRxSingle().await().minBy { + val chapter = db.getChaptersByMangaId(manga.id!!).asRxSingle().await().minByOrNull { it.date_upload } diff --git a/app/src/main/java/exh/smartsearch/SmartSearchEngine.kt b/app/src/main/java/exh/smartsearch/SmartSearchEngine.kt index fa0670395..6a4a8bcff 100644 --- a/app/src/main/java/exh/smartsearch/SmartSearchEngine.kt +++ b/app/src/main/java/exh/smartsearch/SmartSearchEngine.kt @@ -7,21 +7,15 @@ import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.SManga import exh.util.await import info.debatty.java.stringsimilarity.NormalizedLevenshtein -import kotlin.coroutines.CoroutineContext -import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job import kotlinx.coroutines.async import kotlinx.coroutines.supervisorScope import rx.schedulers.Schedulers import uy.kohesive.injekt.injectLazy class SmartSearchEngine( - parentContext: CoroutineContext, private val extraSearchParams: String? = null -) : CoroutineScope { - override val coroutineContext: CoroutineContext = parentContext + Job() + Dispatchers.Default - +) { private val db: DatabaseHelper by injectLazy() private val normalizedLevenshtein = NormalizedLevenshtein() @@ -52,7 +46,7 @@ class SmartSearchEngine( }.flatMap { it.await() } } - return eligibleManga.maxBy { it.dist }?.manga + return eligibleManga.maxByOrNull { it.dist }?.manga } suspend fun normalSearch(source: CatalogueSource, title: String): SManga? { @@ -74,7 +68,7 @@ class SmartSearchEngine( } } - return eligibleManga.maxBy { it.dist }?.manga + return eligibleManga.maxByOrNull { it.dist }?.manga } private fun getSmartSearchQueries(cleanedTitle: String): List { diff --git a/app/src/main/java/exh/ui/smartsearch/SmartSearchPresenter.kt b/app/src/main/java/exh/ui/smartsearch/SmartSearchPresenter.kt index 3be172750..cbef65af1 100644 --- a/app/src/main/java/exh/ui/smartsearch/SmartSearchPresenter.kt +++ b/app/src/main/java/exh/ui/smartsearch/SmartSearchPresenter.kt @@ -21,7 +21,7 @@ class SmartSearchPresenter(private val source: CatalogueSource?, private val con val smartSearchChannel = Channel() - private val smartSearchEngine = SmartSearchEngine(scope.coroutineContext) + private val smartSearchEngine = SmartSearchEngine() override fun onCreate(savedState: Bundle?) { super.onCreate(savedState) diff --git a/app/src/main/java/exh/util/OkHttpUtil.kt b/app/src/main/java/exh/util/OkHttpUtil.kt index 714caf743..d1cbd22f9 100644 --- a/app/src/main/java/exh/util/OkHttpUtil.kt +++ b/app/src/main/java/exh/util/OkHttpUtil.kt @@ -3,7 +3,7 @@ package exh.util import com.elvishew.xlog.XLog import eu.kanade.tachiyomi.util.asJsoup import okhttp3.Response -import okhttp3.ResponseBody +import okhttp3.ResponseBody.Companion.toResponseBody import org.jsoup.nodes.Document fun Response.interceptAsHtml(block: (Document) -> Unit): Response { @@ -13,7 +13,7 @@ fun Response.interceptAsHtml(block: (Document) -> Unit): Response { ) { val bodyString = body.string() val rebuiltResponse = newBuilder() - .body(ResponseBody.create(body.contentType(), bodyString)) + .body(bodyString.toResponseBody(body.contentType())) .build() try { // Search for captcha