From 7ebb98ce06f610f111b7a02f3a9ab1bdf448c795 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Sun, 13 Feb 2022 08:50:41 +0200 Subject: [PATCH 1/5] Allow overwrite non-empty download directory #99 --- .../java/org/koitharu/kotatsu/local/data/MangaZip.kt | 2 +- .../org/koitharu/kotatsu/local/data/WritableCbzFile.kt | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) 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 c9d93f147..533c619a8 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 @@ -16,7 +16,7 @@ class MangaZip(val file: File) { private var index = MangaIndex(null) suspend fun prepare(manga: Manga) { - writableCbz.prepare() + writableCbz.prepare(overwrite = true) index = MangaIndex(writableCbz[INDEX_ENTRY].takeIfReadable()?.readText()) index.setMangaInfo(manga, append = true) } 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 fbc2637aa..fe61169b2 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 @@ -14,9 +14,13 @@ class WritableCbzFile(private val file: File) { private val dir = File(file.parentFile, file.nameWithoutExtension) - suspend fun prepare() = withContext(Dispatchers.IO) { - check(dir.list().isNullOrEmpty()) { - "Dir ${dir.name} is not empty" + suspend fun prepare(overwrite: Boolean) = withContext(Dispatchers.IO) { + if (!dir.list().isNullOrEmpty()) { + if (overwrite) { + dir.deleteRecursively() + } else { + throw IllegalStateException("Dir ${dir.name} is not empty") + } } if (!dir.exists()) { dir.mkdir() From 2f3b1f397cce2d5bc442fc78d1cc1eb0d7883217 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Sun, 20 Feb 2022 18:40:47 +0200 Subject: [PATCH 2/5] Fix Remanga source and check for paid chapters #101 --- .../core/parser/site/RemangaRepository.kt | 33 +++++++++++++------ 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/org/koitharu/kotatsu/core/parser/site/RemangaRepository.kt b/app/src/main/java/org/koitharu/kotatsu/core/parser/site/RemangaRepository.kt index 2319dfcd2..d6c047363 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/parser/site/RemangaRepository.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/parser/site/RemangaRepository.kt @@ -9,6 +9,7 @@ import org.koitharu.kotatsu.core.model.* import org.koitharu.kotatsu.core.parser.MangaRepositoryAuthProvider import org.koitharu.kotatsu.core.parser.RemoteMangaRepository import org.koitharu.kotatsu.utils.ext.* +import java.text.DateFormat import java.text.SimpleDateFormat import java.util.* @@ -32,7 +33,7 @@ class RemangaRepository(loaderContext: MangaLoaderContext) : RemoteMangaReposito offset: Int, query: String?, tags: Set?, - sortOrder: SortOrder? + sortOrder: SortOrder?, ): List { copyCookies() val domain = getDomain() @@ -118,7 +119,7 @@ class RemangaRepository(loaderContext: MangaLoaderContext) : RemoteMangaReposito chapters = chapters.mapIndexed { i, jo -> val id = jo.getLong("id") val name = jo.getString("name").toTitleCase(Locale.ROOT) - val publishers = jo.getJSONArray("publishers") + val publishers = jo.optJSONArray("publishers") MangaChapter( id = generateUid(id), url = "/api/titles/chapters/$id/", @@ -135,7 +136,7 @@ class RemangaRepository(loaderContext: MangaLoaderContext) : RemoteMangaReposito } }, uploadDate = dateFormat.tryParse(jo.getString("upload_date")), - scanlator = publishers.optJSONObject(0)?.getStringOrNull("name"), + scanlator = publishers?.optJSONObject(0)?.getStringOrNull("name"), source = MangaSource.REMANGA, branch = null, ) @@ -146,16 +147,28 @@ class RemangaRepository(loaderContext: MangaLoaderContext) : RemoteMangaReposito override suspend fun getPages(chapter: MangaChapter): List { val referer = "https://${getDomain()}/" val content = loaderContext.httpGet(chapter.url.withDomain(subdomain = "api")).parseJson() - .getJSONObject("content").getJSONArray("pages") - val pages = ArrayList(content.length()) - for (i in 0 until content.length()) { - when (val item = content.get(i)) { - is JSONObject -> pages += parsePage(item, referer) - is JSONArray -> item.mapTo(pages) { parsePage(it, referer) } + .getJSONObject("content") + val pages = content.optJSONArray("pages") + if (pages == null) { + val pubDate = content.getStringOrNull("pub_date")?.let { + SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.US).tryParse(it) + } + if (pubDate != null && pubDate > System.currentTimeMillis()) { + val at = SimpleDateFormat.getDateInstance(DateFormat.LONG).format(Date(pubDate)) + parseFailed("Глава станет доступной $at") + } else { + parseFailed("Глава недоступна") + } + } + val result = ArrayList(pages.length()) + for (i in 0 until pages.length()) { + when (val item = pages.get(i)) { + is JSONObject -> result += parsePage(item, referer) + is JSONArray -> item.mapTo(result) { parsePage(it, referer) } else -> throw ParseException("Unknown json item $item") } } - return pages + return result } override suspend fun getTags(): Set { From 9089555320cc0dbab43fc491cedc8fe77a4a54fd Mon Sep 17 00:00:00 2001 From: Koitharu Date: Sun, 20 Feb 2022 18:41:38 +0200 Subject: [PATCH 3/5] Fix internal storage sharing #98 --- app/src/main/res/xml/filepaths.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main/res/xml/filepaths.xml b/app/src/main/res/xml/filepaths.xml index c6116aaa4..7dac5f16b 100644 --- a/app/src/main/res/xml/filepaths.xml +++ b/app/src/main/res/xml/filepaths.xml @@ -3,6 +3,9 @@ + From 1713efb51fda9226b0f60c87ba2ce752342bc8a8 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Sun, 20 Feb 2022 18:43:12 +0200 Subject: [PATCH 4/5] Increase version --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 1f5456819..e59984b8a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -13,8 +13,8 @@ android { applicationId 'org.koitharu.kotatsu' minSdkVersion 21 targetSdkVersion 31 - versionCode 380 - versionName '2.1.4' + versionCode 381 + versionName '2.1.5' generatedDensities = [] testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" From 15d0addb7b56da320a0d6e9c0cf64e4155ccf14c Mon Sep 17 00:00:00 2001 From: Koitharu Date: Tue, 22 Feb 2022 19:34:00 +0200 Subject: [PATCH 5/5] Fix Remanga chapters parsing --- .../core/parser/site/RemangaRepository.kt | 26 ++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/org/koitharu/kotatsu/core/parser/site/RemangaRepository.kt b/app/src/main/java/org/koitharu/kotatsu/core/parser/site/RemangaRepository.kt index d6c047363..ebea9bc94 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/parser/site/RemangaRepository.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/parser/site/RemangaRepository.kt @@ -98,9 +98,7 @@ class RemangaRepository(loaderContext: MangaLoaderContext) : RemoteMangaReposito } val branchId = content.getJSONArray("branches").optJSONObject(0) ?.getLong("id") ?: throw ParseException("No branches found") - val chapters = loaderContext.httpGet( - url = "https://api.$domain/api/titles/chapters/?branch_id=$branchId" - ).parseJson().getJSONArray("content") + val chapters = grabChapters(domain, branchId) val dateFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.US) return manga.copy( description = content.getString("description"), @@ -123,7 +121,7 @@ class RemangaRepository(loaderContext: MangaLoaderContext) : RemoteMangaReposito MangaChapter( id = generateUid(id), url = "/api/titles/chapters/$id/", - number = chapters.length() - i, + number = chapters.size - i, name = buildString { append("Том ") append(jo.optString("tome", "0")) @@ -211,6 +209,26 @@ class RemangaRepository(loaderContext: MangaLoaderContext) : RemoteMangaReposito source = source, ) + private suspend fun grabChapters(domain: String, branchId: Long): List { + val result = ArrayList(100) + var page = 1 + while (true) { + val content = loaderContext.httpGet( + "https://api.$domain/api/titles/chapters/?branch_id=$branchId&page=$page&count=100" + ).parseJson().getJSONArray("content") + val len = content.length() + if (len == 0) { + break + } + result.ensureCapacity(result.size + len) + for (i in 0 until len) { + result.add(content.getJSONObject(i)) + } + page++ + } + return result + } + private companion object { const val PAGE_SIZE = 30