diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/cache/ChapterCache.kt b/app/src/main/java/eu/kanade/tachiyomi/data/cache/ChapterCache.kt index c7f884b41..0c9826962 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/data/cache/ChapterCache.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/cache/ChapterCache.kt @@ -51,6 +51,7 @@ class ChapterCache(private val context: Context) { /** Cache class used for cache management. */ // --> EH private var diskCache = setupDiskCache(prefs.eh_cacheSize().getOrDefault().toLong()) + init { prefs.eh_cacheSize().asObservable().skip(1).subscribe { // Save old cache for destruction later @@ -83,9 +84,9 @@ class ChapterCache(private val context: Context) { // Cache size is in MB private fun setupDiskCache(cacheSize: Long): DiskLruCache { return DiskLruCache.open(File(context.cacheDir, PARAMETER_CACHE_DIRECTORY), - PARAMETER_APP_VERSION, - PARAMETER_VALUE_COUNT, - cacheSize * 1024 * 1024) + PARAMETER_APP_VERSION, + PARAMETER_VALUE_COUNT, + cacheSize * 1024 * 1024) } // <-- EH diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Category.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Category.kt index 374183a75..4c1d16040 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Category.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Category.kt @@ -12,7 +12,7 @@ interface Category : Serializable { var flags: Int - var mangaOrder:List + var mangaOrder: List val nameLower: String get() = name.toLowerCase() diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyanimelistApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyanimelistApi.kt deleted file mode 100755 index 6d1839047..000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyanimelistApi.kt +++ /dev/null @@ -1,505 +0,0 @@ -package eu.kanade.tachiyomi.data.track.myanimelist - -import android.net.Uri -import eu.kanade.tachiyomi.data.database.models.Track -import eu.kanade.tachiyomi.data.track.TrackManager -import eu.kanade.tachiyomi.data.track.model.TrackSearch -import eu.kanade.tachiyomi.network.GET -import eu.kanade.tachiyomi.network.POST -import eu.kanade.tachiyomi.network.asObservable -import eu.kanade.tachiyomi.network.asObservableSuccess -import eu.kanade.tachiyomi.util.lang.toCalendar -import eu.kanade.tachiyomi.util.selectInt -import eu.kanade.tachiyomi.util.selectText -import java.io.BufferedReader -import java.io.InputStreamReader -import java.text.SimpleDateFormat -import java.util.Calendar -import java.util.GregorianCalendar -import java.util.Locale -import java.util.zip.GZIPInputStream -import okhttp3.FormBody -import okhttp3.MediaType.Companion.toMediaTypeOrNull -import okhttp3.OkHttpClient -import okhttp3.RequestBody -import okhttp3.RequestBody.Companion.toRequestBody -import okhttp3.Response -import org.json.JSONObject -import org.jsoup.Jsoup -import org.jsoup.nodes.Document -import org.jsoup.nodes.Element -import org.jsoup.parser.Parser -import rx.Observable - -class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListInterceptor) { - - private val authClient = client.newBuilder().addInterceptor(interceptor).build() - - fun search(query: String): Observable> { - return if (query.startsWith(PREFIX_MY)) { - val realQuery = query.removePrefix(PREFIX_MY) - getList() - .flatMap { Observable.from(it) } - .filter { it.title.contains(realQuery, true) } - .toList() - } else { - client.newCall(GET(searchUrl(query))) - .asObservable() - .flatMap { response -> - Observable.from( - Jsoup.parse(response.consumeBody()) - .select("div.js-categories-seasonal.js-block-list.list") - .select("table").select("tbody") - .select("tr").drop(1) - ) - } - .filter { row -> - row.select(TD)[2].text() != "Novel" - } - .map { row -> - TrackSearch.create(TrackManager.MYANIMELIST).apply { - title = row.searchTitle() - media_id = row.searchMediaId() - total_chapters = row.searchTotalChapters() - summary = row.searchSummary() - cover_url = row.searchCoverUrl() - tracking_url = mangaUrl(media_id) - publishing_status = row.searchPublishingStatus() - publishing_type = row.searchPublishingType() - start_date = row.searchStartDate() - } - } - .toList() - } - } - - fun addLibManga(track: Track): Observable { - return Observable.defer { - authClient.newCall(POST(url = addUrl(), body = mangaPostPayload(track))) - .asObservableSuccess() - .map { track } - } - } - - fun updateLibManga(track: Track): Observable { - return Observable.defer { - // Get track data - val response = authClient.newCall(GET(url = editPageUrl(track.media_id))).execute() - val editData = response.use { - val page = Jsoup.parse(it.consumeBody()) - - // Extract track data from MAL page - extractDataFromEditPage(page).apply { - // Apply changes to the just fetched data - copyPersonalFrom(track) - } - } - - // Update remote - authClient.newCall(POST(url = editPageUrl(track.media_id), body = mangaEditPostBody(editData))) - .asObservableSuccess() - .map { - track - } - } - } - - fun findLibManga(track: Track): Observable { - return authClient.newCall(GET(url = editPageUrl(track.media_id))) - .asObservable() - .map { response -> - var libTrack: Track? = null - response.use { - if (it.priorResponse?.isRedirect != true) { - val trackForm = Jsoup.parse(it.consumeBody()) - - libTrack = Track.create(TrackManager.MYANIMELIST).apply { - last_chapter_read = trackForm.select("#add_manga_num_read_chapters").`val`().toInt() - total_chapters = trackForm.select("#totalChap").text().toInt() - status = trackForm.select("#add_manga_status > option[selected]").`val`().toInt() - score = trackForm.select("#add_manga_score > option[selected]").`val`().toFloatOrNull() - ?: 0f - started_reading_date = trackForm.searchDatePicker("#add_manga_start_date") - finished_reading_date = trackForm.searchDatePicker("#add_manga_finish_date") - } - } - } - libTrack - } - } - - fun getLibManga(track: Track): Observable { - return findLibManga(track) - .map { it ?: throw Exception("Could not find manga") } - } - - fun login(username: String, password: String): String { - val csrf = getSessionInfo() - - login(username, password, csrf) - - return csrf - } - - private fun getSessionInfo(): String { - val response = client.newCall(GET(loginUrl())).execute() - - return Jsoup.parse(response.consumeBody()) - .select("meta[name=csrf_token]") - .attr("content") - } - - private fun login(username: String, password: String, csrf: String) { - val response = client.newCall(POST(url = loginUrl(), body = loginPostBody(username, password, csrf))).execute() - - response.use { - if (response.priorResponse?.code != 302) throw Exception("Authentication error") - } - } - - private fun getList(): Observable> { - return getListUrl() - .flatMap { url -> - getListXml(url) - } - .flatMap { doc -> - Observable.from(doc.select("manga")) - } - .map { - TrackSearch.create(TrackManager.MYANIMELIST).apply { - title = it.selectText("manga_title")!! - media_id = it.selectInt("manga_mangadb_id") - last_chapter_read = it.selectInt("my_read_chapters") - status = getStatus(it.selectText("my_status")!!) - score = it.selectInt("my_score").toFloat() - total_chapters = it.selectInt("manga_chapters") - tracking_url = mangaUrl(media_id) - started_reading_date = it.searchDateXml("my_start_date") - finished_reading_date = it.searchDateXml("my_finish_date") - } - } - .toList() - } - - private fun getListUrl(): Observable { - return authClient.newCall(POST(url = exportListUrl(), body = exportPostBody())) - .asObservable() - .map { response -> - baseUrl + Jsoup.parse(response.consumeBody()) - .select("div.goodresult") - .select("a") - .attr("href") - } - } - - private fun getListXml(url: String): Observable { - return authClient.newCall(GET(url)) - .asObservable() - .map { response -> - Jsoup.parse(response.consumeXmlBody(), "", Parser.xmlParser()) - } - } - - private fun Response.consumeBody(): String? { - use { - if (it.code != 200) throw Exception("HTTP error ${it.code}") - return it.body?.string() - } - } - - private fun Response.consumeXmlBody(): String? { - use { res -> - if (res.code != 200) throw Exception("Export list error") - BufferedReader(InputStreamReader(GZIPInputStream(res.body?.source()?.inputStream()))).use { reader -> - val sb = StringBuilder() - reader.forEachLine { line -> - sb.append(line) - } - return sb.toString() - } - } - } - - private fun extractDataFromEditPage(page: Document): MyAnimeListEditData { - val tables = page.select("form#main-form table") - - return MyAnimeListEditData( - entry_id = tables[0].select("input[name=entry_id]").`val`(), // Always 0 - manga_id = tables[0].select("#manga_id").`val`(), - status = tables[0].select("#add_manga_status > option[selected]").`val`(), - num_read_volumes = tables[0].select("#add_manga_num_read_volumes").`val`(), - last_completed_vol = tables[0].select("input[name=last_completed_vol]").`val`(), // Always empty - num_read_chapters = tables[0].select("#add_manga_num_read_chapters").`val`(), - score = tables[0].select("#add_manga_score > option[selected]").`val`(), - start_date_month = tables[0].select("#add_manga_start_date_month > option[selected]").`val`(), - start_date_day = tables[0].select("#add_manga_start_date_day > option[selected]").`val`(), - start_date_year = tables[0].select("#add_manga_start_date_year > option[selected]").`val`(), - finish_date_month = tables[0].select("#add_manga_finish_date_month > option[selected]").`val`(), - finish_date_day = tables[0].select("#add_manga_finish_date_day > option[selected]").`val`(), - finish_date_year = tables[0].select("#add_manga_finish_date_year > option[selected]").`val`(), - tags = tables[1].select("#add_manga_tags").`val`(), - priority = tables[1].select("#add_manga_priority > option[selected]").`val`(), - storage_type = tables[1].select("#add_manga_storage_type > option[selected]").`val`(), - num_retail_volumes = tables[1].select("#add_manga_num_retail_volumes").`val`(), - num_read_times = tables[1].select("#add_manga_num_read_times").`val`(), - reread_value = tables[1].select("#add_manga_reread_value > option[selected]").`val`(), - comments = tables[1].select("#add_manga_comments").`val`(), - is_asked_to_discuss = tables[1].select("#add_manga_is_asked_to_discuss > option[selected]").`val`(), - sns_post_type = tables[1].select("#add_manga_sns_post_type > option[selected]").`val`() - ) - } - - companion object { - const val CSRF = "csrf_token" - - private const val baseUrl = "https://myanimelist.net" - private const val baseMangaUrl = "$baseUrl/manga/" - private const val baseModifyListUrl = "$baseUrl/ownlist/manga" - private const val PREFIX_MY = "my:" - private const val TD = "td" - - private fun mangaUrl(remoteId: Int) = baseMangaUrl + remoteId - - private fun loginUrl() = Uri.parse(baseUrl).buildUpon() - .appendPath("login.php") - .toString() - - private fun searchUrl(query: String): String { - val col = "c[]" - return Uri.parse(baseUrl).buildUpon() - .appendPath("manga.php") - .appendQueryParameter("q", query) - .appendQueryParameter(col, "a") - .appendQueryParameter(col, "b") - .appendQueryParameter(col, "c") - .appendQueryParameter(col, "d") - .appendQueryParameter(col, "e") - .appendQueryParameter(col, "g") - .toString() - } - - private fun exportListUrl() = Uri.parse(baseUrl).buildUpon() - .appendPath("panel.php") - .appendQueryParameter("go", "export") - .toString() - - private fun editPageUrl(mediaId: Int) = Uri.parse(baseModifyListUrl).buildUpon() - .appendPath(mediaId.toString()) - .appendPath("edit") - .toString() - - private fun addUrl() = Uri.parse(baseModifyListUrl).buildUpon() - .appendPath("add.json") - .toString() - - private fun loginPostBody(username: String, password: String, csrf: String): RequestBody { - return FormBody.Builder() - .add("user_name", username) - .add("password", password) - .add("cookie", "1") - .add("sublogin", "Login") - .add("submit", "1") - .add(CSRF, csrf) - .build() - } - - private fun exportPostBody(): RequestBody { - return FormBody.Builder() - .add("type", "2") - .add("subexport", "Export My List") - .build() - } - - private fun mangaPostPayload(track: Track): RequestBody { - val body = JSONObject() - .put("manga_id", track.media_id) - .put("status", track.status) - .put("score", track.score) - .put("num_read_chapters", track.last_chapter_read) - - return body.toString().toRequestBody("application/json; charset=utf-8".toMediaTypeOrNull()) - } - - private fun mangaEditPostBody(track: MyAnimeListEditData): RequestBody { - return FormBody.Builder() - .add("entry_id", track.entry_id) - .add("manga_id", track.manga_id) - .add("add_manga[status]", track.status) - .add("add_manga[num_read_volumes]", track.num_read_volumes) - .add("last_completed_vol", track.last_completed_vol) - .add("add_manga[num_read_chapters]", track.num_read_chapters) - .add("add_manga[score]", track.score) - .add("add_manga[start_date][month]", track.start_date_month) - .add("add_manga[start_date][day]", track.start_date_day) - .add("add_manga[start_date][year]", track.start_date_year) - .add("add_manga[finish_date][month]", track.finish_date_month) - .add("add_manga[finish_date][day]", track.finish_date_day) - .add("add_manga[finish_date][year]", track.finish_date_year) - .add("add_manga[tags]", track.tags) - .add("add_manga[priority]", track.priority) - .add("add_manga[storage_type]", track.storage_type) - .add("add_manga[num_retail_volumes]", track.num_retail_volumes) - .add("add_manga[num_read_times]", track.num_read_times) - .add("add_manga[reread_value]", track.reread_value) - .add("add_manga[comments]", track.comments) - .add("add_manga[is_asked_to_discuss]", track.is_asked_to_discuss) - .add("add_manga[sns_post_type]", track.sns_post_type) - .add("submitIt", track.submitIt) - .build() - } - - private fun Element.searchDateXml(field: String): Long { - val text = selectText(field, "0000-00-00")!! - // MAL sets the data to 0000-00-00 when date is invalid or missing - if (text == "0000-00-00") { - return 0L - } - - return SimpleDateFormat("yyyy-MM-dd", Locale.US).parse(text)?.time ?: 0L - } - - private fun Element.searchDatePicker(id: String): Long { - val month = select(id + "_month > option[selected]").`val`().toIntOrNull() - val day = select(id + "_day > option[selected]").`val`().toIntOrNull() - val year = select(id + "_year > option[selected]").`val`().toIntOrNull() - if (year == null || month == null || day == null) { - return 0L - } - - return GregorianCalendar(year, month - 1, day).timeInMillis - } - - private fun Element.searchTitle() = select("strong").text()!! - - private fun Element.searchTotalChapters() = if (select(TD)[4].text() == "-") 0 else select(TD)[4].text().toInt() - - private fun Element.searchCoverUrl() = select("img") - .attr("data-src") - .split("\\?")[0] - .replace("/r/50x70/", "/") - - private fun Element.searchMediaId() = select("div.picSurround") - .select("a").attr("id") - .replace("sarea", "") - .toInt() - - private fun Element.searchSummary() = select("div.pt4") - .first() - .ownText()!! - - private fun Element.searchPublishingStatus() = if (select(TD).last().text() == "-") "Publishing" else "Finished" - - private fun Element.searchPublishingType() = select(TD)[2].text()!! - - private fun Element.searchStartDate() = select(TD)[6].text()!! - - private fun getStatus(status: String) = when (status) { - "Reading" -> 1 - "Completed" -> 2 - "On-Hold" -> 3 - "Dropped" -> 4 - "Plan to Read" -> 6 - else -> 1 - } - } - - private class MyAnimeListEditData( - // entry_id - var entry_id: String, - - // manga_id - var manga_id: String, - - // add_manga[status] - var status: String, - - // add_manga[num_read_volumes] - var num_read_volumes: String, - - // last_completed_vol - var last_completed_vol: String, - - // add_manga[num_read_chapters] - var num_read_chapters: String, - - // add_manga[score] - var score: String, - - // add_manga[start_date][month] - var start_date_month: String, // [1-12] - - // add_manga[start_date][day] - var start_date_day: String, - - // add_manga[start_date][year] - var start_date_year: String, - - // add_manga[finish_date][month] - var finish_date_month: String, // [1-12] - - // add_manga[finish_date][day] - var finish_date_day: String, - - // add_manga[finish_date][year] - var finish_date_year: String, - - // add_manga[tags] - var tags: String, - - // add_manga[priority] - var priority: String, - - // add_manga[storage_type] - var storage_type: String, - - // add_manga[num_retail_volumes] - var num_retail_volumes: String, - - // add_manga[num_read_times] - var num_read_times: String, - - // add_manga[reread_value] - var reread_value: String, - - // add_manga[comments] - var comments: String, - - // add_manga[is_asked_to_discuss] - var is_asked_to_discuss: String, - - // add_manga[sns_post_type] - var sns_post_type: String, - - // submitIt - val submitIt: String = "0" - ) { - fun copyPersonalFrom(track: Track) { - num_read_chapters = track.last_chapter_read.toString() - val numScore = track.score.toInt() - if (numScore in 1..9) { - score = numScore.toString() - } - status = track.status.toString() - if (track.started_reading_date == 0L) { - start_date_month = "" - start_date_day = "" - start_date_year = "" - } - if (track.finished_reading_date == 0L) { - finish_date_month = "" - finish_date_day = "" - finish_date_year = "" - } - track.started_reading_date.toCalendar()?.let { cal -> - start_date_month = (cal[Calendar.MONTH] + 1).toString() - start_date_day = cal[Calendar.DAY_OF_MONTH].toString() - start_date_year = cal[Calendar.YEAR].toString() - } - track.finished_reading_date.toCalendar()?.let { cal -> - finish_date_month = (cal[Calendar.MONTH] + 1).toString() - finish_date_day = cal[Calendar.DAY_OF_MONTH].toString() - finish_date_year = cal[Calendar.YEAR].toString() - } - } - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionManager.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionManager.kt index 1e2426bb8..1b8a7b8fa 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionManager.kt @@ -138,7 +138,7 @@ class ExtensionManager( fun Iterable.filterNotBlacklisted(): List { val blacklistEnabled = preferences.eh_enableSourceBlacklist().getOrDefault() return filter { - if(it.isBlacklisted(blacklistEnabled)) { + if (it.isBlacklisted(blacklistEnabled)) { XLog.d("[EXH] Removing blacklisted extension: (name: %s, pkgName: %s)!", it.name, it.pkgName) false } else true @@ -304,7 +304,7 @@ class ExtensionManager( * @param extension The extension to be registered. */ private fun registerNewExtension(extension: Extension.Installed) { - if(extension.isBlacklisted()) { + if (extension.isBlacklisted()) { XLog.d("[EXH] Removing blacklisted extension: (name: String, pkgName: %s)!", extension.name, extension.pkgName) return } @@ -320,7 +320,7 @@ class ExtensionManager( * @param extension The extension to be registered. */ private fun registerUpdatedExtension(extension: Extension.Installed) { - if(extension.isBlacklisted()) { + if (extension.isBlacklisted()) { XLog.d("[EXH] Removing blacklisted extension: (name: String, pkgName: %s)!", extension.name, extension.pkgName) return } diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/model/SManga.kt b/app/src/main/java/eu/kanade/tachiyomi/source/model/SManga.kt index eed3ad1bf..c240095a7 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/source/model/SManga.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/model/SManga.kt @@ -24,7 +24,7 @@ interface SManga : Serializable { fun copyFrom(other: SManga) { // EXH --> - if(other.title.isNotBlank()) + if (other.title.isNotBlank()) title = other.title // EXH <-- diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/LewdSource.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/LewdSource.kt index db9c3c811..e27951e78 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/source/online/LewdSource.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/online/LewdSource.kt @@ -36,7 +36,8 @@ interface LewdSource : CatalogueSource { */ private fun newMetaInstance() = metaClass.constructors.find { it.parameters.isEmpty() - }?.call() ?: error("Could not find no-args constructor for meta class: ${metaClass.qualifiedName}!") + }?.call() + ?: error("Could not find no-args constructor for meta class: ${metaClass.qualifiedName}!") /** * Parses metadata from the input and then copies it into the manga @@ -45,12 +46,12 @@ interface LewdSource : CatalogueSource { */ fun parseToManga(manga: SManga, input: I): Completable { val mangaId = (manga as? Manga)?.id - val metaObservable = if(mangaId != null) { + val metaObservable = if (mangaId != null) { // We have to use fromCallable because StorIO messes up the thread scheduling if we use their rx functions Single.fromCallable { db.getFlatMetadataForManga(mangaId).executeAsBlocking() - } .map { - if(it != null) it.raise(metaClass) + }.map { + if (it != null) it.raise(metaClass) else newMetaInstance() } } else { @@ -62,7 +63,7 @@ interface LewdSource : CatalogueSource { it.copyTo(manga) it }.flatMapCompletable { - if(mangaId != null) { + if (mangaId != null) { it.mangaId = mangaId db.insertFlatMetadata(it.flatten()) } else Completable.complete() @@ -77,7 +78,7 @@ interface LewdSource : CatalogueSource { * also be saved to the DB. */ fun getOrLoadMetadata(mangaId: Long?, inputProducer: () -> Single): Single { - val metaObservable = if(mangaId != null) { + val metaObservable = if (mangaId != null) { // We have to use fromCallable because StorIO messes up the thread scheduling if we use their rx functions Single.fromCallable { db.getFlatMetadataForManga(mangaId).executeAsBlocking() @@ -87,12 +88,12 @@ interface LewdSource : CatalogueSource { } else Single.just(null) return metaObservable.flatMap { existingMeta -> - if(existingMeta == null) { + if (existingMeta == null) { inputProducer().flatMap { input -> val newMeta = newMetaInstance() parseIntoMetadata(newMeta, input) val newMetaSingle = Single.just(newMeta) - if(mangaId != null) { + if (mangaId != null) { newMeta.mangaId = mangaId db.insertFlatMetadata(newMeta.flatten()).andThen(newMetaSingle) } else newMetaSingle diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/all/EHentai.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/all/EHentai.kt index 05ff1f5de..80d187921 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/source/online/all/EHentai.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/online/all/EHentai.kt @@ -56,13 +56,13 @@ class EHentai(override val id: Long, override val metaClass = EHentaiSearchMetadata::class val schema: String - get() = if(prefs.secureEXH().getOrDefault()) + get() = if (prefs.secureEXH().getOrDefault()) "https" else "http" val domain: String - get() = if(exh) + get() = if (exh) "exhentai.org" else "e-hentai.org" @@ -81,8 +81,7 @@ class EHentai(override val id: Long, */ data class ParsedManga(val fav: Int, val manga: Manga) - fun extendedGenericMangaParse(doc: Document) - = with(doc) { + fun extendedGenericMangaParse(doc: Document) = with(doc) { // Parse mangas (supports compact + extended layout) val parsedMangas = select(".itg > tbody > tr").filter { // Do not parse header and ads @@ -112,7 +111,7 @@ class EHentai(override val id: Long, val parsedLocation = doc.location().toHttpUrlOrNull() //Add to page if required - val hasNextPage = if(parsedLocation == null + val hasNextPage = if (parsedLocation == null || !parsedLocation.queryParameterNames.contains(REVERSE_PARAM)) { select("a[onclick=return false]").last()?.let { it.text() == ">" @@ -126,13 +125,11 @@ class EHentai(override val id: Long, /** * Parse a list of galleries */ - fun genericMangaParse(response: Response) - = extendedGenericMangaParse(response.asJsoup()).let { + fun genericMangaParse(response: Response) = extendedGenericMangaParse(response.asJsoup()).let { MangasPage(it.first.map { it.manga }, it.second) } - override fun fetchChapterList(manga: SManga) - = fetchChapterList(manga) {} + override fun fetchChapterList(manga: SManga) = fetchChapterList(manga) {} fun fetchChapterList(manga: SManga, throttleFunc: () -> Unit): Observable> { return Single.fromCallable { @@ -148,7 +145,7 @@ class EHentai(override val id: Long, val cachedParent = updateHelper.parentLookupTable.get( gid ) - if(cachedParent == null) { + if (cachedParent == null) { throttleFunc() val resp = client.newCall(exGet(baseUrl + url)).execute() @@ -192,7 +189,7 @@ class EHentai(override val id: Long, }!!.nextElementSibling().text()).time } // Build and append the rest of the galleries - if(DebugToggles.INCLUDE_ONLY_ROOT_WHEN_LOADING_EXH_VERSIONS.enabled) listOf(self) + if (DebugToggles.INCLUDE_ONLY_ROOT_WHEN_LOADING_EXH_VERSIONS.enabled) listOf(self) else { newDisplay.mapIndexed { index, newGallery -> val link = newGallery.attr("href") @@ -209,8 +206,7 @@ class EHentai(override val id: Long, }.toObservable() } - override fun fetchPageList(chapter: SChapter) - = fetchChapterPage(chapter, baseUrl + chapter.url).map { + override fun fetchPageList(chapter: SChapter) = fetchChapterPage(chapter, baseUrl + chapter.url).map { it.mapIndexed { i, s -> Page(i, s) } @@ -223,28 +219,28 @@ class EHentai(override val id: Long, val jsoup = it.asJsoup() urls += parseChapterPage(jsoup) val nextUrl = nextPageUrl(jsoup) - if(nextUrl != null) { + if (nextUrl != null) { fetchChapterPage(chapter, nextUrl, urls) } else { Observable.just(urls) } } } - private fun parseChapterPage(response: Element) - = with(response) { + + private fun parseChapterPage(response: Element) = with(response) { select(".gdtm a").map { Pair(it.child(0).attr("alt").toInt(), it.attr("href")) }.sortedBy(Pair::first).map { it.second } } + private fun chapterPageCall(np: String) = client.newCall(chapterPageRequest(np)).asObservableSuccess() private fun chapterPageRequest(np: String) = exGet(np, null, headers) - private fun nextPageUrl(element: Element): String? - = element.select("a[onclick=return false]").last()?.let { + private fun nextPageUrl(element: Element): String? = element.select("a[onclick=return false]").last()?.let { return if (it.text() == ">") it.attr("href") else null } - override fun popularMangaRequest(page: Int) = if(exh) + override fun popularMangaRequest(page: Int) = if (exh) latestUpdatesRequest(page) else exGet("$baseUrl/toplist.php?tl=15&p=${page - 1}", null) // Custom page logic for toplists @@ -254,7 +250,7 @@ class EHentai(override val id: Long, urlImportFetchSearchManga(query) { searchMangaRequestObservable(page, query, filters).flatMap { client.newCall(it).asObservableSuccess() - } .map { response -> + }.map { response -> searchMangaParse(response) } } @@ -263,13 +259,13 @@ class EHentai(override val id: Long, val uri = Uri.parse("$baseUrl$QUERY_PREFIX").buildUpon() uri.appendQueryParameter("f_search", query) filters.forEach { - if(it is UriFilter) it.addToUri(uri) + if (it is UriFilter) it.addToUri(uri) } val request = exGet(uri.toString(), page) // Reverse search results on filter - if(filters.any { it is ReverseFilter && it.state }) { + if (filters.any { it is ReverseFilter && it.state }) { return client.newCall(request) .asObservableSuccess() .map { @@ -290,8 +286,7 @@ class EHentai(override val id: Long, } } - override fun searchMangaRequest(page: Int, query: String, filters: FilterList) - = throw UnsupportedOperationException() + override fun searchMangaRequest(page: Int, query: String, filters: FilterList) = throw UnsupportedOperationException() override fun latestUpdatesRequest(page: Int) = exGet(baseUrl, page) @@ -299,8 +294,7 @@ class EHentai(override val id: Long, override fun searchMangaParse(response: Response) = genericMangaParse(response) override fun latestUpdatesParse(response: Response) = genericMangaParse(response) - fun exGet(url: String, page: Int? = null, additionalHeaders: Headers? = null, cache: Boolean = true) - = GET(page?.let { + fun exGet(url: String, page: Int? = null, additionalHeaders: Headers? = null, cache: Boolean = true) = GET(page?.let { addParam(url, "page", Integer.toString(page - 1)) } ?: url, additionalHeaders?.let { val headers = headers.newBuilder() @@ -311,7 +305,7 @@ class EHentai(override val id: Long, } headers.build() } ?: headers).let { - if(!cache) + if (!cache) it.newBuilder().cacheControl(CacheControl.FORCE_NETWORK).build() else it @@ -327,11 +321,11 @@ class EHentai(override val id: Long, return client.newCall(mangaDetailsRequest(manga)) .asObservableWithAsyncStacktrace() .flatMap { (stacktrace, response) -> - if(response.isSuccessful) { + if (response.isSuccessful) { // Pull to most recent val doc = response.asJsoup() val newerGallery = doc.select("#gnd a").lastOrNull() - val pre = if(newerGallery != null && DebugToggles.PULL_TO_ROOT_WHEN_LOADING_EXH_MANGA_DETAILS.enabled) { + val pre = if (newerGallery != null && DebugToggles.PULL_TO_ROOT_WHEN_LOADING_EXH_MANGA_DETAILS.enabled) { manga.url = EHentaiSearchMetadata.normalizeUrl(newerGallery.attr("href")) client.newCall(mangaDetailsRequest(manga)) .asObservableSuccess().map { it.asJsoup() } @@ -388,7 +382,7 @@ class EHentai(override val id: Long, val left = it.select(".gdt1").text().nullIfBlank()?.trim() val rightElement = it.selectFirst(".gdt2") val right = rightElement.text().nullIfBlank()?.trim() - if(left != null && right != null) { + if (left != null && right != null) { ignore { when (left.removeSuffix(":") .toLowerCase()) { @@ -413,10 +407,10 @@ class EHentai(override val id: Long, } lastUpdateCheck = System.currentTimeMillis() - if(datePosted != null + if (datePosted != null && lastUpdateCheck - datePosted!! > EHentaiUpdateWorkerConstants.GALLERY_AGE_TIME) { aged = true - XLog.d("aged %s - too old", title) + XLog.d("aged %s - too old", title) } //Parse ratings @@ -442,7 +436,7 @@ class EHentai(override val id: Long, RaisedTag( namespace, element.text().trim(), - if(element.hasClass("gtl")) + if (element.hasClass("gtl")) TAG_TYPE_LIGHT else TAG_TYPE_NORMAL @@ -458,11 +452,9 @@ class EHentai(override val id: Long, } } - override fun chapterListParse(response: Response) - = throw UnsupportedOperationException("Unused method was called somehow!") + override fun chapterListParse(response: Response) = throw UnsupportedOperationException("Unused method was called somehow!") - override fun pageListParse(response: Response) - = throw UnsupportedOperationException("Unused method was called somehow!") + override fun pageListParse(response: Response) = throw UnsupportedOperationException("Unused method was called somehow!") override fun fetchImageUrl(page: Page): Observable { return client.newCall(imageUrlRequest(page)) @@ -515,29 +507,29 @@ class EHentai(override val id: Long, return Pair(result as List, favNames!!) } - fun spPref() = if(exh) + fun spPref() = if (exh) prefs.eh_exhSettingsProfile() else prefs.eh_ehSettingsProfile() fun rawCookies(sp: Int): Map { val cookies: MutableMap = mutableMapOf() - if(prefs.enableExhentai().getOrDefault()) { + if (prefs.enableExhentai().getOrDefault()) { cookies[LoginController.MEMBER_ID_COOKIE] = prefs.memberIdVal().get()!! cookies[LoginController.PASS_HASH_COOKIE] = prefs.passHashVal().get()!! cookies[LoginController.IGNEOUS_COOKIE] = prefs.igneousVal().get()!! cookies["sp"] = sp.toString() val sessionKey = prefs.eh_settingsKey().getOrDefault() - if(sessionKey != null) + if (sessionKey != null) cookies["sk"] = sessionKey val sessionCookie = prefs.eh_sessionCookie().getOrDefault() - if(sessionCookie != null) + if (sessionCookie != null) cookies["s"] = sessionCookie val hathPerksCookie = prefs.eh_hathPerksCookies().getOrDefault() - if(hathPerksCookie != null) + if (hathPerksCookie != null) cookies["hath_perks"] = hathPerksCookie } @@ -550,15 +542,12 @@ class EHentai(override val id: Long, return cookies } - fun cookiesHeader(sp: Int = spPref().getOrDefault()) - = buildCookies(rawCookies(sp)) + fun cookiesHeader(sp: Int = spPref().getOrDefault()) = buildCookies(rawCookies(sp)) //Headers - override fun headersBuilder() - = super.headersBuilder().add("Cookie", cookiesHeader())!! + override fun headersBuilder() = super.headersBuilder().add("Cookie", cookiesHeader())!! - fun addParam(url: String, param: String, value: String) - = Uri.parse(url) + fun addParam(url: String, param: String, value: String) = Uri.parse(url) .buildUpon() .appendQueryParameter(param, value) .toString() @@ -586,12 +575,12 @@ class EHentai(override val id: Long, class Watched : Filter.CheckBox("Watched List"), UriFilter { override fun addToUri(builder: Uri.Builder) { - if(state) + if (state) builder.appendPath("watched") } } - class GenreOption(name: String, val genreId: Int): Filter.CheckBox(name, false) + class GenreOption(name: String, val genreId: Int) : Filter.CheckBox(name, false) class GenreGroup : Filter.Group("Genres", listOf( GenreOption("Dōjinshi", 2), GenreOption("Manga", 4), @@ -606,22 +595,22 @@ class EHentai(override val id: Long, )), UriFilter { override fun addToUri(builder: Uri.Builder) { val bits = state.fold(0) { acc, genre -> - if(!genre.state) acc + genre.genreId else acc + if (!genre.state) acc + genre.genreId else acc } builder.appendQueryParameter("f_cats", bits.toString()) } } - class AdvancedOption(name: String, val param: String, defValue: Boolean = false): Filter.CheckBox(name, defValue), UriFilter { + class AdvancedOption(name: String, val param: String, defValue: Boolean = false) : Filter.CheckBox(name, defValue), UriFilter { override fun addToUri(builder: Uri.Builder) { - if(state) + if (state) builder.appendQueryParameter(param, "on") } } open class PageOption(name: String, private val queryKey: String) : Filter.Text(name), UriFilter { override fun addToUri(builder: Uri.Builder) { - if(state.isNotBlank()) { + if (state.isNotBlank()) { if (builder.build().getQueryParameters("f_sp").isEmpty()) { builder.appendQueryParameter("f_sp", "on") } @@ -630,6 +619,7 @@ class EHentai(override val id: Long, } } } + class MinPagesOption : PageOption("Minimum Pages", "f_spf") class MaxPagesOption : PageOption("Maximum Pages", "f_spt") @@ -641,7 +631,7 @@ class EHentai(override val id: Long, "5 stars" )), UriFilter { override fun addToUri(builder: Uri.Builder) { - if(state > 0) { + if (state > 0) { builder.appendQueryParameter("f_srdd", Integer.toString(state + 1)) builder.appendQueryParameter("f_sr", "on") } @@ -664,16 +654,16 @@ class EHentai(override val id: Long, class ReverseFilter : Filter.CheckBox("Reverse search results") - override val name = if(exh) + override val name = if (exh) "ExHentai" else "E-Hentai" - class GalleryNotFoundException(cause: Throwable): RuntimeException("Gallery not found!", cause) + class GalleryNotFoundException(cause: Throwable) : RuntimeException("Gallery not found!", cause) - // === URL IMPORT STUFF + // === URL IMPORT STUFF - override val matchingHosts: List = if(exh) listOf( + override val matchingHosts: List = if (exh) listOf( "exhentai.org" ) else listOf( "g.e-hentai.org", @@ -745,8 +735,7 @@ class EHentai(override val id: Long, "e8e" ) - fun buildCookies(cookies: Map) - = cookies.entries.joinToString(separator = "; ") { + fun buildCookies(cookies: Map) = cookies.entries.joinToString(separator = "; ") { "${URLEncoder.encode(it.key, "UTF-8")}=${URLEncoder.encode(it.value, "UTF-8")}" } diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/all/Hitomi.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/all/Hitomi.kt index c6dc5e99c..58ed0dbf7 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/source/online/all/Hitomi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/online/all/Hitomi.kt @@ -61,7 +61,7 @@ class Hitomi : HttpSource(), LewdSource, UrlImpo private var tagIndexVersionCacheTime: Long = 0 private fun tagIndexVersion(): Single { val sCachedTagIndexVersion = cachedTagIndexVersion - return if(sCachedTagIndexVersion == null + return if (sCachedTagIndexVersion == null || tagIndexVersionCacheTime + INDEX_VERSION_CACHE_TIME_MS < System.currentTimeMillis()) { HitomiNozomi.getIndexVersion(client, "tagindex").subscribeOn(Schedulers.io()).doOnNext { cachedTagIndexVersion = it @@ -76,7 +76,7 @@ class Hitomi : HttpSource(), LewdSource, UrlImpo private var galleryIndexVersionCacheTime: Long = 0 private fun galleryIndexVersion(): Single { val sCachedGalleryIndexVersion = cachedGalleryIndexVersion - return if(sCachedGalleryIndexVersion == null + return if (sCachedGalleryIndexVersion == null || galleryIndexVersionCacheTime + INDEX_VERSION_CACHE_TIME_MS < System.currentTimeMillis()) { HitomiNozomi.getIndexVersion(client, "galleriesindex").subscribeOn(Schedulers.io()).doOnNext { cachedGalleryIndexVersion = it @@ -106,7 +106,7 @@ class Hitomi : HttpSource(), LewdSource, UrlImpo input.select(".gallery-info tr").forEach { val content = it.child(1) - when(it.child(0).text().toLowerCase()) { + when (it.child(0).text().toLowerCase()) { "group" -> { group = content.text() tags += RaisedTag("group", group!!, TAG_TYPE_VIRTUAL) @@ -133,10 +133,10 @@ class Hitomi : HttpSource(), LewdSource, UrlImpo } "tags" -> { tags += content.select("a").map { - val ns = if(it.attr("href").startsWith("/tag/male")) "male" - else if (it.attr("href").startsWith("/tag/female")) "female" - else "misc" - RaisedTag(ns, it.text().dropLast(if (ns=="misc") 0 else 2), TAG_TYPE_DEFAULT) + val ns = if (it.attr("href").startsWith("/tag/male")) "male" + else if (it.attr("href").startsWith("/tag/female")) "female" + else "misc" + RaisedTag(ns, it.text().dropLast(if (ns == "misc") 0 else 2), TAG_TYPE_DEFAULT) } } } @@ -178,8 +178,7 @@ class Hitomi : HttpSource(), LewdSource, UrlImpo * @param query the search query. * @param filters the list of filters to apply. */ - override fun searchMangaRequest(page: Int, query: String, filters: FilterList) - = throw UnsupportedOperationException() + override fun searchMangaRequest(page: Int, query: String, filters: FilterList) = throw UnsupportedOperationException() override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable { return urlImportFetchSearchManga(query) { @@ -192,7 +191,7 @@ class Hitomi : HttpSource(), LewdSource, UrlImpo val hn = Single.zip(tagIndexVersion(), galleryIndexVersion()) { tv, gv -> tv to gv } .map { HitomiNozomi(client, it.first, it.second) } - var base = if(positive.isEmpty()) { + var base = if (positive.isEmpty()) { hn.flatMap { n -> n.getGalleryIdsFromNozomi(null, "index", "all").map { n to it.toSet() } } } else { val q = positive.removeAt(0) @@ -275,7 +274,7 @@ class Hitomi : HttpSource(), LewdSource, UrlImpo private fun parseNozomiPage(array: ByteArray): Observable> { val cursor = ByteCursor(array) - val ids = (1 .. array.size / 4).map { + val ids = (1..array.size / 4).map { cursor.nextInt() } @@ -297,7 +296,7 @@ class Hitomi : HttpSource(), LewdSource, UrlImpo return SManga.create().apply { val titleElement = doc.selectFirst("h1") title = titleElement.text() - thumbnail_url = "https:" + if(prefs.eh_hl_useHighQualityThumbs().getOrDefault()) { + thumbnail_url = "https:" + if (prefs.eh_hl_useHighQualityThumbs().getOrDefault()) { doc.selectFirst("img").attr("data-srcset").substringBefore(' ') } else { doc.selectFirst("img").attr("data-src") @@ -364,16 +363,16 @@ class Hitomi : HttpSource(), LewdSource, UrlImpo val hlId = response.request.url.pathSegments.last().removeSuffix(".js").toLong() val str = response.body!!.string() val json = jsonParser.parse(str.removePrefix("var galleryinfo = ")) - return json["files"].array.mapIndexed { index, jsonElement -> + return json["files"].array.mapIndexed { index, jsonElement -> val hash = jsonElement["hash"].string - val ext = if (jsonElement["haswebp"].string=="0") jsonElement["name"].string.split('.').last() else "webp" - val path = if (jsonElement["haswebp"].string=="0") "images" else "webp" + val ext = if (jsonElement["haswebp"].string == "0") jsonElement["name"].string.split('.').last() else "webp" + val path = if (jsonElement["haswebp"].string == "0") "images" else "webp" val hashPath1 = hash.takeLast(1) val hashPath2 = hash.takeLast(3).take(2) Page( index, "", - "https://${subdomainFromGalleryId(hlId)}a.hitomi.la/$path/$hashPath1/$hashPath2/$hash.$ext" + "https://${subdomainFromGalleryId(hlId)}a.hitomi.la/$path/$hashPath1/$hashPath2/$hash.$ext" ) } } @@ -406,7 +405,7 @@ class Hitomi : HttpSource(), LewdSource, UrlImpo override fun mapUrlToMangaUrl(uri: Uri): String? { val lcFirstPathSegment = uri.pathSegments.firstOrNull()?.toLowerCase() ?: return null - if(lcFirstPathSegment != "manga" && lcFirstPathSegment != "reader") + if (lcFirstPathSegment != "manga" && lcFirstPathSegment != "reader") return null return "https://hitomi.la/manga/${uri.pathSegments[1].substringBefore('.')}.html" @@ -418,7 +417,7 @@ class Hitomi : HttpSource(), LewdSource, UrlImpo private val NUMBER_OF_FRONTENDS = 2 private val DATE_FORMAT by lazy { - if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) SimpleDateFormat("yyyy-MM-dd HH:mm:ssX", Locale.US) else SimpleDateFormat("yyyy-MM-dd HH:mm:ss'-05'", Locale.US) diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/all/NHentai.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/all/NHentai.kt index 5e307ad98..06f1bc62c 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/source/online/all/NHentai.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/online/all/NHentai.kt @@ -42,7 +42,7 @@ class NHentai(context: Context) : HttpSource(), LewdSource { val trimmedIdQuery = query.trim().removePrefix("id:") - val newQuery = if(trimmedIdQuery.toIntOrNull() ?: -1 >= 0) { + val newQuery = if (trimmedIdQuery.toIntOrNull() ?: -1 >= 0) { "$baseUrl/g/$trimmedIdQuery/" } else query @@ -56,15 +56,15 @@ class NHentai(context: Context) : HttpSource(), LewdSource { - val langFilter = filters.filterIsInstance().firstOrNull() + val langFilter = filters.filterIsInstance().firstOrNull() var langFilterString = "" - if (langFilter != null) { - langFilterString = SOURCE_LANG_LIST.first {it.first == langFilter!!.values[langFilter!!.state]}.second + if (langFilter != null) { + langFilterString = SOURCE_LANG_LIST.first { it.first == langFilter!!.values[langFilter!!.state] }.second } - val uri = if(query.isNotBlank()) { + val uri = if (query.isNotBlank()) { Uri.parse("$baseUrl/search/").buildUpon().apply { - appendQueryParameter("q", query+langFilterString) + appendQueryParameter("q", query + langFilterString) } } else { Uri.parse(baseUrl).buildUpon() @@ -73,12 +73,12 @@ class NHentai(context: Context) : HttpSource(), LewdSource().firstOrNull()?.state ?: defaultSortFilterSelection() - if(sortFilter.index == 1) { - if(query.isBlank()) error("You must specify a search query if you wish to sort by popularity!") + if (sortFilter.index == 1) { + if (query.isBlank()) error("You must specify a search query if you wish to sort by popularity!") uri.appendQueryParameter("sort", "popular") } - if(sortFilter.ascending) { + if (sortFilter.ascending) { return client.newCall(nhGet(uri.toString())) .asObservableSuccess() .map { @@ -103,11 +103,9 @@ class NHentai(context: Context) : HttpSource(), LewdSource - if(metadata.mediaId == null) emptyList() + override fun fetchPageList(chapter: SChapter) = getOrLoadMetadata(chapter.mangaId, NHentaiSearchMetadata.nhUrlToId(chapter.url)).map { metadata -> + if (metadata.mediaId == null) emptyList() else metadata.pageImageTypes.mapIndexed { index, s -> val imageUrl = imageUrlFromType(metadata.mediaId!!, index + 1, s) @@ -264,6 +258,7 @@ class NHentai(context: Context) : HttpSource(), LewdSource { - if(it is TextNode) { + if (it is TextNode) { val text = it.text().trim() - if(!text.isBlank()) + if (!text.isBlank()) newAltTitles += text } } "Artist" -> { - if(it is Element && it.tagName() == "a") { + if (it is Element && it.tagName() == "a") { artist = it.text() tags += RaisedTag("artist", it.text().toLowerCase(), TAG_TYPE_VIRTUAL) } } "Genres" -> { - if(it is Element && it.tagName() == "a") + if (it is Element && it.tagName() == "a") tags += RaisedTag(null, it.text().toLowerCase(), TAG_TYPE_DEFAULT) } "Type" -> { - if(it is TextNode) { + if (it is TextNode) { val text = it.text().trim() - if(!text.isBlank()) + if (!text.isBlank()) type = text } } "Status" -> { - if(it is TextNode) { + if (it is TextNode) { val text = it.text().trim() - if(!text.isBlank()) + if (!text.isBlank()) status = text } } @@ -197,8 +197,7 @@ class PervEden(override val id: Long, val pvLang: PervEdenLang) : ParsedHttpSour } } - override fun mangaDetailsParse(document: Document): SManga - = throw UnsupportedOperationException() + override fun mangaDetailsParse(document: Document): SManga = throw UnsupportedOperationException() override fun latestUpdatesRequest(page: Int): Request { val num = when (lang) { @@ -226,18 +225,17 @@ class PervEden(override val id: Long, val pvLang: PervEdenLang) : ParsedHttpSour try { date_upload = DATE_FORMAT.parse(element.getElementsByClass("chapterDate").first().text().trim()).time - } catch(ignored: Exception) {} + } catch (ignored: Exception) { + } } - override fun pageListParse(document: Document) - = document.getElementById("pageSelect").getElementsByTag("option").map { + override fun pageListParse(document: Document) = document.getElementById("pageSelect").getElementsByTag("option").map { Page(it.attr("data-page").toInt() - 1, baseUrl + it.attr("value")) } - override fun imageUrlParse(document: Document) - = "http:" + document.getElementById("mainImg").attr("src")!! + override fun imageUrlParse(document: Document) = "http:" + document.getElementById("mainImg").attr("src")!! - override fun getFilterList() = FilterList ( + override fun getFilterList() = FilterList( AuthorFilter(), ArtistFilter(), TypeFilterGroup(), @@ -253,7 +251,7 @@ class PervEden(override val id: Long, val pvLang: PervEdenLang) : ParsedHttpSour class StatusFilter(n: String, val id: Int) : Filter.CheckBox(n, false), UriFilter { override fun addToUri(builder: Uri.Builder) { - if(state) + if (state) builder.appendQueryParameter("status", id.toString()) } } @@ -302,7 +300,7 @@ class PervEden(override val id: Long, val pvLang: PervEdenLang) : ParsedHttpSour class TypeFilter(n: String, val id: Int) : Filter.CheckBox(n, false), UriFilter { override fun addToUri(builder: Uri.Builder) { - if(state) + if (state) builder.appendQueryParameter("type", id.toString()) } } @@ -310,7 +308,7 @@ class PervEden(override val id: Long, val pvLang: PervEdenLang) : ParsedHttpSour override val matchingHosts = listOf("www.perveden.com") override fun matchesUri(uri: Uri): Boolean { - return super.matchesUri(uri) && uri.pathSegments.firstOrNull()?.toLowerCase() == when(pvLang) { + return super.matchesUri(uri) && uri.pathSegments.firstOrNull()?.toLowerCase() == when (pvLang) { PervEdenLang.en -> "en-manga" PervEdenLang.it -> "it-manga" } diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/english/EightMuses.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/english/EightMuses.kt index a213f2715..cc4b2313d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/source/online/english/EightMuses.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/online/english/EightMuses.kt @@ -32,7 +32,7 @@ import rx.schedulers.Schedulers typealias SiteMap = NakedTrie -class EightMuses: HttpSource(), +class EightMuses : HttpSource(), LewdSource, UrlImportableSource { override val id = EIGHTMUSES_SOURCE_ID @@ -118,7 +118,7 @@ class EightMuses: HttpSource(), * @param filters the list of filters to apply. */ override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { - val urlBuilder = if(!query.isBlank()) { + val urlBuilder = if (!query.isBlank()) { "$baseUrl/search".toHttpUrlOrNull()!! .newBuilder() .addQueryParameter("q", query) @@ -161,11 +161,9 @@ class EightMuses: HttpSource(), throw UnsupportedOperationException("Should not be called!") } - override fun fetchLatestUpdates(page: Int) - = fetchListing(latestUpdatesRequest(page), false) + override fun fetchLatestUpdates(page: Int) = fetchListing(latestUpdatesRequest(page), false) - override fun fetchPopularManga(page: Int) - = fetchListing(popularMangaRequest(page), false) // TODO Dig + override fun fetchPopularManga(page: Int) = fetchListing(popularMangaRequest(page), false) // TODO Dig override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable { return urlImportFetchSearchManga(query) { @@ -190,7 +188,7 @@ class EightMuses: HttpSource(), val onLastPage = doc.selectFirst(".current:nth-last-child(2)") != null return MangasPage( - if(dig) { + if (dig) { contents.albums.flatMap { val href = it.attr("href") val splitHref = href.split('/') @@ -265,14 +263,14 @@ class EightMuses: HttpSource(), val contents = parseSelf(response.asJsoup()) val out = mutableListOf() - if(contents.images.isNotEmpty()) { + if (contents.images.isNotEmpty()) { out += SChapter.create().apply { this.url = url - this.name = if(prefix.isBlank()) ">" else prefix + this.name = if (prefix.isBlank()) ">" else prefix } } - val builtPrefix = if(prefix.isBlank()) "> " else "$prefix > " + val builtPrefix = if (prefix.isBlank()) "> " else "$prefix > " out + contents.albums.flatMap { ele -> fetchAndParseChapterList(builtPrefix + ele.selectFirst(".title-text").text(), ele.attr("href")) @@ -281,6 +279,7 @@ class EightMuses: HttpSource(), } data class SelfContents(val albums: List, val images: List) + private fun parseSelf(doc: Document): SelfContents { // Parse self val gc = doc.select(".gallery .c-tile") @@ -377,7 +376,7 @@ class EightMuses: HttpSource(), override fun mapUrlToMangaUrl(uri: Uri): String? { var path = uri.pathSegments.drop(2) - if(uri.pathSegments[1].toLowerCase() == "picture") { + if (uri.pathSegments[1].toLowerCase() == "picture") { path = path.dropLast(1) } return "/comics/album/${path.joinToString("/")}" diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/english/HBrowse.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/english/HBrowse.kt index 797e3fdf3..18aced414 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/source/online/english/HBrowse.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/online/english/HBrowse.kt @@ -74,8 +74,7 @@ class HBrowse : HttpSource(), LewdSource, UrlIm * * @param page the page number to retrieve. */ - override fun popularMangaRequest(page: Int) - = GET("$baseUrl/browse/title/rank/DESC/$page", headers) + override fun popularMangaRequest(page: Int) = GET("$baseUrl/browse/title/rank/DESC/$page", headers) private fun parseListing(response: Response): MangasPage { val doc = response.asJsoup() @@ -125,8 +124,7 @@ class HBrowse : HttpSource(), LewdSource, UrlIm * @param query the search query. * @param filters the list of filters to apply. */ - override fun searchMangaRequest(page: Int, query: String, filters: FilterList) - = throw UnsupportedOperationException("Should not be called!") + override fun searchMangaRequest(page: Int, query: String, filters: FilterList) = throw UnsupportedOperationException("Should not be called!") private fun fetchSearchMangaInternal(page: Int, query: String, filters: FilterList): Observable { return RxJavaInterop.toV1Single(GlobalScope.async(Dispatchers.IO) { @@ -138,28 +136,28 @@ class HBrowse : HttpSource(), LewdSource, UrlIm // var tagQuery: List>? = null - if(sortFilter != null) { + if (sortFilter != null) { sortFilter.state?.let { state -> - if(query.isNotBlank()) { + if (query.isNotBlank()) { throw IllegalArgumentException("Cannot use sorting while text/tag search is active!") } isSortFilter = true - base = "/browse/title/${SortFilter.SORT_OPTIONS[state.index].first}/${if(state.ascending) "ASC" else "DESC"}" + base = "/browse/title/${SortFilter.SORT_OPTIONS[state.index].first}/${if (state.ascending) "ASC" else "DESC"}" } } - if(base == null) { - base = if(modeFilter != null && modeFilter.state == 1) { + if (base == null) { + base = if (modeFilter != null && modeFilter.state == 1) { tagQuery = searchEngine.parseQuery(query, false).map { when (it) { is Text -> { var minDist = Int.MAX_VALUE.toDouble() // ns, value var minContent: Pair = "" to "" - for(ns in ALL_TAGS) { + for (ns in ALL_TAGS) { val (v, d) = ns.value.nearest(it.rawTextOnly(), minDist) - if(d < minDist) { + if (d < minDist) { minDist = d minContent = ns.key to v } @@ -171,7 +169,7 @@ class HBrowse : HttpSource(), LewdSource, UrlIm val mappedNs = NS_MAPPINGS[it.namespace] ?: it.namespace var key = mappedNs - if(!ALL_TAGS.containsKey(key)) key = ALL_TAGS.keys.sorted().nearest(mappedNs).first + if (!ALL_TAGS.containsKey(key)) key = ALL_TAGS.keys.sorted().nearest(mappedNs).first // Find nearest NS val nsContents = ALL_TAGS[key] @@ -193,18 +191,18 @@ class HBrowse : HttpSource(), LewdSource, UrlIm base += "/$page" - if(isSortFilter) { + if (isSortFilter) { parseListing(client.newCall(GET(baseUrl + base, headers)) .asObservableSuccess() .toSingle() .await(Schedulers.io())) } else { - val body = if(tagQuery != null) { + val body = if (tagQuery != null) { FormBody.Builder() .add("type", "advance") .apply { tagQuery.forEach { - add(it.first + "_" + it.second, if(it.third) "n" else "y") + add(it.first + "_" + it.second, if (it.third) "n" else "y") } } } else { @@ -222,7 +220,7 @@ class HBrowse : HttpSource(), LewdSource, UrlIm .toSingle() .await(Schedulers.io()) - if(!processResponse.isRedirect) + if (!processResponse.isRedirect) throw IllegalStateException("Unexpected process response code!") val sessId = processResponse.headers("Set-Cookie").find { @@ -258,13 +256,13 @@ class HBrowse : HttpSource(), LewdSource, UrlIm // Collection must be sorted and cannot be sorted private fun List.nearest(string: String, maxDist: Double = Int.MAX_VALUE.toDouble()): Pair { val idx = binarySearch(string) - return if(idx < 0) { + return if (idx < 0) { val l = Levenshtein() var minSoFar = maxDist var minIndexSoFar = 0 forEachIndexed { index, s -> val d = l.distance(string, s, ceil(minSoFar).toInt()) - if(d < minSoFar) { + if (d < minSoFar) { minSoFar = d minIndexSoFar = index } @@ -312,7 +310,7 @@ class HBrowse : HttpSource(), LewdSource, UrlIm tags.clear() (tables[""]!! + tables["categories"]!!).forEach { (k, v) -> - when(val lowercaseNs = k.toLowerCase()) { + when (val lowercaseNs = k.toLowerCase()) { "title" -> title = v.text() "length" -> length = v.text().substringBefore(" ").toInt() else -> { @@ -376,8 +374,9 @@ class HBrowse : HttpSource(), LewdSource, UrlIm val doc = response.asJsoup() val basePath = listOf("data") + response.request.url.pathSegments val scripts = doc.getElementsByTag("script").map { it.data() } - for(script in scripts) { - val totalPages = TOTAL_PAGES_REGEX.find(script)?.groupValues?.getOrNull(1)?.toIntOrNull() ?: continue + for (script in scripts) { + val totalPages = TOTAL_PAGES_REGEX.find(script)?.groupValues?.getOrNull(1)?.toIntOrNull() + ?: continue val pageList = PAGE_LIST_REGEX.find(script)?.groupValues?.getOrNull(1) ?: continue return jsonParser.parse(pageList).array.take(totalPages).map { @@ -956,6 +955,7 @@ class HBrowse : HttpSource(), LewdSource, UrlIm ).mapValues { it.value.sorted() } private val TAGS_AS_MARKDOWN = ALL_TAGS.map { (ns, values) -> - "#### $ns\n" + values.map { "- $it" }.joinToString("\n") }.joinToString("\n\n") + "#### $ns\n" + values.map { "- $it" }.joinToString("\n") + }.joinToString("\n\n") } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/english/HentaiCafe.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/english/HentaiCafe.kt index 2ed7896a9..6628e391c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/source/online/english/HentaiCafe.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/online/english/HentaiCafe.kt @@ -98,7 +98,7 @@ class HentaiCafe(delegate: HttpSource) : DelegatedHttpSource(delegate), override fun mapUrlToMangaUrl(uri: Uri): String? { val lcFirstPathSegment = uri.pathSegments.firstOrNull()?.toLowerCase() ?: return null - return if(lcFirstPathSegment == "manga") + return if (lcFirstPathSegment == "manga") "https://hentai.cafe/${uri.pathSegments[2]}" else "https://hentai.cafe/$lcFirstPathSegment" diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Pururin.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Pururin.kt index 0ca525201..e4f4f1b2e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Pururin.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Pururin.kt @@ -32,7 +32,7 @@ class Pururin(delegate: HttpSource) : DelegatedHttpSource(delegate), //Support direct URL importing override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable { val trimmedIdQuery = query.trim().removePrefix("id:") - val newQuery = if(trimmedIdQuery.toIntOrNull() ?: -1 >= 0) { + val newQuery = if (trimmedIdQuery.toIntOrNull() ?: -1 >= 0) { "$baseUrl/gallery/$trimmedIdQuery/-" } else query @@ -68,7 +68,7 @@ class Pururin(delegate: HttpSource) : DelegatedHttpSource(delegate), contentWrapper.select(".table-gallery-info > tbody > tr").forEach { ele -> val key = ele.child(0).text().toLowerCase() val value = ele.child(1) - when(key) { + when (key) { "pages" -> { val split = value.text().split("(").trimAll().dropBlank() diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Tsumino.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Tsumino.kt index 453981e95..df7bdb354 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Tsumino.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Tsumino.kt @@ -25,105 +25,107 @@ import java.text.SimpleDateFormat import java.util.* class Tsumino(delegate: HttpSource) : DelegatedHttpSource(delegate), -LewdSource, UrlImportableSource { - override val metaClass = TsuminoSearchMetadata::class; - override val lang = "en" + LewdSource, UrlImportableSource { + override val metaClass = TsuminoSearchMetadata::class; + override val lang = "en" - //Support direct URL importing - override fun fetchSearchManga(page: Int, query: String, filters: FilterList) = - urlImportFetchSearchManga(query) { - super.fetchSearchManga(page, query, filters) - } - override fun mapUrlToMangaUrl(uri: Uri): String? { - val lcFirstPathSegment = uri.pathSegments.firstOrNull()?.toLowerCase() ?: return null - if(lcFirstPathSegment != "read" && lcFirstPathSegment != "book" && lcFirstPathSegment != "entry") - return null - return "https://tsumino.com/Book/Info/${uri.lastPathSegment}" - } + //Support direct URL importing + override fun fetchSearchManga(page: Int, query: String, filters: FilterList) = + urlImportFetchSearchManga(query) { + super.fetchSearchManga(page, query, filters) + } - override fun fetchMangaDetails(manga: SManga): Observable { - return client.newCall(mangaDetailsRequest(manga)) - .asObservableSuccess() - .flatMap { - parseToManga(manga, it.asJsoup()).andThen(Observable.just(manga)) - } - } + override fun mapUrlToMangaUrl(uri: Uri): String? { + val lcFirstPathSegment = uri.pathSegments.firstOrNull()?.toLowerCase() ?: return null + if (lcFirstPathSegment != "read" && lcFirstPathSegment != "book" && lcFirstPathSegment != "entry") + return null + return "https://tsumino.com/Book/Info/${uri.lastPathSegment}" + } - override fun parseIntoMetadata(metadata: TsuminoSearchMetadata, input: Document) { - with(metadata) { - tmId = TsuminoSearchMetadata.tmIdFromUrl(input.location()).toInt() - tags.clear() + override fun fetchMangaDetails(manga: SManga): Observable { + return client.newCall(mangaDetailsRequest(manga)) + .asObservableSuccess() + .flatMap { + parseToManga(manga, it.asJsoup()).andThen(Observable.just(manga)) + } + } - input.getElementById("Title")?.text()?.let { - title = it.trim() - } + override fun parseIntoMetadata(metadata: TsuminoSearchMetadata, input: Document) { + with(metadata) { + tmId = TsuminoSearchMetadata.tmIdFromUrl(input.location()).toInt() + tags.clear() - input.getElementById("Artist")?.children()?.first()?.text()?.trim()?.let { - tags.add(RaisedTag("artist", it, TAG_TYPE_VIRTUAL)) - artist = it - } + input.getElementById("Title")?.text()?.let { + title = it.trim() + } - input.getElementById("Uploader")?.children()?.first()?.text()?.trim()?.let { - uploader = it - } + input.getElementById("Artist")?.children()?.first()?.text()?.trim()?.let { + tags.add(RaisedTag("artist", it, TAG_TYPE_VIRTUAL)) + artist = it + } - input.getElementById("Uploaded")?.text()?.let { - uploadDate = TM_DATE_FORMAT.parse(it.trim()).time - } + input.getElementById("Uploader")?.children()?.first()?.text()?.trim()?.let { + uploader = it + } - input.getElementById("Pages")?.text()?.let { - length = it.trim().toIntOrNull() - } + input.getElementById("Uploaded")?.text()?.let { + uploadDate = TM_DATE_FORMAT.parse(it.trim()).time + } - input.getElementById("Rating")?.text()?.let { - ratingString = it.trim() - } + input.getElementById("Pages")?.text()?.let { + length = it.trim().toIntOrNull() + } - input.getElementById("Category")?.children()?.first()?.text()?.let { - category = it.trim() - tags.add(RaisedTag("genre", it, TAG_TYPE_VIRTUAL)) - } + input.getElementById("Rating")?.text()?.let { + ratingString = it.trim() + } - input.getElementById("Collection")?.children()?.first()?.text()?.let { - collection = it.trim() - } + input.getElementById("Category")?.children()?.first()?.text()?.let { + category = it.trim() + tags.add(RaisedTag("genre", it, TAG_TYPE_VIRTUAL)) + } - input.getElementById("Group")?.children()?.first()?.text()?.let { - group = it.trim() - tags.add(RaisedTag("group", it, TAG_TYPE_VIRTUAL)) - } + input.getElementById("Collection")?.children()?.first()?.text()?.let { + collection = it.trim() + } - val newParody = mutableListOf() - input.getElementById("Parody")?.children()?.forEach { - val entry = it.text().trim() - newParody.add(entry) - tags.add(RaisedTag("parody", entry, TAG_TYPE_VIRTUAL)) - } - parody = newParody + input.getElementById("Group")?.children()?.first()?.text()?.let { + group = it.trim() + tags.add(RaisedTag("group", it, TAG_TYPE_VIRTUAL)) + } - val newCharacter = mutableListOf() - input.getElementById("Character")?.children()?.forEach { - val entry = it.text().trim() - newCharacter.add(entry) - tags.add(RaisedTag("character", entry, TAG_TYPE_VIRTUAL)) - } - character = newCharacter + val newParody = mutableListOf() + input.getElementById("Parody")?.children()?.forEach { + val entry = it.text().trim() + newParody.add(entry) + tags.add(RaisedTag("parody", entry, TAG_TYPE_VIRTUAL)) + } + parody = newParody - input.getElementById("Tag")?.children()?.let { - tags.addAll(it.map { - RaisedTag(null, it.text().trim(), TAG_TYPE_DEFAULT) - }) - } - } - } - override val matchingHosts = listOf( - "www.tsumino.com", - "tsumino.com" - ) + val newCharacter = mutableListOf() + input.getElementById("Character")?.children()?.forEach { + val entry = it.text().trim() + newCharacter.add(entry) + tags.add(RaisedTag("character", entry, TAG_TYPE_VIRTUAL)) + } + character = newCharacter - companion object { - val jsonParser by lazy {JsonParser()} - val TM_DATE_FORMAT = SimpleDateFormat("yyyy MMM dd", Locale.US) - private val ASP_NET_COOKIE_NAME = "ASP.NET_SessionId" - } + input.getElementById("Tag")?.children()?.let { + tags.addAll(it.map { + RaisedTag(null, it.text().trim(), TAG_TYPE_DEFAULT) + }) + } + } + } + + override val matchingHosts = listOf( + "www.tsumino.com", + "tsumino.com" + ) + + companion object { + val jsonParser by lazy { JsonParser() } + val TM_DATE_FORMAT = SimpleDateFormat("yyyy MMM dd", Locale.US) + private val ASP_NET_COOKIE_NAME = "ASP.NET_SessionId" + } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/ExtensionFilterController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/ExtensionFilterController.kt index 5675b6d40..448d505b4 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/ExtensionFilterController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/ExtensionFilterController.kt @@ -19,13 +19,13 @@ class ExtensionFilterController : SettingsController() { val activeLangs = preferences.enabledLanguages().get() val availableLangs = - Injekt.get().availableExtensions.groupBy { - it.lang - }.keys.minus("all").partition { - it in activeLangs - }.let { - it.first + it.second - } + Injekt.get().availableExtensions.groupBy { + it.lang + }.keys.minus("all").partition { + it in activeLangs + }.let { + it.first + it.second + } availableLangs.forEach { switchPreference { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourcePresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourcePresenter.kt index 47cd440f8..b16d8cf79 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourcePresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourcePresenter.kt @@ -427,14 +427,14 @@ open class BrowseSourcePresenter( return loaded.map { try { val id = it.substringBefore(':').toLong() - if(id != source.id) return@map null + if (id != source.id) return@map null val content = jsonParser.parse(it.substringAfter(':')).obj val originalFilters = source.getFilterList() filterSerializer.deserialize(originalFilters, content["filters"].array) EXHSavedSearch(content["name"].string, content["query"].string, originalFilters) - } catch(t: RuntimeException) { + } catch (t: RuntimeException) { // Load failed Timber.e(t, "Failed to load saved search!") t.printStackTrace() diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryAdapter.kt index cb9e0ba98..86cee9f75 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryAdapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryAdapter.kt @@ -36,7 +36,9 @@ class LibraryCategoryAdapter(view: LibraryCategoryView) : // Keep compatibility as searchText field was replaced when we upgraded FlexibleAdapter var searchText get() = getFilter(String::class.java) ?: "" - set(value) { setFilter(value) } + set(value) { + setFilter(value) + } // EXH <-- /** @@ -73,7 +75,7 @@ class LibraryCategoryAdapter(view: LibraryCategoryView) : // we want to perform a no-op filter) suspend fun performFilter(cScope: CoroutineScope) { lastFilterJob?.cancel() - if(mangas.isNotEmpty() && searchText.isNotBlank()) { + if (mangas.isNotEmpty() && searchText.isNotBlank()) { val savedSearchText = searchText val job = cScope.launch(Dispatchers.IO) { @@ -90,7 +92,7 @@ class LibraryCategoryAdapter(view: LibraryCategoryView) : val mangaWithMetaIdsQuery = db.getIdsOfFavoriteMangaWithMetadata().await() val mangaWithMetaIds = LongArray(mangaWithMetaIdsQuery.count) - if(mangaWithMetaIds.isNotEmpty()) { + if (mangaWithMetaIds.isNotEmpty()) { val mangaIdCol = mangaWithMetaIdsQuery.getColumnIndex(MangaTable.COL_ID) mangaWithMetaIdsQuery.moveToFirst() while (!mangaWithMetaIdsQuery.isAfterLast) { @@ -104,7 +106,7 @@ class LibraryCategoryAdapter(view: LibraryCategoryView) : ensureActive() // Fail early when cancelled val convertedResult = LongArray(queryResult.count) - if(convertedResult.isNotEmpty()) { + if (convertedResult.isNotEmpty()) { val mangaIdCol = queryResult.getColumnIndex(SearchMetadataTable.COL_MANGA_ID) queryResult.moveToFirst() while (!queryResult.isAfterLast) { @@ -119,11 +121,11 @@ class LibraryCategoryAdapter(view: LibraryCategoryView) : // Flow the mangas to allow cancellation of this filter operation mangas.asFlow().cancellable().filter { item -> - if(isLewdSource(item.manga.source)) { + if (isLewdSource(item.manga.source)) { val mangaId = item.manga.id ?: -1 - if(convertedResult.binarySearch(mangaId) < 0) { + if (convertedResult.binarySearch(mangaId) < 0) { // Check if this manga even has metadata - if(mangaWithMetaIds.binarySearch(mangaId) < 0) { + if (mangaWithMetaIds.binarySearch(mangaId) < 0) { // No meta? Filter using title item.filter(savedSearchText) } else false @@ -134,7 +136,7 @@ class LibraryCategoryAdapter(view: LibraryCategoryView) : }.toList() } catch (e: Exception) { // Do not catch cancellations - if(e is CancellationException) throw e + if (e is CancellationException) throw e Timber.w(e, "Could not filter mangas!") mangas diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoPresenter.kt index e4127cdde..aebcd5dd3 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoPresenter.kt @@ -182,10 +182,10 @@ class MangaInfoPresenter( suspend fun smartSearchMerge(manga: Manga, originalMangaId: Long): Manga { val originalManga = db.getManga(originalMangaId).await() ?: throw IllegalArgumentException("Unknown manga ID: $originalMangaId") - val toInsert = if(originalManga.source == MERGED_SOURCE_ID) { + val toInsert = if (originalManga.source == MERGED_SOURCE_ID) { originalManga.apply { val originalChildren = MergedSource.MangaConfig.readFromUrl(gson, url).children - if(originalChildren.any { it.source == manga.source && it.url == manga.url }) + if (originalChildren.any { it.source == manga.source && it.url == manga.url }) throw IllegalArgumentException("This manga is already merged with the current manga!") url = MergedSource.MangaConfig(originalChildren + MergedSource.MangaSource( @@ -216,9 +216,9 @@ class MangaInfoPresenter( // Note that if the manga are merged in a different order, this won't trigger, but I don't care lol val existingManga = db.getManga(toInsert.url, toInsert.source).await() - if(existingManga != null) { + if (existingManga != null) { withContext(NonCancellable) { - if(toInsert.id != null) { + if (toInsert.id != null) { db.deleteManga(toInsert).await() } } @@ -230,7 +230,7 @@ class MangaInfoPresenter( toInsert.initialized = false val newId = db.insertManga(toInsert).await().insertedId() - if(newId != null) toInsert.id = newId + if (newId != null) toInsert.id = newId return toInsert } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/SaveImageNotifier.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/SaveImageNotifier.kt index 2b9fe851d..0f31284f2 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/SaveImageNotifier.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/SaveImageNotifier.kt @@ -37,12 +37,12 @@ class SaveImageNotifier(private val context: Context) { */ fun onComplete(file: File) { val bitmap = GlideApp.with(context) - .asBitmap() - .load(file) - .diskCacheStrategy(DiskCacheStrategy.NONE) - .skipMemoryCache(true) - .submit(720, 1280) - .get() + .asBitmap() + .load(file) + .diskCacheStrategy(DiskCacheStrategy.NONE) + .skipMemoryCache(true) + .submit(720, 1280) + .get() if (bitmap != null) { showCompleteNotification(file, bitmap) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/DirectoryPageLoader.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/DirectoryPageLoader.kt index 95e7c6e5e..77f921b5c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/DirectoryPageLoader.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/DirectoryPageLoader.kt @@ -19,16 +19,16 @@ class DirectoryPageLoader(val file: File) : PageLoader() { */ override fun getPages(): Observable> { return file.listFiles() - .filter { !it.isDirectory && ImageUtil.isImage(it.name) { FileInputStream(it) } } - .sortedWith(Comparator { f1, f2 -> f1.name.compareToCaseInsensitiveNaturalOrder(f2.name) }) - .mapIndexed { i, file -> - val streamFn = { FileInputStream(file) } - ReaderPage(i).apply { - stream = streamFn - status = Page.READY + .filter { !it.isDirectory && ImageUtil.isImage(it.name) { FileInputStream(it) } } + .sortedWith(Comparator { f1, f2 -> f1.name.compareToCaseInsensitiveNaturalOrder(f2.name) }) + .mapIndexed { i, file -> + val streamFn = { FileInputStream(file) } + ReaderPage(i).apply { + stream = streamFn + status = Page.READY + } } - } - .let { Observable.just(it) } + .let { Observable.just(it) } } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/EpubPageLoader.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/EpubPageLoader.kt index 00895e901..f18e12502 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/EpubPageLoader.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/EpubPageLoader.kt @@ -30,14 +30,14 @@ class EpubPageLoader(file: File) : PageLoader() { */ override fun getPages(): Observable> { return epub.getImagesFromPages() - .mapIndexed { i, path -> - val streamFn = { epub.getInputStream(epub.getEntry(path)!!) } - ReaderPage(i).apply { - stream = streamFn - status = Page.READY + .mapIndexed { i, path -> + val streamFn = { epub.getInputStream(epub.getEntry(path)!!) } + ReaderPage(i).apply { + stream = streamFn + status = Page.READY + } } - } - .let { Observable.just(it) } + .let { Observable.just(it) } } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/RarPageLoader.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/RarPageLoader.kt index 37b35a97c..814a22185 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/RarPageLoader.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/RarPageLoader.kt @@ -43,17 +43,17 @@ class RarPageLoader(file: File) : PageLoader() { */ override fun getPages(): Observable> { return archive.fileHeaders - .filter { !it.isDirectory && ImageUtil.isImage(it.fileNameString) { archive.getInputStream(it) } } - .sortedWith(Comparator { f1, f2 -> f1.fileNameString.compareToCaseInsensitiveNaturalOrder(f2.fileNameString) }) - .mapIndexed { i, header -> - val streamFn = { getStream(header) } + .filter { !it.isDirectory && ImageUtil.isImage(it.fileNameString) { archive.getInputStream(it) } } + .sortedWith(Comparator { f1, f2 -> f1.fileNameString.compareToCaseInsensitiveNaturalOrder(f2.fileNameString) }) + .mapIndexed { i, header -> + val streamFn = { getStream(header) } - ReaderPage(i).apply { - stream = streamFn - status = Page.READY + ReaderPage(i).apply { + stream = streamFn + status = Page.READY + } } - } - .let { Observable.just(it) } + .let { Observable.just(it) } } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/ZipPageLoader.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/ZipPageLoader.kt index e2cca59fe..1e350981f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/ZipPageLoader.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/ZipPageLoader.kt @@ -33,16 +33,16 @@ class ZipPageLoader(file: File) : PageLoader() { */ override fun getPages(): Observable> { return zip.entries().toList() - .filter { !it.isDirectory && ImageUtil.isImage(it.name) { zip.getInputStream(it) } } - .sortedWith(Comparator { f1, f2 -> f1.name.compareToCaseInsensitiveNaturalOrder(f2.name) }) - .mapIndexed { i, entry -> - val streamFn = { zip.getInputStream(entry) } - ReaderPage(i).apply { - stream = streamFn - status = Page.READY + .filter { !it.isDirectory && ImageUtil.isImage(it.name) { zip.getInputStream(it) } } + .sortedWith(Comparator { f1, f2 -> f1.name.compareToCaseInsensitiveNaturalOrder(f2.name) }) + .mapIndexed { i, entry -> + val streamFn = { zip.getInputStream(entry) } + ReaderPage(i).apply { + stream = streamFn + status = Page.READY + } } - } - .let { Observable.just(it) } + .let { Observable.just(it) } } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonRecyclerView.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonRecyclerView.kt index 91c839ec8..85cf08e5d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonRecyclerView.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonRecyclerView.kt @@ -146,13 +146,13 @@ open class WebtoonRecyclerView @JvmOverloads constructor( } animate() - .apply { - newX?.let { x(it) } - newY?.let { y(it) } - } - .setInterpolator(DecelerateInterpolator()) - .setDuration(400) - .start() + .apply { + newX?.let { x(it) } + newY?.let { y(it) } + } + .setInterpolator(DecelerateInterpolator()) + .setDuration(400) + .start() return true } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsEhController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsEhController.kt index fe8d1e9e5..21e88db99 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsEhController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsEhController.kt @@ -85,7 +85,7 @@ class SettingsEhController : SettingsController() { onChange { newVal -> newVal as Boolean - if(!newVal) { + if (!newVal) { preferences.enableExhentai().set(false) true } else { @@ -226,7 +226,7 @@ class SettingsEhController : SettingsController() { defaultValue = "0" preferences.eh_autoUpdateFrequency().asObservable().subscribeUntilDestroy { newVal -> - summary = if(newVal == 0) { + summary = if (newVal == 0) { "${context.getString(R.string.app_name)} will currently never check galleries in your library for updates." } else { "${context.getString(R.string.app_name)} checks/updates galleries in batches. " + diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/chapter/ChapterSourceSync.kt b/app/src/main/java/eu/kanade/tachiyomi/util/chapter/ChapterSourceSync.kt index 043124113..56073410d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/chapter/ChapterSourceSync.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/chapter/ChapterSourceSync.kt @@ -124,9 +124,9 @@ fun syncChaptersWithSource( } // --> EXH (carry over reading progress) - if(manga.source == EH_SOURCE_ID || manga.source == EXH_SOURCE_ID) { + if (manga.source == EH_SOURCE_ID || manga.source == EXH_SOURCE_ID) { val finalAdded = toAdd.subtract(readded) - if(finalAdded.isNotEmpty()) { + if (finalAdded.isNotEmpty()) { val max = dbChapters.maxBy { it.last_page_read } if (max != null && max.last_page_read > 0) { for (chapter in finalAdded) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/storage/EpubFile.kt b/app/src/main/java/eu/kanade/tachiyomi/util/storage/EpubFile.kt index 7f1e966f6..58953e00d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/storage/EpubFile.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/storage/EpubFile.kt @@ -139,8 +139,8 @@ class EpubFile(file: File) : Closeable { */ private fun getPagesFromDocument(document: Document): List { val pages = document.select("manifest > item") - .filter { "application/xhtml+xml" == it.attr("media-type") } - .associateBy { it.attr("id") } + .filter { "application/xhtml+xml" == it.attr("media-type") } + .associateBy { it.attr("id") } val spine = document.select("spine > itemref").map { it.attr("idref") } return spine.mapNotNull { pages[it] }.map { it.attr("href") }