parent
fae290cf22
commit
4333999b85
@ -145,7 +145,7 @@ class DownloadCache(
|
||||
mangaDirs.values.forEach { mangaDir ->
|
||||
val chapterDirs = mangaDir.dir.listFiles()
|
||||
.orEmpty()
|
||||
.mapNotNull { it.name }
|
||||
.mapNotNull { it.name?.replace(".cbz", "") }
|
||||
.toHashSet()
|
||||
|
||||
mangaDir.files = chapterDirs
|
||||
|
@ -89,7 +89,7 @@ class DownloadProvider(private val context: Context) {
|
||||
fun findChapterDir(chapter: Chapter, manga: Manga, source: Source): UniFile? {
|
||||
val mangaDir = findMangaDir(manga, source)
|
||||
return getValidChapterDirNames(chapter).asSequence()
|
||||
.mapNotNull { mangaDir?.findFile(it) }
|
||||
.mapNotNull { mangaDir?.findFile(it) ?: mangaDir?.findFile("$it.cbz") }
|
||||
.firstOrNull()
|
||||
}
|
||||
|
||||
@ -104,7 +104,7 @@ class DownloadProvider(private val context: Context) {
|
||||
val mangaDir = findMangaDir(manga, source) ?: return emptyList()
|
||||
return chapters.mapNotNull { chapter ->
|
||||
getValidChapterDirNames(chapter).asSequence()
|
||||
.mapNotNull { mangaDir.findFile(it) }
|
||||
.mapNotNull { mangaDir.findFile(it) ?: mangaDir.findFile("$it.cbz") }
|
||||
.firstOrNull()
|
||||
}
|
||||
}
|
||||
@ -127,7 +127,7 @@ class DownloadProvider(private val context: Context) {
|
||||
(
|
||||
chapters.find { chp ->
|
||||
getValidChapterDirNames(chp).any { dir ->
|
||||
mangaDir.findFile(dir) != null
|
||||
mangaDir.findFile(dir) ?: mangaDir.findFile("$dir.cbz") != null
|
||||
}
|
||||
} == null
|
||||
) || it.name?.endsWith("_tmp") == true
|
||||
|
@ -11,6 +11,7 @@ import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.download.model.Download
|
||||
import eu.kanade.tachiyomi.data.download.model.DownloadQueue
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
import eu.kanade.tachiyomi.source.model.Page
|
||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
@ -22,7 +23,11 @@ import eu.kanade.tachiyomi.util.lang.plusAssign
|
||||
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
||||
import eu.kanade.tachiyomi.util.storage.saveTo
|
||||
import eu.kanade.tachiyomi.util.system.ImageUtil
|
||||
import java.io.BufferedOutputStream
|
||||
import java.io.File
|
||||
import java.util.zip.CRC32
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipOutputStream
|
||||
import kotlinx.coroutines.async
|
||||
import okhttp3.Response
|
||||
import rx.Observable
|
||||
@ -30,6 +35,8 @@ import rx.android.schedulers.AndroidSchedulers
|
||||
import rx.schedulers.Schedulers
|
||||
import rx.subscriptions.CompositeSubscription
|
||||
import timber.log.Timber
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
/**
|
||||
@ -53,6 +60,8 @@ class Downloader(
|
||||
private val sourceManager: SourceManager
|
||||
) {
|
||||
|
||||
private val preferences: PreferencesHelper = Injekt.get()
|
||||
|
||||
private val chapterCache: ChapterCache by injectLazy()
|
||||
|
||||
/**
|
||||
@ -464,7 +473,39 @@ class Downloader(
|
||||
|
||||
// Only rename the directory if it's downloaded.
|
||||
if (download.status == Download.DOWNLOADED) {
|
||||
tmpDir.renameTo(dirname)
|
||||
mangaDir.findFile(dirname + ".tmp")?.delete()
|
||||
if (preferences.saveChaptersAsCBZ().get()) {
|
||||
val zip = mangaDir.createFile(dirname + ".tmp")
|
||||
val zipOut = ZipOutputStream(BufferedOutputStream(zip.openOutputStream()))
|
||||
|
||||
zipOut.setLevel(preferences.saveChaptersAsCBZLevel().get())
|
||||
|
||||
if (preferences.saveChaptersAsCBZLevel().get() == 0) {
|
||||
zipOut.setMethod(ZipEntry.STORED)
|
||||
}
|
||||
|
||||
tmpDir.listFiles()?.forEach { img ->
|
||||
val input = img.openInputStream()
|
||||
val data = input.readBytes()
|
||||
val entry = ZipEntry(img.name)
|
||||
if (preferences.saveChaptersAsCBZLevel().get() == 0) {
|
||||
val crc = CRC32()
|
||||
val size = img.length()
|
||||
crc.update(data)
|
||||
entry.crc = crc.value
|
||||
entry.compressedSize = size
|
||||
entry.size = size
|
||||
}
|
||||
zipOut.putNextEntry(entry)
|
||||
zipOut.write(data)
|
||||
input.close()
|
||||
}
|
||||
zipOut.close()
|
||||
zip.renameTo(dirname + ".cbz")
|
||||
tmpDir.delete()
|
||||
} else {
|
||||
tmpDir.renameTo(dirname)
|
||||
}
|
||||
cache.addChapter(dirname, mangaDir, download.manga)
|
||||
|
||||
DiskUtil.createNoMediaFile(tmpDir, context)
|
||||
|
@ -302,4 +302,8 @@ object PreferenceKeys {
|
||||
const val dataSaverServer = "data_saver_server"
|
||||
|
||||
const val dataSaverColorBW = "data_saver_color_bw"
|
||||
|
||||
const val saveChaptersAsCBZ = "save_chapter_as_cbz"
|
||||
|
||||
const val saveChaptersAsCBZLevel = "save_chapter_as_cbz_level"
|
||||
}
|
||||
|
@ -407,4 +407,8 @@ class PreferencesHelper(val context: Context) {
|
||||
fun dataSaverServer() = flowPrefs.getString(Keys.dataSaverServer, "")
|
||||
|
||||
fun dataSaverColorBW() = flowPrefs.getBoolean(Keys.dataSaverColorBW, false)
|
||||
|
||||
fun saveChaptersAsCBZ() = flowPrefs.getBoolean(Keys.saveChaptersAsCBZ, false)
|
||||
|
||||
fun saveChaptersAsCBZLevel() = flowPrefs.getInt(Keys.saveChaptersAsCBZLevel, 0)
|
||||
}
|
||||
|
@ -4,10 +4,16 @@ import android.app.Application
|
||||
import android.net.Uri
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||
import eu.kanade.tachiyomi.data.download.DownloadProvider
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.model.Page
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
|
||||
import eu.kanade.tachiyomi.util.lang.compareToCaseInsensitiveNaturalOrder
|
||||
import eu.kanade.tachiyomi.util.system.ImageUtil
|
||||
import java.io.File
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipFile
|
||||
import rx.Observable
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
@ -26,20 +32,54 @@ class DownloadPageLoader(
|
||||
*/
|
||||
private val context by injectLazy<Application>()
|
||||
|
||||
private val downloadProvider by lazy { DownloadProvider(context) }
|
||||
|
||||
/**
|
||||
* Returns an observable containing the pages found on this downloaded chapter.
|
||||
*/
|
||||
override fun getPages(): Observable<List<ReaderPage>> {
|
||||
return downloadManager.buildPageList(source, manga, chapter.chapter)
|
||||
.map { pages ->
|
||||
pages.map { page ->
|
||||
ReaderPage(page.index, page.url, page.imageUrl) {
|
||||
context.contentResolver.openInputStream(page.uri ?: Uri.EMPTY)!!
|
||||
}.apply {
|
||||
val chapterPath = downloadProvider.findChapterDir(chapter.chapter, manga, source)
|
||||
|
||||
if (chapterPath?.isFile!!) {
|
||||
val zip = if (!File(chapterPath.filePath!!).canRead()) {
|
||||
val tmpFile = File.createTempFile(chapterPath.name!!.replace(".cbz", ""), ".cbz")
|
||||
val buffer = ByteArray(1024)
|
||||
chapterPath.openInputStream().use { input ->
|
||||
tmpFile.outputStream().use { fileOut ->
|
||||
while (true) {
|
||||
val length = input.read(buffer)
|
||||
if (length <= 0) break
|
||||
fileOut.write(buffer, 0, length)
|
||||
}
|
||||
fileOut.flush()
|
||||
}
|
||||
}
|
||||
ZipFile(tmpFile.absolutePath)
|
||||
} else ZipFile(chapterPath.filePath)
|
||||
|
||||
return zip.entries().toList()
|
||||
.filter { !it.isDirectory && ImageUtil.isImage(it.name) { zip.getInputStream(it) } }
|
||||
.sortedWith(Comparator<ZipEntry> { 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) }
|
||||
} else {
|
||||
return downloadManager.buildPageList(source, manga, chapter.chapter)
|
||||
.map { pages ->
|
||||
pages.map { page ->
|
||||
ReaderPage(page.index, page.url, page.imageUrl) {
|
||||
context.contentResolver.openInputStream(page.uri ?: Uri.EMPTY)!!
|
||||
}.apply {
|
||||
status = Page.READY
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getPage(page: ReaderPage): Observable<Int> {
|
||||
|
@ -64,6 +64,24 @@ class SettingsDownloadController : SettingsController() {
|
||||
titleRes = R.string.pref_download_only_over_wifi
|
||||
defaultValue = true
|
||||
}
|
||||
|
||||
switchPreference {
|
||||
key = Keys.saveChaptersAsCBZ
|
||||
titleRes = R.string.save_chapter_as_cbz
|
||||
defaultValue = false
|
||||
}
|
||||
|
||||
intListPreference {
|
||||
titleRes = R.string.save_chapter_as_cbz_level
|
||||
key = Keys.saveChaptersAsCBZLevel
|
||||
entries = arrayOf("0", "1", "2", "3", "4", "5", "6", "7", "8", "9")
|
||||
entryValues = entries
|
||||
defaultValue = "0"
|
||||
|
||||
preferences.saveChaptersAsCBZ().asImmediateFlow { isVisible = it }
|
||||
.launchIn(scope)
|
||||
}
|
||||
|
||||
preferenceCategory {
|
||||
titleRes = R.string.pref_category_delete_chapters
|
||||
|
||||
|
@ -478,5 +478,8 @@
|
||||
<item quantity="other">%2$s, %1$d pages</item>
|
||||
</plurals>
|
||||
|
||||
<string name="save_chapter_as_cbz">Save Chapters as CBZ</string>
|
||||
<string name="save_chapter_as_cbz_level">CBZ Compression level</string>
|
||||
|
||||
|
||||
</resources>
|
Loading…
x
Reference in New Issue
Block a user