From dec2ed795944d8101965a02a4dff535b9577d720 Mon Sep 17 00:00:00 2001
From: Rishvaish <68911202+rishabpuranika@users.noreply.github.com>
Date: Wed, 23 Apr 2025 14:58:42 +0530
Subject: [PATCH 01/10] hope for the best
* Update README.md
* To install multiple mangas
users can enter the value required to install as there is an EditText field instead of the Text View
* Issues
1)Installation of many mangas at same time now made to one to increase the installation efficiency
2)Installation order from the latest progresses chapter to the limit index
3)Tried to resolve the app crash bug
* Issues
1)Installation of many mangas at same time now made to one to increase the installation efficiency
2)Installation order from the latest progresses chapter to the limit index
3)Tried to resolve the app crash bug
---------
Co-authored-by: rebel onion <87634197+rebelonion@users.noreply.github.com>
---
.../ani/dantotsu/media/manga/MangaCache.kt | 13 ++++-
.../dantotsu/media/manga/MangaReadFragment.kt | 47 ++++++++++++-------
2 files changed, 40 insertions(+), 20 deletions(-)
diff --git a/app/src/main/java/ani/dantotsu/media/manga/MangaCache.kt b/app/src/main/java/ani/dantotsu/media/manga/MangaCache.kt
index 359c64a5..f47f416f 100644
--- a/app/src/main/java/ani/dantotsu/media/manga/MangaCache.kt
+++ b/app/src/main/java/ani/dantotsu/media/manga/MangaCache.kt
@@ -16,6 +16,7 @@ import eu.kanade.tachiyomi.source.online.HttpSource
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.io.File
+import java.io.FileNotFoundException
import java.io.FileOutputStream
data class ImageData(
@@ -76,7 +77,7 @@ fun saveImage(
uri?.let {
contentResolver.openOutputStream(it)?.use { os ->
bitmap.compress(format, quality, os)
- }
+ } ?: throw FileNotFoundException("Failed to open output stream for URI: $uri")
}
} else {
val directory =
@@ -86,12 +87,20 @@ fun saveImage(
}
val file = File(directory, filename)
+
+ // Check if the file already exists
+ if (file.exists()) {
+ println("File already exists: ${file.absolutePath}")
+ return
+ }
+
FileOutputStream(file).use { outputStream ->
bitmap.compress(format, quality, outputStream)
}
}
+ } catch (e: FileNotFoundException) {
+ println("File not found: ${e.message}")
} catch (e: Exception) {
- // Handle exception here
println("Exception while saving image: ${e.message}")
}
}
diff --git a/app/src/main/java/ani/dantotsu/media/manga/MangaReadFragment.kt b/app/src/main/java/ani/dantotsu/media/manga/MangaReadFragment.kt
index 63ef7408..2ad28a75 100644
--- a/app/src/main/java/ani/dantotsu/media/manga/MangaReadFragment.kt
+++ b/app/src/main/java/ani/dantotsu/media/manga/MangaReadFragment.kt
@@ -66,6 +66,7 @@ import eu.kanade.tachiyomi.extension.manga.model.MangaExtension
import eu.kanade.tachiyomi.source.ConfigurableSource
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import uy.kohesive.injekt.Injekt
@@ -232,25 +233,35 @@ open class MangaReadFragment : Fragment(), ScanlatorSelectionListener {
}
fun multiDownload(n: Int) {
- // Get last viewed chapter
- val selected = media.userProgress
- val chapters = media.manga?.chapters?.values?.toList()
- // Filter by selected language
- val progressChapterIndex = (chapters?.indexOfFirst {
- MediaNameAdapter.findChapterNumber(it.number)?.toInt() == selected
- } ?: 0) + 1
-
- if (progressChapterIndex < 0 || n < 1 || chapters == null) return
-
- // Calculate the end index
- val endIndex = minOf(progressChapterIndex + n, chapters.size)
-
- // Make sure there are enough chapters
- val chaptersToDownload = chapters.subList(progressChapterIndex, endIndex)
-
-
- for (chapter in chaptersToDownload) {
+ lifecycleScope.launch {
+ // Get the last viewed chapter
+ val selected = media.userProgress ?: 0
+ val chapters = media.manga?.chapters?.values?.toList()
+ // Ensure chapters are available in the extensions
+ if (chapters.isNullOrEmpty() || n < 1) return@launch
+ // Find the index of the last viewed chapter
+ val progressChapterIndex = (chapters.indexOfFirst {
+ MediaNameAdapter.findChapterNumber(it.number)?.toInt() == selected
+ } + 1).coerceAtLeast(0)
+ // Calculate the end value for the range of chapters to download
+ val endIndex = (progressChapterIndex + n).coerceAtMost(chapters.size)
+ // Get the list of chapters to download
+ val chaptersToDownload = chapters.subList(progressChapterIndex, endIndex)
+ // Trigger the download for each chapter sequentially
+ for (chapter in chaptersToDownload) {
+ try {
+ downloadChapterSequentially(chapter)
+ } catch (e: Exception) {
+ Toast.makeText(requireContext(), "Failed to download chapter: ${chapter.title}", Toast.LENGTH_SHORT).show()
+ }
+ }
+ Toast.makeText(requireContext(), "All downloads completed!", Toast.LENGTH_SHORT).show()
+ }
+ }
+ private suspend fun downloadChapterSequentially(chapter: MangaChapter) {
+ withContext(Dispatchers.IO) {
onMangaChapterDownloadClick(chapter)
+ delay(2000) // A 2-second download
}
}
From 7d0894cd923866a0091162fcb8f0ec1680632ef1 Mon Sep 17 00:00:00 2001
From: rebel onion <87634197+rebelonion@users.noreply.github.com>
Date: Wed, 14 May 2025 22:35:50 -0500
Subject: [PATCH 02/10] chore: bump extension interface
---
README.md | 2 -
app/build.gradle | 2 +-
.../ani/dantotsu/parsers/AniyomiAdapter.kt | 16 +-
.../tachiyomi/animesource/AnimeSource.kt | 20 ++
.../tachiyomi/animesource/model/Hoster.kt | 81 ++++++
.../tachiyomi/animesource/model/Video.kt | 273 +++++++++++++-----
6 files changed, 311 insertions(+), 83 deletions(-)
create mode 100644 app/src/main/java/eu/kanade/tachiyomi/animesource/model/Hoster.kt
diff --git a/README.md b/README.md
index 6b713a2a..a1b1d673 100644
--- a/README.md
+++ b/README.md
@@ -14,8 +14,6 @@ Dantotsu is an [Anilist](https://anilist.co/) only client.
> **Dantotsu (断トツ; Dan-totsu)** literally means "the best of the best" in Japanese. Try it out for yourself and be the judge!
-
-
## Terms of Use
By downloading, installing, or using this application, you agree to:
- Use the application in compliance with all applicable laws
diff --git a/app/build.gradle b/app/build.gradle
index bcda959a..b983443c 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -19,7 +19,7 @@ android {
targetSdk 35
versionCode((System.currentTimeMillis() / 60000).toInteger())
versionName "3.2.1"
- versionCode 300200100
+ versionCode versionName.split("\\.").collect { it.toInteger() * 100 }.join("") as Integer
signingConfig signingConfigs.debug
}
diff --git a/app/src/main/java/ani/dantotsu/parsers/AniyomiAdapter.kt b/app/src/main/java/ani/dantotsu/parsers/AniyomiAdapter.kt
index adfd857e..fa1fa9a2 100644
--- a/app/src/main/java/ani/dantotsu/parsers/AniyomiAdapter.kt
+++ b/app/src/main/java/ani/dantotsu/parsers/AniyomiAdapter.kt
@@ -226,8 +226,18 @@ class DynamicAnimeParser(extension: AnimeExtension.Installed) : AnimeParser() {
?: return emptyList())
return try {
- val videos = source.getVideoList(sEpisode)
- videos.map { videoToVideoServer(it) }
+ // TODO(1.6): Remove else block when dropping support for ext lib <1.6
+ if ((source as AnimeHttpSource).javaClass.declaredMethods.any { it.name == "getHosterList" }){
+ val hosters = source.getHosterList(sEpisode)
+ val allVideos = hosters.flatMap { hoster ->
+ val videos = source.getVideoList(hoster)
+ videos.map { it.copy(videoTitle = "${hoster.hosterName} - ${it.videoTitle}") }
+ }
+ allVideos.map { videoToVideoServer(it) }
+ } else {
+ val videos = source.getVideoList(sEpisode)
+ videos.map { videoToVideoServer(it) }
+ }
} catch (e: Exception) {
Logger.log("Exception occurred: ${e.message}")
emptyList()
@@ -576,7 +586,7 @@ class VideoServerPassthrough(private val videoServer: VideoServer) : VideoExtrac
number,
format!!,
FileUrl(videoUrl, headersMap),
- if (aniVideo.totalContentLength == 0L) null else aniVideo.bytesDownloaded.toDouble()
+ null
)
}
diff --git a/app/src/main/java/eu/kanade/tachiyomi/animesource/AnimeSource.kt b/app/src/main/java/eu/kanade/tachiyomi/animesource/AnimeSource.kt
index 171b07b2..4b54360a 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/animesource/AnimeSource.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/animesource/AnimeSource.kt
@@ -1,5 +1,6 @@
package eu.kanade.tachiyomi.animesource
+import eu.kanade.tachiyomi.animesource.model.Hoster
import eu.kanade.tachiyomi.animesource.model.SAnime
import eu.kanade.tachiyomi.animesource.model.SEpisode
import eu.kanade.tachiyomi.animesource.model.Video
@@ -48,6 +49,25 @@ interface AnimeSource {
return fetchEpisodeList(anime).awaitSingle()
}
+ /**
+ * Get the list of hoster for an episode. The first hoster in the list should
+ * be the preferred hoster.
+ *
+ * @since extensions-lib 16
+ * @param episode the episode.
+ * @return the hosters for the episode.
+ */
+ suspend fun getHosterList(episode: SEpisode): List = throw IllegalStateException("Not used")
+
+ /**
+ * Get the list of videos for a hoster.
+ *
+ * @since extensions-lib 16
+ * @param hoster the hoster.
+ * @return the videos for the hoster.
+ */
+ suspend fun getVideoList(hoster: Hoster): List