mirror of
https://github.com/Suwayomi/Suwayomi-Server.git
synced 2026-07-10 22:34:33 -05:00
rethink image cache (#498)
This commit is contained in:
@@ -22,16 +22,16 @@ import java.io.File
|
||||
|
||||
private val applicationDirs by DI.global.instance<ApplicationDirs>()
|
||||
|
||||
fun getMangaDir(mangaId: Int, cache: Boolean = false): String {
|
||||
private fun getMangaDir(mangaId: Int): String {
|
||||
val mangaEntry = getMangaEntry(mangaId)
|
||||
val source = GetCatalogueSource.getCatalogueSourceOrStub(mangaEntry[MangaTable.sourceReference])
|
||||
|
||||
val sourceDir = source.toString()
|
||||
val sourceDir = SafePath.buildValidFilename(source.toString())
|
||||
val mangaDir = SafePath.buildValidFilename(mangaEntry[MangaTable.title])
|
||||
return (if (cache) applicationDirs.cacheRoot else applicationDirs.mangaDownloadsRoot) + "/$sourceDir/$mangaDir"
|
||||
return "$sourceDir/$mangaDir"
|
||||
}
|
||||
|
||||
fun getChapterDir(mangaId: Int, chapterId: Int, cache: Boolean = false): String {
|
||||
private fun getChapterDir(mangaId: Int, chapterId: Int): String {
|
||||
val chapterEntry = transaction { ChapterTable.select { ChapterTable.id eq chapterId }.first() }
|
||||
|
||||
val chapterDir = SafePath.buildValidFilename(
|
||||
@@ -41,9 +41,18 @@ fun getChapterDir(mangaId: Int, chapterId: Int, cache: Boolean = false): String
|
||||
}
|
||||
)
|
||||
|
||||
return getMangaDir(mangaId, cache) + "/$chapterDir"
|
||||
return getMangaDir(mangaId) + "/$chapterDir"
|
||||
}
|
||||
|
||||
fun getChapterDownloadPath(mangaId: Int, chapterId: Int): String {
|
||||
return applicationDirs.mangaDownloadsRoot + "/" + getChapterDir(mangaId, chapterId)
|
||||
}
|
||||
fun getChapterCachePath(mangaId: Int, chapterId: Int): String {
|
||||
return applicationDirs.tempMangaCacheRoot + "/" + getChapterDir(mangaId, chapterId)
|
||||
}
|
||||
|
||||
// (if (useTempCache) applicationDirs.tempCacheRoot else )
|
||||
|
||||
/** return value says if rename/move was successful */
|
||||
fun updateMangaDownloadDir(mangaId: Int, newTitle: String): Boolean {
|
||||
val mangaEntry = getMangaEntry(mangaId)
|
||||
|
||||
@@ -9,7 +9,6 @@ package suwayomi.tachidesk.manga.impl.util.storage
|
||||
|
||||
import okhttp3.Response
|
||||
import okhttp3.internal.closeQuietly
|
||||
import suwayomi.tachidesk.manga.impl.util.getChapterDir
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import java.io.InputStream
|
||||
@@ -19,6 +18,7 @@ object ImageResponse {
|
||||
return FileInputStream(path).buffered()
|
||||
}
|
||||
|
||||
/** find file with name when file extension is not known */
|
||||
fun findFileNameStartingWith(directoryPath: String, fileName: String): String? {
|
||||
val target = "$fileName."
|
||||
File(directoryPath).listFiles().orEmpty().forEach { file ->
|
||||
@@ -29,8 +29,17 @@ object ImageResponse {
|
||||
return null
|
||||
}
|
||||
|
||||
/** fetch a cached image response, calls `fetcher` if cache fails */
|
||||
private suspend fun getCachedImageResponse(saveDir: String, fileName: String, fetcher: suspend () -> Response): Pair<InputStream, String> {
|
||||
/**
|
||||
* Get a cached image response
|
||||
*
|
||||
* Note: The caller should also call [clearCachedImage] when appropriate
|
||||
*
|
||||
* @param cacheSavePath where to save the cached image. Caller should decide to use perma cache or temp cache (OS temp dir)
|
||||
* @param fileName what the saved cache file should be named
|
||||
*/
|
||||
suspend fun getCachedImageResponse(saveDir: String, fileName: String, fetcher: suspend () -> Response): Pair<InputStream, String> {
|
||||
File(saveDir).mkdirs()
|
||||
|
||||
val cachedFile = findFileNameStartingWith(saveDir, fileName)
|
||||
val filePath = "$saveDir/$fileName"
|
||||
if (cachedFile != null) {
|
||||
@@ -52,6 +61,7 @@ object ImageResponse {
|
||||
}
|
||||
}
|
||||
|
||||
/** Save image safely */
|
||||
fun saveImage(filePath: String, image: InputStream): Pair<String, String> {
|
||||
val tmpSavePath = "$filePath.tmp"
|
||||
val tmpSaveFile = File(tmpSavePath)
|
||||
@@ -73,39 +83,4 @@ object ImageResponse {
|
||||
File(it).delete()
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun getNoCacheImageResponse(fetcher: suspend () -> Response): Pair<InputStream, String> {
|
||||
val response = fetcher()
|
||||
|
||||
if (response.code == 200) {
|
||||
val responseBytes = response.body!!.bytes()
|
||||
|
||||
// find image type
|
||||
val imageType = response.headers["content-type"]
|
||||
?: ImageUtil.findImageType { responseBytes.inputStream() }?.mime
|
||||
?: "image/jpeg"
|
||||
|
||||
return responseBytes.inputStream() to imageType
|
||||
} else {
|
||||
response.closeQuietly()
|
||||
throw Exception("request error! ${response.code}")
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getImageResponse(saveDir: String, fileName: String, useCache: Boolean, fetcher: suspend () -> Response): Pair<InputStream, String> {
|
||||
return if (useCache) {
|
||||
getCachedImageResponse(saveDir, fileName, fetcher)
|
||||
} else {
|
||||
getNoCacheImageResponse(fetcher)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getImageResponse(mangaId: Int, chapterId: Int, fileName: String, useCache: Boolean, fetcher: suspend () -> Response): Pair<InputStream, String> {
|
||||
var saveDir = ""
|
||||
if (useCache) {
|
||||
saveDir = getChapterDir(mangaId, chapterId, true)
|
||||
File(saveDir).mkdirs()
|
||||
}
|
||||
return getImageResponse(saveDir, fileName, useCache, fetcher)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user