From 852f31574f3bc53f8eee6f7f7dd0a5c39fdd3486 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Sun, 23 Jan 2022 07:49:03 +0200 Subject: [PATCH 1/5] Fix MangaRead parse #87 --- app/build.gradle | 4 ++-- .../kotatsu/core/parser/site/MangareadRepository.kt | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 68bb3d879..9f01df521 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -13,8 +13,8 @@ android { applicationId 'org.koitharu.kotatsu' minSdkVersion 21 targetSdkVersion 31 - versionCode 378 - versionName '2.1.2' + versionCode 379 + versionName '2.1.3' generatedDensities = [] testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" diff --git a/app/src/main/java/org/koitharu/kotatsu/core/parser/site/MangareadRepository.kt b/app/src/main/java/org/koitharu/kotatsu/core/parser/site/MangareadRepository.kt index 7999fb7f2..2b2f9b8cd 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/parser/site/MangareadRepository.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/parser/site/MangareadRepository.kt @@ -151,8 +151,10 @@ class MangareadRepository( ?.selectFirst("div.reading-content") ?: throw ParseException("Root not found") return root.select("div.page-break").map { div -> - val img = div.selectFirst("img") - val url = img?.relUrl("src") ?: parseFailed("Page image not found") + val img = div.selectFirst("img") ?: parseFailed("Page image not found") + val url = img.relUrl("data-src").ifEmpty { + img.relUrl("src") + } MangaPage( id = generateUid(url), url = url, From 2a7761dbc3fa901721f5fb4b6d0d363b292f40fe Mon Sep 17 00:00:00 2001 From: Koitharu Date: Sun, 23 Jan 2022 08:05:07 +0200 Subject: [PATCH 2/5] Fix widgets #86 --- .../java/org/koitharu/kotatsu/utils/PendingIntentCompat.kt | 6 ++++++ .../koitharu/kotatsu/widget/recent/RecentWidgetProvider.kt | 2 +- .../koitharu/kotatsu/widget/shelf/ShelfWidgetProvider.kt | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/PendingIntentCompat.kt b/app/src/main/java/org/koitharu/kotatsu/utils/PendingIntentCompat.kt index 4169a571d..c99050819 100644 --- a/app/src/main/java/org/koitharu/kotatsu/utils/PendingIntentCompat.kt +++ b/app/src/main/java/org/koitharu/kotatsu/utils/PendingIntentCompat.kt @@ -10,4 +10,10 @@ object PendingIntentCompat { } else { 0 } + + val FLAG_MUTABLE = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + PendingIntent.FLAG_MUTABLE + } else { + 0 + } } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/widget/recent/RecentWidgetProvider.kt b/app/src/main/java/org/koitharu/kotatsu/widget/recent/RecentWidgetProvider.kt index 63a2816ae..a5c6bb748 100644 --- a/app/src/main/java/org/koitharu/kotatsu/widget/recent/RecentWidgetProvider.kt +++ b/app/src/main/java/org/koitharu/kotatsu/widget/recent/RecentWidgetProvider.kt @@ -31,7 +31,7 @@ class RecentWidgetProvider : AppWidgetProvider() { context, 0, intent, - PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_MUTABLE ) ) views.setEmptyView(R.id.stackView, R.id.textView_holder) diff --git a/app/src/main/java/org/koitharu/kotatsu/widget/shelf/ShelfWidgetProvider.kt b/app/src/main/java/org/koitharu/kotatsu/widget/shelf/ShelfWidgetProvider.kt index 334941d51..7b3ba2059 100644 --- a/app/src/main/java/org/koitharu/kotatsu/widget/shelf/ShelfWidgetProvider.kt +++ b/app/src/main/java/org/koitharu/kotatsu/widget/shelf/ShelfWidgetProvider.kt @@ -31,7 +31,7 @@ class ShelfWidgetProvider : AppWidgetProvider() { context, 0, intent, - PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_MUTABLE ) ) views.setEmptyView(R.id.gridView, R.id.textView_holder) From fc3efbabbd522a126953e1c9d6cd3582271742bf Mon Sep 17 00:00:00 2001 From: Koitharu Date: Sun, 23 Jan 2022 08:14:56 +0200 Subject: [PATCH 3/5] Fix missing fragment crash #91 --- app/proguard-rules.pro | 1 + 1 file changed, 1 insertion(+) diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 74c093891..5d74551b7 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -7,5 +7,6 @@ public static void checkParameterIsNotNull(...); public static void checkNotNullParameter(...); } +-keep public class ** extends org.koitharu.kotatsu.base.ui.BaseFragment -keep class org.koitharu.kotatsu.core.db.entity.* { *; } -dontwarn okhttp3.internal.platform.ConscryptPlatform \ No newline at end of file From b6e13de73f97a5798820e37456bd8629b19abefa Mon Sep 17 00:00:00 2001 From: Koitharu Date: Sun, 23 Jan 2022 09:46:26 +0200 Subject: [PATCH 4/5] Fix MangaTown licensed chapters --- .../core/parser/RemoteMangaRepository.kt | 4 ++- .../core/parser/site/MangaTownRepository.kt | 28 ++++++++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/org/koitharu/kotatsu/core/parser/RemoteMangaRepository.kt b/app/src/main/java/org/koitharu/kotatsu/core/parser/RemoteMangaRepository.kt index ef4c55817..0062bc1d0 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/parser/RemoteMangaRepository.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/parser/RemoteMangaRepository.kt @@ -53,8 +53,10 @@ abstract class RemoteMangaRepository( if (subdomain != null) { append(subdomain) append('.') + append(conf.getDomain(defaultDomain).removePrefix("www.")) + } else { + append(conf.getDomain(defaultDomain)) } - append(conf.getDomain(defaultDomain)) append(this@withDomain) } else -> this diff --git a/app/src/main/java/org/koitharu/kotatsu/core/parser/site/MangaTownRepository.kt b/app/src/main/java/org/koitharu/kotatsu/core/parser/site/MangaTownRepository.kt index 7f1285369..afe3750c3 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/parser/site/MangaTownRepository.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/parser/site/MangaTownRepository.kt @@ -128,7 +128,7 @@ class MangaTownRepository(loaderContext: MangaLoaderContext) : scanlator = null, branch = null, ) - } + } ?: bypassLicensedChapters(manga) ) } @@ -191,6 +191,32 @@ class MangaTownRepository(loaderContext: MangaLoaderContext) : map[SourceSettings.KEY_USE_SSL] = true } + private suspend fun bypassLicensedChapters(manga: Manga): List { + val doc = loaderContext.httpGet(manga.url.withDomain("m")).parseHtml() + val list = doc.body().selectFirst("ul.detail-ch-list") ?: return emptyList() + val dateFormat = SimpleDateFormat("MMM dd,yyyy", Locale.US) + return list.select("li").asReversed().mapIndexedNotNull { i, li -> + val a = li.selectFirst("a") ?: return@mapIndexedNotNull null + val href = a.relUrl("href") + val name = a.selectFirst("span.vol")?.text().orEmpty().ifEmpty { + a.ownText() + } + MangaChapter( + id = generateUid(href), + url = href, + source = MangaSource.MANGATOWN, + number = i + 1, + uploadDate = parseChapterDate( + dateFormat, + li.selectFirst("span.time")?.text() + ), + name = name.ifEmpty { "${manga.title} - ${i + 1}" }, + scanlator = null, + branch = null, + ) + } + } + private fun String.parseTagKey() = split('/').findLast { TAG_REGEX matches it } private companion object { From 2535739c2b30934bba8594045a2e2a58d41a628a Mon Sep 17 00:00:00 2001 From: Koitharu Date: Sun, 23 Jan 2022 10:13:32 +0200 Subject: [PATCH 5/5] Enhance download cancellation in blocking io tasks #90 --- .../download/domain/DownloadManager.kt | 2 +- .../koitharu/kotatsu/local/data/MangaZip.kt | 8 +-- .../kotatsu/local/data/WritableCbzFile.kt | 58 +++++++++---------- 3 files changed, 34 insertions(+), 34 deletions(-) diff --git a/app/src/main/java/org/koitharu/kotatsu/download/domain/DownloadManager.kt b/app/src/main/java/org/koitharu/kotatsu/download/domain/DownloadManager.kt index 75905aa51..1a36ec7fc 100644 --- a/app/src/main/java/org/koitharu/kotatsu/download/domain/DownloadManager.kt +++ b/app/src/main/java/org/koitharu/kotatsu/download/domain/DownloadManager.kt @@ -145,7 +145,7 @@ class DownloadManager( while (true) { try { val response = call.clone().await() - withContext(Dispatchers.IO) { + runInterruptible(Dispatchers.IO) { file.outputStream().use { out -> checkNotNull(response.body).byteStream().copyTo(out) } diff --git a/app/src/main/java/org/koitharu/kotatsu/local/data/MangaZip.kt b/app/src/main/java/org/koitharu/kotatsu/local/data/MangaZip.kt index 2904910d6..c9d93f147 100644 --- a/app/src/main/java/org/koitharu/kotatsu/local/data/MangaZip.kt +++ b/app/src/main/java/org/koitharu/kotatsu/local/data/MangaZip.kt @@ -31,7 +31,7 @@ class MangaZip(val file: File) { return writableCbz.flush() } - fun addCover(file: File, ext: String) { + suspend fun addCover(file: File, ext: String) { val name = buildString { append(FILENAME_PATTERN.format(0, 0)) if (ext.isNotEmpty() && ext.length <= 4) { @@ -39,11 +39,11 @@ class MangaZip(val file: File) { append(ext) } } - writableCbz[name] = file + writableCbz.put(name, file) index.setCoverEntry(name) } - fun addPage(chapter: MangaChapter, file: File, pageNumber: Int, ext: String) { + suspend fun addPage(chapter: MangaChapter, file: File, pageNumber: Int, ext: String) { val name = buildString { append(FILENAME_PATTERN.format(chapter.number, pageNumber)) if (ext.isNotEmpty() && ext.length <= 4) { @@ -51,7 +51,7 @@ class MangaZip(val file: File) { append(ext) } } - writableCbz[name] = file + writableCbz.put(name, file) index.addChapter(chapter) } diff --git a/app/src/main/java/org/koitharu/kotatsu/local/data/WritableCbzFile.kt b/app/src/main/java/org/koitharu/kotatsu/local/data/WritableCbzFile.kt index 5a591740f..b7c5f7b9f 100644 --- a/app/src/main/java/org/koitharu/kotatsu/local/data/WritableCbzFile.kt +++ b/app/src/main/java/org/koitharu/kotatsu/local/data/WritableCbzFile.kt @@ -1,8 +1,7 @@ package org.koitharu.kotatsu.local.data import androidx.annotation.CheckResult -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext +import kotlinx.coroutines.* import java.io.File import java.io.FileInputStream import java.io.FileOutputStream @@ -27,11 +26,13 @@ class WritableCbzFile(private val file: File) { } ZipInputStream(FileInputStream(file)).use { zip -> var entry = zip.nextEntry - while (entry != null) { + while (entry != null && currentCoroutineContext().isActive) { val target = File(dir.path + File.separator + entry.name) - target.parentFile?.mkdirs() - target.outputStream().use { out -> - zip.copyTo(out) + runInterruptible { + target.parentFile?.mkdirs() + target.outputStream().use { out -> + zip.copyTo(out) + } } zip.closeEntry() entry = zip.nextEntry @@ -51,11 +52,13 @@ class WritableCbzFile(private val file: File) { tempFile.delete() } try { - ZipOutputStream(FileOutputStream(tempFile)).use { zip -> - dir.listFiles()?.forEach { - zipFile(it, it.name, zip) + runInterruptible { + ZipOutputStream(FileOutputStream(tempFile)).use { zip -> + dir.listFiles()?.forEach { + zipFile(it, it.name, zip) + } + zip.flush() } - zip.flush() } tempFile.renameTo(file) } finally { @@ -67,29 +70,26 @@ class WritableCbzFile(private val file: File) { operator fun get(name: String) = File(dir, name) - operator fun set(name: String, file: File) { + suspend fun put(name: String, file: File) = runInterruptible(Dispatchers.IO) { file.copyTo(this[name], overwrite = true) } - companion object { - - private fun zipFile(fileToZip: File, fileName: String, zipOut: ZipOutputStream) { - if (fileToZip.isDirectory) { - if (fileName.endsWith("/")) { - zipOut.putNextEntry(ZipEntry(fileName)) - } else { - zipOut.putNextEntry(ZipEntry("$fileName/")) - } - zipOut.closeEntry() - fileToZip.listFiles()?.forEach { childFile -> - zipFile(childFile, "$fileName/${childFile.name}", zipOut) - } + private fun zipFile(fileToZip: File, fileName: String, zipOut: ZipOutputStream) { + if (fileToZip.isDirectory) { + if (fileName.endsWith("/")) { + zipOut.putNextEntry(ZipEntry(fileName)) } else { - FileInputStream(fileToZip).use { fis -> - val zipEntry = ZipEntry(fileName) - zipOut.putNextEntry(zipEntry) - fis.copyTo(zipOut) - } + zipOut.putNextEntry(ZipEntry("$fileName/")) + } + zipOut.closeEntry() + fileToZip.listFiles()?.forEach { childFile -> + zipFile(childFile, "$fileName/${childFile.name}", zipOut) + } + } else { + FileInputStream(fileToZip).use { fis -> + val zipEntry = ZipEntry(fileName) + zipOut.putNextEntry(zipEntry) + fis.copyTo(zipOut) } } }