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:
@@ -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 ->
|
||||
|
||||
+2
-20
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user