fix password protect downloads and copying ComicInfo files in LocalSource (#1084)

* fix password protect downloads

* fixed copying of ComicInfo file in LocalSource.kt

* Return correct archive file

* Applied upstream fix

* Use tempFileManager instead of file path

* Use streams instead of files
This commit is contained in:
Shamicen
2024-03-02 17:56:57 +01:00
committed by GitHub
parent dd412e33ad
commit eed8ffb9d4
5 changed files with 170 additions and 105 deletions
@@ -11,6 +11,10 @@ import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.util.lang.compareToCaseInsensitiveNaturalOrder
import eu.kanade.tachiyomi.util.storage.CbzCrypto
import eu.kanade.tachiyomi.util.storage.CbzCrypto.addStreamToZip
import eu.kanade.tachiyomi.util.storage.CbzCrypto.getCoverStreamFromZip
import eu.kanade.tachiyomi.util.storage.CbzCrypto.getZipInputStream
import eu.kanade.tachiyomi.util.storage.CbzCrypto.isEncryptedZip
import eu.kanade.tachiyomi.util.storage.EpubFile
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
@@ -18,8 +22,6 @@ import kotlinx.serialization.json.Json
import kotlinx.serialization.json.decodeFromStream
import kotlinx.serialization.json.encodeToStream
import logcat.LogPriority
import net.lingala.zip4j.ZipFile
import net.lingala.zip4j.model.ZipParameters
import nl.adaptivity.xmlutil.AndroidXmlReader
import nl.adaptivity.xmlutil.serialization.XML
import tachiyomi.core.common.i18n.stringResource
@@ -44,7 +46,6 @@ import tachiyomi.source.local.io.Format
import tachiyomi.source.local.io.LocalSourceFileSystem
import tachiyomi.source.local.metadata.fillMetadata
import uy.kohesive.injekt.injectLazy
import java.io.File
import java.io.InputStream
import java.nio.charset.StandardCharsets
import kotlin.time.Duration.Companion.days
@@ -199,15 +200,12 @@ actual class LocalSource(
}
// SY -->
comicInfoArchiveFile != null -> {
val comicInfoArchive = ZipFile(tempFileManager.createTempFile(comicInfoArchiveFile))
noXmlFile?.delete()
if (CbzCrypto.checkCbzPassword(comicInfoArchive, CbzCrypto.getDecryptedPasswordCbz())) {
comicInfoArchive.setPassword(CbzCrypto.getDecryptedPasswordCbz())
val comicInfoEntry = comicInfoArchive.fileHeaders.firstOrNull { it.fileName == COMIC_INFO_FILE }
setMangaDetailsFromComicInfoFile(comicInfoArchive.getInputStream(comicInfoEntry), manga)
}
comicInfoArchiveFile.getZipInputStream(COMIC_INFO_FILE)
?.let { setMangaDetailsFromComicInfoFile(it, manga) }
}
// SY <--
// Old custom JSON format
@@ -239,18 +237,13 @@ actual class LocalSource(
.filter(Archive::isSupported)
.toList()
val folderPath = mangaDir?.filePath
val copiedFile = mangaDir?.let { copyComicInfoFileFromArchive(chapterArchives, it) }
val copiedFile = copyComicInfoFileFromArchive(chapterArchives, folderPath)
// SY -->
if (copiedFile != null && copiedFile.name != COMIC_INFO_ARCHIVE) {
setMangaDetailsFromComicInfoFile(copiedFile.inputStream(), manga)
setMangaDetailsFromComicInfoFile(copiedFile.openInputStream(), manga)
} else if (copiedFile != null && copiedFile.name == COMIC_INFO_ARCHIVE) {
val comicInfoArchive = ZipFile(copiedFile)
comicInfoArchive.setPassword(CbzCrypto.getDecryptedPasswordCbz())
val comicInfoEntry = comicInfoArchive.fileHeaders.firstOrNull { it.fileName == COMIC_INFO_FILE }
setMangaDetailsFromComicInfoFile(comicInfoArchive.getInputStream(comicInfoEntry), manga)
copiedFile.getZipInputStream(COMIC_INFO_FILE)?.let { setMangaDetailsFromComicInfoFile(it, manga) }
} // SY <--
else {
// Avoid re-scanning
@@ -265,33 +258,20 @@ actual class LocalSource(
return@withIOContext manga
}
private fun copyComicInfoFileFromArchive(chapterArchives: List<UniFile>, folderPath: String?): File? {
private fun copyComicInfoFileFromArchive(chapterArchives: List<UniFile>, folder: UniFile): UniFile? {
for (chapter in chapterArchives) {
when (Format.valueOf(chapter)) {
is Format.Zip -> {
ZipFile(tempFileManager.createTempFile(chapter)).use { zip: ZipFile ->
// SY -->
if (zip.isEncrypted && !CbzCrypto.checkCbzPassword(zip, CbzCrypto.getDecryptedPasswordCbz())
) {
return null
} else if (
zip.isEncrypted && CbzCrypto.checkCbzPassword(zip, CbzCrypto.getDecryptedPasswordCbz())
) {
zip.setPassword(CbzCrypto.getDecryptedPasswordCbz())
}
zip.getFileHeader(COMIC_INFO_FILE)?.let { comicInfoFile ->
// SY <--
zip.getInputStream(comicInfoFile).buffered().use { stream ->
return copyComicInfoFile(stream, folderPath)
}
}
// SY -->
chapter.getZipInputStream(COMIC_INFO_FILE)?.buffered().use { stream ->
return stream?.let { copyComicInfoFile(it, folder) }
}
}
is Format.Rar -> {
JunrarArchive(tempFileManager.createTempFile(chapter)).use { rar ->
rar.fileHeaders.firstOrNull { it.fileName == COMIC_INFO_FILE }?.let { comicInfoFile ->
rar.getInputStream(comicInfoFile).buffered().use { stream ->
return copyComicInfoFile(stream, folderPath)
return copyComicInfoFile(stream, folder)
}
}
}
@@ -302,24 +282,20 @@ actual class LocalSource(
return null
}
private fun copyComicInfoFile(comicInfoFileStream: InputStream, folderPath: String?): File {
private fun copyComicInfoFile(comicInfoFileStream: InputStream, folder: UniFile): UniFile? {
// SY -->
if (
CbzCrypto.getPasswordProtectDlPref() &&
CbzCrypto.isPasswordSet()
) {
val zipParameters = ZipParameters()
CbzCrypto.setZipParametersEncrypted(zipParameters)
zipParameters.fileNameInZip = COMIC_INFO_FILE
val comicInfoArchive = folder.createFile(COMIC_INFO_ARCHIVE)
comicInfoArchive?.addStreamToZip(comicInfoFileStream, COMIC_INFO_FILE, CbzCrypto.getDecryptedPasswordCbz())
val zipEncrypted = ZipFile("$folderPath/$COMIC_INFO_ARCHIVE")
zipEncrypted.setPassword(CbzCrypto.getDecryptedPasswordCbz())
zipEncrypted.addStream(comicInfoFileStream, zipParameters)
return zipEncrypted.file
return comicInfoArchive
} else {
// SY <--
return File("$folderPath/$COMIC_INFO_FILE").apply {
outputStream().use { outputStream ->
return folder.createFile(COMIC_INFO_FILE)?.apply {
openOutputStream().use { outputStream ->
comicInfoFileStream.use { it.copyTo(outputStream) }
}
}
@@ -413,19 +389,15 @@ actual class LocalSource(
entry?.let { coverManager.update(manga, it.openInputStream()) }
}
is Format.Zip -> {
ZipFile(tempFileManager.createTempFile(format.file)).use { zip ->
// SY -->
var encrypted = false
if (zip.isEncrypted) {
zip.setPassword(CbzCrypto.getDecryptedPasswordCbz())
encrypted = true
}
val entry = zip.fileHeaders.toList()
.sortedWith { f1, f2 -> f1.fileName.compareToCaseInsensitiveNaturalOrder(f2.fileName) }
.find { !it.isDirectory && ImageUtil.isImage(it.fileName) { zip.getInputStream(it) } }
entry?.let { coverManager.update(manga, zip.getInputStream(it), encrypted) }
// SY <--
// SY -->
format.file.getCoverStreamFromZip()?.let { inputStream ->
coverManager.update(
manga,
inputStream,
format.file.isEncryptedZip()
)
}
// SY <--
}
is Format.Rar -> {
JunrarArchive(tempFileManager.createTempFile(format.file)).use { archive ->
@@ -4,13 +4,11 @@ import android.content.Context
import com.hippo.unifile.UniFile
import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.util.storage.CbzCrypto
import eu.kanade.tachiyomi.util.storage.CbzCrypto.addStreamToZip
import eu.kanade.tachiyomi.util.storage.DiskUtil
import net.lingala.zip4j.ZipFile
import net.lingala.zip4j.model.ZipParameters
import tachiyomi.core.common.storage.nameWithoutExtension
import tachiyomi.core.common.util.system.ImageUtil
import tachiyomi.source.local.io.LocalSourceFileSystem
import java.io.File
import java.io.InputStream
private const val DEFAULT_COVER_NAME = "cover.jpg"
@@ -60,23 +58,7 @@ actual class LocalCoverManager(
inputStream.use { input ->
// SY -->
if (encrypted) {
val tempFile = File.createTempFile(
targetFile.nameWithoutExtension.orEmpty().padEnd(3), // Prefix must be 3+ chars
null,
)
val zip4j = ZipFile(tempFile)
val zipParameters = ZipParameters()
zip4j.setPassword(CbzCrypto.getDecryptedPasswordCbz())
CbzCrypto.setZipParametersEncrypted(zipParameters)
zipParameters.fileNameInZip = DEFAULT_COVER_NAME
zip4j.addStream(input, zipParameters)
zip4j.close()
targetFile.openOutputStream().use { output ->
tempFile.inputStream().use { input ->
input.copyTo(output)
}
}
targetFile.addStreamToZip(inputStream, DEFAULT_COVER_NAME, CbzCrypto.getDecryptedPasswordCbz())
DiskUtil.createNoMediaFile(directory, context)
manga.thumbnail_url = targetFile.uri.toString()