fix: some download optimizations
This commit is contained in:
parent
b30047804a
commit
5800dcf3e7
6 changed files with 107 additions and 63 deletions
|
@ -125,7 +125,7 @@ class DownloadCompat {
|
|||
Logger.log(e)
|
||||
Injekt.get<CrashlyticsInterface>().logException(e)
|
||||
return OfflineAnimeModel(
|
||||
"unknown",
|
||||
downloadedType.titleName,
|
||||
"0",
|
||||
"??",
|
||||
"??",
|
||||
|
@ -188,7 +188,7 @@ class DownloadCompat {
|
|||
Logger.log(e)
|
||||
Injekt.get<CrashlyticsInterface>().logException(e)
|
||||
return OfflineMangaModel(
|
||||
"unknown",
|
||||
downloadedType.titleName,
|
||||
"0",
|
||||
"??",
|
||||
"??",
|
||||
|
|
|
@ -181,7 +181,6 @@ class AnimeDownloaderService : Service() {
|
|||
}
|
||||
|
||||
private fun updateNotification() {
|
||||
// Update the notification to reflect the current state of the queue
|
||||
val pendingDownloads = AnimeServiceDataSingleton.downloadQueue.size
|
||||
val text = if (pendingDownloads > 0) {
|
||||
"Pending downloads: $pendingDownloads"
|
||||
|
@ -201,7 +200,7 @@ class AnimeDownloaderService : Service() {
|
|||
|
||||
@androidx.annotation.OptIn(UnstableApi::class)
|
||||
suspend fun download(task: AnimeDownloadTask) {
|
||||
withContext(Dispatchers.Main) {
|
||||
withContext(Dispatchers.IO) {
|
||||
try {
|
||||
val notifi = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
ContextCompat.checkSelfPermission(
|
||||
|
@ -214,13 +213,21 @@ class AnimeDownloaderService : Service() {
|
|||
|
||||
builder.setContentText("Downloading ${getTaskName(task.title, task.episode)}")
|
||||
if (notifi) {
|
||||
withContext(Dispatchers.Main) {
|
||||
notificationManager.notify(NOTIFICATION_ID, builder.build())
|
||||
}
|
||||
}
|
||||
|
||||
val outputDir = getSubDirectory(
|
||||
val baseOutputDir = getSubDirectory(
|
||||
this@AnimeDownloaderService,
|
||||
MediaType.ANIME,
|
||||
false,
|
||||
task.title
|
||||
) ?: throw Exception("Failed to create output directory")
|
||||
val outputDir = getSubDirectory(
|
||||
this@AnimeDownloaderService,
|
||||
MediaType.ANIME,
|
||||
true,
|
||||
task.title,
|
||||
task.episode
|
||||
) ?: throw Exception("Failed to create output directory")
|
||||
|
@ -277,7 +284,7 @@ class AnimeDownloaderService : Service() {
|
|||
currentTasks.find { it.getTaskName() == task.getTaskName() }?.sessionId =
|
||||
ffTask
|
||||
|
||||
saveMediaInfo(task)
|
||||
saveMediaInfo(task, baseOutputDir)
|
||||
|
||||
// periodically check if the download is complete
|
||||
while (ffExtension.getState(ffTask) != "COMPLETED") {
|
||||
|
@ -291,7 +298,11 @@ class AnimeDownloaderService : Service() {
|
|||
)
|
||||
} Download failed"
|
||||
)
|
||||
if (notifi) {
|
||||
withContext(Dispatchers.Main) {
|
||||
notificationManager.notify(NOTIFICATION_ID, builder.build())
|
||||
}
|
||||
}
|
||||
toast("${getTaskName(task.title, task.episode)} Download failed")
|
||||
Logger.log("Download failed: ${ffExtension.getStackTrace(ffTask)}")
|
||||
downloadsManager.removeDownload(
|
||||
|
@ -324,8 +335,10 @@ class AnimeDownloaderService : Service() {
|
|||
percent.coerceAtMost(99)
|
||||
)
|
||||
if (notifi) {
|
||||
withContext(Dispatchers.Main) {
|
||||
notificationManager.notify(NOTIFICATION_ID, builder.build())
|
||||
}
|
||||
}
|
||||
kotlinx.coroutines.delay(2000)
|
||||
}
|
||||
if (ffExtension.getState(ffTask) == "COMPLETED") {
|
||||
|
@ -339,7 +352,11 @@ class AnimeDownloaderService : Service() {
|
|||
)
|
||||
} Download failed"
|
||||
)
|
||||
if (notifi) {
|
||||
withContext(Dispatchers.Main) {
|
||||
notificationManager.notify(NOTIFICATION_ID, builder.build())
|
||||
}
|
||||
}
|
||||
snackString("${getTaskName(task.title, task.episode)} Download failed")
|
||||
downloadsManager.removeDownload(
|
||||
DownloadedType(
|
||||
|
@ -371,7 +388,11 @@ class AnimeDownloaderService : Service() {
|
|||
)
|
||||
} Download completed"
|
||||
)
|
||||
if (notifi) {
|
||||
withContext(Dispatchers.Main) {
|
||||
notificationManager.notify(NOTIFICATION_ID, builder.build())
|
||||
}
|
||||
}
|
||||
snackString("${getTaskName(task.title, task.episode)} Download completed")
|
||||
PrefManager.getAnimeDownloadPreferences().edit().putString(
|
||||
task.getTaskName(),
|
||||
|
@ -401,11 +422,8 @@ class AnimeDownloaderService : Service() {
|
|||
}
|
||||
}
|
||||
|
||||
private fun saveMediaInfo(task: AnimeDownloadTask) {
|
||||
private fun saveMediaInfo(task: AnimeDownloadTask, directory: DocumentFile) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val directory =
|
||||
getSubDirectory(this@AnimeDownloaderService, MediaType.ANIME, false, task.title)
|
||||
?: throw Exception("Directory not found")
|
||||
directory.findFile("media.json")?.forceDelete(this@AnimeDownloaderService)
|
||||
val file = directory.createFile("application/json", "media.json")
|
||||
?: throw Exception("File not created")
|
||||
|
|
|
@ -30,6 +30,7 @@ import ani.dantotsu.bottomBar
|
|||
import ani.dantotsu.connections.crashlytics.CrashlyticsInterface
|
||||
import ani.dantotsu.currActivity
|
||||
import ani.dantotsu.currContext
|
||||
import ani.dantotsu.download.DownloadCompat
|
||||
import ani.dantotsu.download.DownloadCompat.Companion.loadMediaCompat
|
||||
import ani.dantotsu.download.DownloadCompat.Companion.loadOfflineAnimeModelCompat
|
||||
import ani.dantotsu.download.DownloadedType
|
||||
|
@ -319,17 +320,20 @@ class OfflineAnimeFragment : Fragment(), OfflineAnimeSearchListener {
|
|||
)
|
||||
val gson = GsonBuilder()
|
||||
.registerTypeAdapter(SChapter::class.java, InstanceCreator<SChapter> {
|
||||
SChapterImpl() // Provide an instance of SChapterImpl
|
||||
SChapterImpl()
|
||||
})
|
||||
.registerTypeAdapter(SAnime::class.java, InstanceCreator<SAnime> {
|
||||
SAnimeImpl() // Provide an instance of SAnimeImpl
|
||||
SAnimeImpl()
|
||||
})
|
||||
.registerTypeAdapter(SEpisode::class.java, InstanceCreator<SEpisode> {
|
||||
SEpisodeImpl() // Provide an instance of SEpisodeImpl
|
||||
SEpisodeImpl()
|
||||
})
|
||||
.create()
|
||||
val media = directory?.findFile("media.json")
|
||||
?: return loadMediaCompat(downloadedType)
|
||||
if (media == null) {
|
||||
Logger.log("No media.json found at ${directory?.uri?.path}")
|
||||
return loadMediaCompat(downloadedType)
|
||||
}
|
||||
val mediaJson =
|
||||
media.openInputStream(context ?: currContext()!!)?.bufferedReader().use {
|
||||
it?.readText()
|
||||
|
@ -394,6 +398,7 @@ class OfflineAnimeFragment : Fragment(), OfflineAnimeSearchListener {
|
|||
bannerUri
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
Logger.log(e)
|
||||
return try {
|
||||
loadOfflineAnimeModelCompat(downloadedType)
|
||||
} catch (e: Exception) {
|
||||
|
@ -401,7 +406,7 @@ class OfflineAnimeFragment : Fragment(), OfflineAnimeSearchListener {
|
|||
Logger.log(e)
|
||||
Injekt.get<CrashlyticsInterface>().logException(e)
|
||||
OfflineAnimeModel(
|
||||
"unknown",
|
||||
downloadedType.titleName,
|
||||
"0",
|
||||
"??",
|
||||
"??",
|
||||
|
|
|
@ -134,15 +134,15 @@ class MangaDownloaderService : Service() {
|
|||
mutex.withLock {
|
||||
downloadJobs[task.chapter] = job
|
||||
}
|
||||
job.join() // Wait for the job to complete before continuing to the next task
|
||||
job.join()
|
||||
mutex.withLock {
|
||||
downloadJobs.remove(task.chapter)
|
||||
}
|
||||
updateNotification() // Update the notification after each task is completed
|
||||
updateNotification()
|
||||
}
|
||||
if (MangaServiceDataSingleton.downloadQueue.isEmpty()) {
|
||||
withContext(Dispatchers.Main) {
|
||||
stopSelf() // Stop the service when the queue is empty
|
||||
stopSelf()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -181,7 +181,7 @@ class MangaDownloaderService : Service() {
|
|||
|
||||
suspend fun download(task: DownloadTask) {
|
||||
try {
|
||||
withContext(Dispatchers.Main) {
|
||||
withContext(Dispatchers.IO) {
|
||||
val notifi = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
ContextCompat.checkSelfPermission(
|
||||
this@MangaDownloaderService,
|
||||
|
@ -194,18 +194,27 @@ class MangaDownloaderService : Service() {
|
|||
val deferredMap = mutableMapOf<Int, Deferred<Bitmap?>>()
|
||||
builder.setContentText("Downloading ${task.title} - ${task.chapter}")
|
||||
if (notifi) {
|
||||
withContext(Dispatchers.Main) {
|
||||
notificationManager.notify(NOTIFICATION_ID, builder.build())
|
||||
}
|
||||
}
|
||||
|
||||
getSubDirectory(
|
||||
val baseOutputDir = getSubDirectory(
|
||||
this@MangaDownloaderService,
|
||||
MediaType.MANGA,
|
||||
false,
|
||||
task.title
|
||||
) ?: throw Exception("Base output directory not found")
|
||||
val outputDir = getSubDirectory(
|
||||
this@MangaDownloaderService,
|
||||
MediaType.MANGA,
|
||||
false,
|
||||
task.title,
|
||||
task.chapter
|
||||
)?.deleteRecursively(this@MangaDownloaderService)
|
||||
) ?: throw Exception("Output directory not found")
|
||||
|
||||
outputDir.deleteRecursively(this@MangaDownloaderService, true)
|
||||
|
||||
// Loop through each ImageData object from the task
|
||||
var farthest = 0
|
||||
for ((index, image) in task.imageData.withIndex()) {
|
||||
if (deferredMap.size >= task.simultaneousDownloads) {
|
||||
|
@ -226,30 +235,36 @@ class MangaDownloaderService : Service() {
|
|||
}
|
||||
|
||||
if (bitmap != null) {
|
||||
saveToDisk("$index.jpg", bitmap, task.title, task.chapter)
|
||||
saveToDisk("$index.jpg", outputDir, bitmap)
|
||||
}
|
||||
farthest++
|
||||
|
||||
builder.setProgress(task.imageData.size, farthest, false)
|
||||
|
||||
broadcastDownloadProgress(
|
||||
task.chapter,
|
||||
farthest * 100 / task.imageData.size
|
||||
)
|
||||
if (notifi) {
|
||||
withContext(Dispatchers.Main) {
|
||||
notificationManager.notify(NOTIFICATION_ID, builder.build())
|
||||
}
|
||||
|
||||
}
|
||||
bitmap
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for any remaining deferred to complete
|
||||
deferredMap.values.awaitAll()
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
builder.setContentText("${task.title} - ${task.chapter} Download complete")
|
||||
.setProgress(0, 0, false)
|
||||
if (notifi) {
|
||||
notificationManager.notify(NOTIFICATION_ID, builder.build())
|
||||
}
|
||||
}
|
||||
|
||||
saveMediaInfo(task)
|
||||
saveMediaInfo(task, baseOutputDir)
|
||||
downloadsManager.addDownload(
|
||||
DownloadedType(
|
||||
task.title,
|
||||
|
@ -269,17 +284,16 @@ class MangaDownloaderService : Service() {
|
|||
}
|
||||
|
||||
|
||||
private fun saveToDisk(fileName: String, bitmap: Bitmap, title: String, chapter: String) {
|
||||
private fun saveToDisk(
|
||||
fileName: String,
|
||||
directory: DocumentFile,
|
||||
bitmap: Bitmap
|
||||
) {
|
||||
try {
|
||||
// Define the directory within the private external storage space
|
||||
val directory = getSubDirectory(this, MediaType.MANGA, false, title, chapter)
|
||||
?: throw Exception("Directory not found")
|
||||
directory.findFile(fileName)?.forceDelete(this)
|
||||
// Create a file reference within that directory for the image
|
||||
val file =
|
||||
directory.createFile("image/jpeg", fileName) ?: throw Exception("File not created")
|
||||
|
||||
// Use a FileOutputStream to write the bitmap to the file
|
||||
file.openOutputStream(this, false).use { outputStream ->
|
||||
if (outputStream == null) throw Exception("Output stream is null")
|
||||
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream)
|
||||
|
@ -292,11 +306,8 @@ class MangaDownloaderService : Service() {
|
|||
}
|
||||
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
private fun saveMediaInfo(task: DownloadTask) {
|
||||
private fun saveMediaInfo(task: DownloadTask, directory: DocumentFile) {
|
||||
launchIO {
|
||||
val directory =
|
||||
getSubDirectory(this@MangaDownloaderService, MediaType.MANGA, false, task.title)
|
||||
?: throw Exception("Directory not found")
|
||||
directory.findFile("media.json")?.forceDelete(this@MangaDownloaderService)
|
||||
val file = directory.createFile("application/json", "media.json")
|
||||
?: throw Exception("File not created")
|
||||
|
|
|
@ -171,7 +171,11 @@ class OfflineMangaFragment : Fragment(), OfflineMangaSearchListener {
|
|||
val item = adapter.getItem(position) as OfflineMangaModel
|
||||
val media =
|
||||
downloadManager.mangaDownloadedTypes.firstOrNull { it.titleName.compareName(item.title) }
|
||||
?: downloadManager.novelDownloadedTypes.firstOrNull { it.titleName.compareName(item.title) }
|
||||
?: downloadManager.novelDownloadedTypes.firstOrNull {
|
||||
it.titleName.compareName(
|
||||
item.title
|
||||
)
|
||||
}
|
||||
media?.let {
|
||||
lifecycleScope.launch {
|
||||
ContextCompat.startActivity(
|
||||
|
@ -279,10 +283,12 @@ class OfflineMangaFragment : Fragment(), OfflineMangaSearchListener {
|
|||
downloads = listOf()
|
||||
downloadsJob = Job()
|
||||
CoroutineScope(Dispatchers.IO + downloadsJob).launch {
|
||||
val mangaTitles = downloadManager.mangaDownloadedTypes.map { it.titleName.findValidName() }.distinct()
|
||||
val mangaTitles =
|
||||
downloadManager.mangaDownloadedTypes.map { it.titleName.findValidName() }.distinct()
|
||||
val newMangaDownloads = mutableListOf<OfflineMangaModel>()
|
||||
for (title in mangaTitles) {
|
||||
val tDownloads = downloadManager.mangaDownloadedTypes.filter { it.titleName.findValidName() == title }
|
||||
val tDownloads =
|
||||
downloadManager.mangaDownloadedTypes.filter { it.titleName.findValidName() == title }
|
||||
val download = tDownloads.firstOrNull() ?: continue
|
||||
val offlineMangaModel = loadOfflineMangaModel(download)
|
||||
newMangaDownloads += offlineMangaModel
|
||||
|
@ -291,7 +297,8 @@ class OfflineMangaFragment : Fragment(), OfflineMangaSearchListener {
|
|||
val novelTitles = downloadManager.novelDownloadedTypes.map { it.titleName }.distinct()
|
||||
val newNovelDownloads = mutableListOf<OfflineMangaModel>()
|
||||
for (title in novelTitles) {
|
||||
val tDownloads = downloadManager.novelDownloadedTypes.filter { it.titleName.findValidName() == title }
|
||||
val tDownloads =
|
||||
downloadManager.novelDownloadedTypes.filter { it.titleName.findValidName() == title }
|
||||
val download = tDownloads.firstOrNull() ?: continue
|
||||
val offlineMangaModel = loadOfflineMangaModel(download)
|
||||
newNovelDownloads += offlineMangaModel
|
||||
|
@ -320,11 +327,14 @@ class OfflineMangaFragment : Fragment(), OfflineMangaSearchListener {
|
|||
)
|
||||
val gson = GsonBuilder()
|
||||
.registerTypeAdapter(SChapter::class.java, InstanceCreator<SChapter> {
|
||||
SChapterImpl() // Provide an instance of SChapterImpl
|
||||
SChapterImpl()
|
||||
})
|
||||
.create()
|
||||
val media = directory?.findFile("media.json")
|
||||
?: return DownloadCompat.loadMediaCompat(downloadedType)
|
||||
if (media == null) {
|
||||
Logger.log("No media.json found at ${directory?.uri?.path}")
|
||||
return DownloadCompat.loadMediaCompat(downloadedType)
|
||||
}
|
||||
val mediaJson =
|
||||
media.openInputStream(context ?: currContext()!!)?.bufferedReader().use {
|
||||
it?.readText()
|
||||
|
@ -340,7 +350,6 @@ class OfflineMangaFragment : Fragment(), OfflineMangaSearchListener {
|
|||
|
||||
private suspend fun loadOfflineMangaModel(downloadedType: DownloadedType): OfflineMangaModel {
|
||||
val type = downloadedType.type.asText()
|
||||
//load media.json and convert to media class with gson
|
||||
try {
|
||||
val directory = getSubDirectory(
|
||||
context ?: currContext()!!, downloadedType.type,
|
||||
|
@ -378,6 +387,7 @@ class OfflineMangaFragment : Fragment(), OfflineMangaSearchListener {
|
|||
bannerUri
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
Logger.log(e)
|
||||
return try {
|
||||
loadOfflineMangaModelCompat(downloadedType)
|
||||
} catch (e: Exception) {
|
||||
|
@ -385,7 +395,7 @@ class OfflineMangaFragment : Fragment(), OfflineMangaSearchListener {
|
|||
Logger.log(e)
|
||||
Injekt.get<CrashlyticsInterface>().logException(e)
|
||||
return OfflineMangaModel(
|
||||
"unknown",
|
||||
downloadedType.titleName,
|
||||
"0",
|
||||
"??",
|
||||
"??",
|
||||
|
|
|
@ -239,6 +239,13 @@ class NovelDownloaderService : Service() {
|
|||
return@withContext
|
||||
}
|
||||
|
||||
val baseDirectory = getSubDirectory(
|
||||
this@NovelDownloaderService,
|
||||
MediaType.NOVEL,
|
||||
false,
|
||||
task.title
|
||||
) ?: throw Exception("Directory not found")
|
||||
|
||||
// Start the download
|
||||
withContext(Dispatchers.IO) {
|
||||
try {
|
||||
|
@ -334,7 +341,7 @@ class NovelDownloaderService : Service() {
|
|||
notificationManager.notify(NOTIFICATION_ID, builder.build())
|
||||
}
|
||||
|
||||
saveMediaInfo(task)
|
||||
saveMediaInfo(task, baseDirectory)
|
||||
downloadsManager.addDownload(
|
||||
DownloadedType(
|
||||
task.title,
|
||||
|
@ -354,15 +361,8 @@ class NovelDownloaderService : Service() {
|
|||
}
|
||||
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
private fun saveMediaInfo(task: DownloadTask) {
|
||||
private fun saveMediaInfo(task: DownloadTask, directory: DocumentFile) {
|
||||
launchIO {
|
||||
val directory =
|
||||
getSubDirectory(
|
||||
this@NovelDownloaderService,
|
||||
MediaType.NOVEL,
|
||||
false,
|
||||
task.title
|
||||
) ?: throw Exception("Directory not found")
|
||||
directory.findFile("media.json")?.forceDelete(this@NovelDownloaderService)
|
||||
val file = directory.createFile("application/json", "media.json")
|
||||
?: throw Exception("File not created")
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue