diff --git a/app/src/main/java/eu/kanade/tachiyomi/AppInfo.kt b/app/src/main/java/eu/kanade/tachiyomi/AppInfo.kt index 5cb55af209..7ec80cdb67 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/AppInfo.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/AppInfo.kt @@ -8,4 +8,4 @@ package eu.kanade.tachiyomi object AppInfo { fun getVersionCode() = BuildConfig.VERSION_CODE fun getVersionName() = BuildConfig.VERSION_NAME -} \ No newline at end of file +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadCache.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadCache.kt index 891e5d2863..f340f63a2f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadCache.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadCache.kt @@ -143,7 +143,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 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadManager.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadManager.kt index f328505edc..d6c0ae41d6 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadManager.kt @@ -39,7 +39,7 @@ class DownloadManager( /** * Downloads provider, used to retrieve the folders where the chapters are or should be stored. */ - private val provider = DownloadProvider(context) + val provider = DownloadProvider(context) /** * Cache of downloaded chapters. diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadProvider.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadProvider.kt index 88174ab492..b13e84c95f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadProvider.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadProvider.kt @@ -148,10 +148,14 @@ class DownloadProvider(private val context: Context) { * @param chapter the chapter to query. */ fun getValidChapterDirNames(chapter: Chapter): List { + val chapterName = getChapterDirName(chapter) return listOf( - getChapterDirName(chapter), + // Folder of images + chapterName, + + // Archived chapters + "$chapterName.cbz", - // TODO: remove this // Legacy chapter directory name used in v0.9.2 and before DiskUtil.buildValidFilename(chapter.name) ) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt index 2954f19f7a..30381f0c37 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt @@ -12,6 +12,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.UnmeteredSource import eu.kanade.tachiyomi.source.model.Page @@ -35,7 +36,11 @@ import rx.android.schedulers.AndroidSchedulers import rx.schedulers.Schedulers import rx.subscriptions.CompositeSubscription import uy.kohesive.injekt.injectLazy +import java.io.BufferedOutputStream import java.io.File +import java.util.zip.CRC32 +import java.util.zip.ZipEntry +import java.util.zip.ZipOutputStream /** * This class is the one in charge of downloading chapters. @@ -60,6 +65,8 @@ class Downloader( private val chapterCache: ChapterCache by injectLazy() + private val preferences: PreferencesHelper by injectLazy() + /** * Store for persisting downloads across restarts. */ @@ -484,13 +491,51 @@ class Downloader( // Only rename the directory if it's downloaded. if (download.status == Download.State.DOWNLOADED) { - tmpDir.renameTo(dirname) + if (preferences.saveChaptersAsCBZ().get()) { + archiveChapter(mangaDir, dirname, tmpDir) + } else { + tmpDir.renameTo(dirname) + } cache.addChapter(dirname, mangaDir, download.manga) DiskUtil.createNoMediaFile(tmpDir, context) } } + /** + * Archive the chapter pages as a CBZ. + */ + private fun archiveChapter( + mangaDir: UniFile, + dirname: String, + tmpDir: UniFile, + ) { + val zip = mangaDir.createFile("$dirname.cbz.tmp") + ZipOutputStream(BufferedOutputStream(zip.openOutputStream())).use { zipOut -> + zipOut.setMethod(ZipEntry.STORED) + + tmpDir.listFiles()?.forEach { img -> + img.openInputStream().use { input -> + val data = input.readBytes() + val size = img.length() + val entry = ZipEntry(img.name).apply { + val crc = CRC32().apply { + update(data) + } + setCrc(crc.value) + + compressedSize = size + setSize(size) + } + zipOut.putNextEntry(entry) + zipOut.write(data) + } + } + } + zip.renameTo("$dirname.cbz") + tmpDir.delete() + } + /** * Completes a download. This method is called in the main thread. */ diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt index efe20996d0..49a8410f37 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt @@ -202,6 +202,8 @@ class PreferencesHelper(val context: Context) { fun downloadOnlyOverWifi() = prefs.getBoolean(Keys.downloadOnlyOverWifi, true) + fun saveChaptersAsCBZ() = flowPrefs.getBoolean("save_chapter_as_cbz", false) + fun folderPerManga() = prefs.getBoolean(Keys.folderPerManga, false) fun numberOfBackups() = flowPrefs.getInt("backup_slots", 1) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/DownloadPageLoader.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/DownloadPageLoader.kt index 90aeeed0d9..faad167d5d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/DownloadPageLoader.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/DownloadPageLoader.kt @@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.ui.reader.loader import android.app.Application import android.net.Uri +import com.hippo.unifile.UniFile import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.download.DownloadManager import eu.kanade.tachiyomi.source.Source @@ -10,6 +11,7 @@ import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter import eu.kanade.tachiyomi.ui.reader.model.ReaderPage import rx.Observable import uy.kohesive.injekt.injectLazy +import java.io.File /** * Loader used to load a chapter from the downloaded chapters. @@ -28,6 +30,20 @@ class DownloadPageLoader( * Returns an observable containing the pages found on this downloaded chapter. */ override fun getPages(): Observable> { + val chapterPath = downloadManager.provider.findChapterDir(chapter.chapter, manga, source) + return if (chapterPath?.isFile == true) { + getPagesFromArchive(chapterPath) + } else { + getPagesFromDirectory() + } + } + + private fun getPagesFromArchive(chapterPath: UniFile): Observable> { + val loader = ZipPageLoader(File(chapterPath.filePath!!)) + return loader.getPages() + } + + private fun getPagesFromDirectory(): Observable> { return downloadManager.buildPageList(source, manga, chapter.chapter) .map { pages -> pages.map { page -> diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsDownloadController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsDownloadController.kt index d8111bbdd4..ea12889e15 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsDownloadController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsDownloadController.kt @@ -68,6 +68,10 @@ class SettingsDownloadController : SettingsController() { titleRes = R.string.connected_to_wifi defaultValue = true } + switchPreference { + bindTo(preferences.saveChaptersAsCBZ()) + titleRes = R.string.save_chapter_as_cbz + } preferenceCategory { titleRes = R.string.pref_category_delete_chapters diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ccfe3f174e..7f8f743b64 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -398,6 +398,7 @@ Auto-download Download new chapters Manga in excluded categories will not be downloaded even if they are also in included categories. + Save as CBZ archive Tracking guide