diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 22cd05ecf8..fbbcbc1792 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -79,7 +79,7 @@
+ android:exported="false" />
,
+ private val file: File,
+ private val manga: Manga) : DataFetcher {
+
+
+ override fun loadData(priority: Priority?): InputStream? {
+ return fetcher.loadData(priority)
+ }
+
+ override fun getId(): String {
+ return manga.thumbnail_url + file.lastModified()
+ }
+
+ override fun cancel() {
+ fetcher.cancel()
+ }
+
+ override fun cleanup() {
+ fetcher.cleanup()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/glide/MangaModelLoader.kt b/app/src/main/java/eu/kanade/tachiyomi/data/glide/MangaModelLoader.kt
index 32abfb49aa..e155471a00 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/data/glide/MangaModelLoader.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/data/glide/MangaModelLoader.kt
@@ -1,10 +1,8 @@
package eu.kanade.tachiyomi.data.glide
import android.content.Context
-import android.net.Uri
import android.util.LruCache
import com.bumptech.glide.Glide
-import com.bumptech.glide.Priority
import com.bumptech.glide.load.data.DataFetcher
import com.bumptech.glide.load.model.*
import com.bumptech.glide.load.model.stream.StreamModelLoader
@@ -18,7 +16,7 @@ import java.io.InputStream
/**
* A class for loading a cover associated with a [Manga] that can be present in our own cache.
- * Coupled with [MangaDataFetcher], this class allows to implement the following flow:
+ * Coupled with [MangaUrlFetcher], this class allows to implement the following flow:
*
* - Check in RAM LRU.
* - Check in disk LRU.
@@ -32,23 +30,23 @@ class MangaModelLoader(context: Context) : StreamModelLoader {
/**
* Cover cache where persistent covers are stored.
*/
- val coverCache: CoverCache by injectLazy()
+ private val coverCache: CoverCache by injectLazy()
/**
* Source manager.
*/
- val sourceManager: SourceManager by injectLazy()
+ private val sourceManager: SourceManager by injectLazy()
/**
* Base network loader.
*/
- private val baseLoader = Glide.buildModelLoader(GlideUrl::class.java,
+ private val baseUrlLoader = Glide.buildModelLoader(GlideUrl::class.java,
InputStream::class.java, context)
/**
* Base file loader.
*/
- private val baseFileLoader = Glide.buildModelLoader(Uri::class.java,
+ private val baseFileLoader = Glide.buildModelLoader(File::class.java,
InputStream::class.java, context)
/**
@@ -74,7 +72,7 @@ class MangaModelLoader(context: Context) : StreamModelLoader {
}
/**
- * Returns a [MangaDataFetcher] for the given manga or null if the url is empty.
+ * Returns a fetcher for the given manga or null if the url is empty.
*
* @param manga the model.
* @param width the width of the view where the resource will be loaded.
@@ -86,34 +84,33 @@ class MangaModelLoader(context: Context) : StreamModelLoader {
// Check thumbnail is not null or empty
val url = manga.thumbnail_url
- if (url.isNullOrEmpty()) {
+ if (url == null || url.isEmpty()) {
return null
}
- if (url!!.startsWith("file://")) {
- val cover = File(url.substring(7))
- val id = url + File.separator + cover.lastModified()
- val rf = baseFileLoader.getResourceFetcher(Uri.fromFile(cover), width, height)
- return object : DataFetcher {
- override fun cleanup() = rf.cleanup()
- override fun loadData(priority: Priority?): InputStream = rf.loadData(priority)
- override fun cancel() = rf.cancel()
- override fun getId() = id
- }
+ if (url.startsWith("http")) {
+ // Obtain the request url and the file for this url from the LRU cache, or calculate it
+ // and add them to the cache.
+ val (glideUrl, file) = lruCache.get(url) ?:
+ Pair(GlideUrl(url, getHeaders(manga)), coverCache.getCoverFile(url)).apply {
+ lruCache.put(url, this)
+ }
+
+ // Get the resource fetcher for this request url.
+ val networkFetcher = baseUrlLoader.getResourceFetcher(glideUrl, width, height)
+
+ // Return an instance of the fetcher providing the needed elements.
+ return MangaUrlFetcher(networkFetcher, file, manga)
+ } else {
+ // Get the file from the url, removing the scheme if present.
+ val file = File(url.substringAfter("file://"))
+
+ // Get the resource fetcher for the given file.
+ val fileFetcher = baseFileLoader.getResourceFetcher(file, width, height)
+
+ // Return an instance of the fetcher providing the needed elements.
+ return MangaFileFetcher(fileFetcher, file, manga)
}
-
- // Obtain the request url and the file for this url from the LRU cache, or calculate it
- // and add them to the cache.
- val (glideUrl, file) = lruCache.get(url) ?:
- Pair(GlideUrl(url, getHeaders(manga)), coverCache.getCoverFile(url!!)).apply {
- lruCache.put(url, this)
- }
-
- // Get the network fetcher for this request url.
- val networkFetcher = baseLoader.getResourceFetcher(glideUrl, width, height)
-
- // Return an instance of our fetcher providing the needed elements.
- return MangaDataFetcher(networkFetcher, file, manga)
}
/**
diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/glide/MangaDataFetcher.kt b/app/src/main/java/eu/kanade/tachiyomi/data/glide/MangaUrlFetcher.kt
similarity index 94%
rename from app/src/main/java/eu/kanade/tachiyomi/data/glide/MangaDataFetcher.kt
rename to app/src/main/java/eu/kanade/tachiyomi/data/glide/MangaUrlFetcher.kt
index 2853fea7ed..9893377d22 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/data/glide/MangaDataFetcher.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/data/glide/MangaUrlFetcher.kt
@@ -18,9 +18,9 @@ import java.io.InputStream
* @param file the file where this cover should be. It may exists or not.
* @param manga the manga of the cover to load.
*/
-class MangaDataFetcher(private val networkFetcher: DataFetcher,
- private val file: File,
- private val manga: Manga)
+class MangaUrlFetcher(private val networkFetcher: DataFetcher,
+ private val file: File,
+ private val manga: Manga)
: DataFetcher {
@Throws(Exception::class)
diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/LocalSource.kt b/app/src/main/java/eu/kanade/tachiyomi/source/LocalSource.kt
index 0ff0349416..b46190c555 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/source/LocalSource.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/source/LocalSource.kt
@@ -20,7 +20,6 @@ import java.util.zip.ZipFile
class LocalSource(private val context: Context) : CatalogueSource {
companion object {
- private val FILE_PROTOCOL = "file://"
private val COVER_NAME = "cover.jpg"
private val POPULAR_FILTERS = FilterList(OrderBy())
private val LATEST_FILTERS = FilterList(OrderBy().apply { state = Filter.Sort.Selection(1, false) })
@@ -46,8 +45,8 @@ class LocalSource(private val context: Context) : CatalogueSource {
}
private fun getBaseDirectories(context: Context): List {
- val c = File.separator + context.getString(R.string.app_name) + File.separator + "local"
- return DiskUtil.getExternalStorages(context).map { File(it.absolutePath + c) }
+ val c = context.getString(R.string.app_name) + File.separator + "local"
+ return DiskUtil.getExternalStorages(context).map { File(it.absolutePath, c) }
}
}
@@ -67,7 +66,7 @@ class LocalSource(private val context: Context) : CatalogueSource {
.filter { it.isDirectory || isSupportedFormat(it.extension) }
.map { chapterFile ->
SChapter.create().apply {
- url = chapterFile.absolutePath
+ url = "${manga.url}/${chapterFile.name}"
val chapName = if (chapterFile.isDirectory) {
chapterFile.name
} else {
@@ -79,27 +78,37 @@ class LocalSource(private val context: Context) : CatalogueSource {
ChapterRecognition.parseChapterNumber(this, manga)
}
}
+ .sortedByDescending { it.chapter_number }
- return Observable.just(chapters.sortedByDescending { it.chapter_number })
+ return Observable.just(chapters)
}
override fun fetchPageList(chapter: SChapter): Observable> {
- val chapFile = File(chapter.url)
- if (chapFile.isDirectory) {
- return Observable.just(chapFile.listFiles()
- .filter { !it.isDirectory && DiskUtil.isImage(it.name, { FileInputStream(it) }) }
- .sortedWith(Comparator { t1, t2 -> CaseInsensitiveSimpleNaturalComparator.getInstance().compare(t1.name, t2.name) })
- .mapIndexed { i, v -> Page(i, FILE_PROTOCOL + v.absolutePath, FILE_PROTOCOL + v.absolutePath, Uri.fromFile(v)).apply { status = Page.READY } })
- } else {
- val zip = ZipFile(chapFile)
- return Observable.just(ZipFile(chapFile).entries().toList()
- .filter { !it.isDirectory && DiskUtil.isImage(it.name, { zip.getInputStream(it) }) }
- .sortedWith(Comparator { t1, t2 -> CaseInsensitiveSimpleNaturalComparator.getInstance().compare(t1.name, t2.name) })
- .mapIndexed { i, v ->
- val path = "content://${ZipContentProvider.PROVIDER}${chapFile.absolutePath}!/${v.name}"
- Page(i, path, path, Uri.parse(path)).apply { status = Page.READY }
- })
+ val baseDirs = getBaseDirectories(context)
+
+ for (dir in baseDirs) {
+ val chapFile = File(dir, chapter.url)
+ if (!chapFile.exists()) continue
+
+ val comparator = CaseInsensitiveSimpleNaturalComparator.getInstance()
+
+ val pageList = if (chapFile.isDirectory) {
+ chapFile.listFiles()
+ .filter { !it.isDirectory && DiskUtil.isImage(it.name, { FileInputStream(it) }) }
+ .sortedWith(Comparator { f1, f2 -> comparator.compare(f1.name, f2.name) })
+ .map { Uri.fromFile(it) }
+ } else {
+ val zip = ZipFile(chapFile)
+ zip.entries().toList()
+ .filter { !it.isDirectory && DiskUtil.isImage(it.name, { zip.getInputStream(it) }) }
+ .sortedWith(Comparator { f1, f2 -> comparator.compare(f1.name, f2.name) })
+ .map { Uri.parse("content://${ZipContentProvider.PROVIDER}${chapFile.absolutePath}!/${it.name}") }
+ }.mapIndexed { i, uri -> Page(i, uri = uri).apply { status = Page.READY } }
+
+ return Observable.just(pageList)
}
+
+ return Observable.error(Exception("Chapter not found"))
}
override fun fetchPopularManga(page: Int) = fetchSearchManga(page, "", POPULAR_FILTERS)
@@ -138,7 +147,7 @@ class LocalSource(private val context: Context) : CatalogueSource {
for (dir in baseDirs) {
val cover = File("${dir.absolutePath}/$url", COVER_NAME)
if (cover.exists()) {
- thumbnail_url = FILE_PROTOCOL + cover.absolutePath
+ thumbnail_url = cover.absolutePath
break
}
}
@@ -152,7 +161,7 @@ class LocalSource(private val context: Context) : CatalogueSource {
val input = context.contentResolver.openInputStream(Uri.parse(url))
try {
val dest = updateCover(context, this, input)
- thumbnail_url = dest?.let { FILE_PROTOCOL + it.absolutePath }
+ thumbnail_url = dest?.absolutePath
} catch (e: Exception) {
Timber.e(e)
}
diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/ZipContentProvider.kt b/app/src/main/java/eu/kanade/tachiyomi/util/ZipContentProvider.kt
index b95cc5b390..737007720b 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/util/ZipContentProvider.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/util/ZipContentProvider.kt
@@ -7,7 +7,6 @@ import android.database.Cursor
import android.net.Uri
import android.os.ParcelFileDescriptor
import eu.kanade.tachiyomi.BuildConfig
-import timber.log.Timber
import java.io.IOException
import java.net.URL
import java.net.URLConnection
@@ -40,11 +39,10 @@ class ZipContentProvider : ContentProvider() {
input.use {
output.use {
input.copyTo(output)
- output.flush()
}
}
} catch (e: IOException) {
- Timber.e(e)
+ // Ignore
}
}
return AssetFileDescriptor(pipe[0], 0, -1)