Added mirror selector
Developing new Downloader under xyz.quaver.pupil.util.download
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Pupil, Hitomi.la viewer for Android
|
||||
* Copyright (C) 2019 tom5079
|
||||
* Copyright (C) 2020 tom5079
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -65,7 +65,10 @@ class GalleryDownloader(
|
||||
notificationManager.notify(galleryID, notificationBuilder.build())
|
||||
|
||||
if (reader?.isActive == false && downloadJob?.isActive != true) {
|
||||
val data = File(getDownloadDirectory(this), galleryID.toString())
|
||||
val data = File(
|
||||
getDownloadDirectory(
|
||||
this
|
||||
), galleryID.toString())
|
||||
val cache = File(cacheDir, "imageCache/$galleryID")
|
||||
|
||||
if (File(cache, "images").exists() && !data.exists()) {
|
||||
@@ -111,7 +114,11 @@ class GalleryDownloader(
|
||||
val serializer = Reader.serializer()
|
||||
|
||||
//Check cache
|
||||
val cache = File(getCachedGallery(this@GalleryDownloader, galleryID), "reader.json")
|
||||
val cache = File(
|
||||
getCachedGallery(
|
||||
this@GalleryDownloader,
|
||||
galleryID
|
||||
), "reader.json")
|
||||
|
||||
try {
|
||||
json.parse(serializer, cache.readText())
|
||||
@@ -197,7 +204,11 @@ class GalleryDownloader(
|
||||
val name = "$index".padStart(4, '0')
|
||||
val ext = url.split('.').last()
|
||||
|
||||
val cache = File(getCachedGallery(this@GalleryDownloader, galleryID), "images/$name.$ext")
|
||||
val cache = File(
|
||||
getCachedGallery(
|
||||
this@GalleryDownloader,
|
||||
galleryID
|
||||
), "images/$name.$ext")
|
||||
|
||||
if (!cache.exists())
|
||||
try {
|
||||
@@ -255,7 +266,10 @@ class GalleryDownloader(
|
||||
if (download) {
|
||||
File(cacheDir, "imageCache/${galleryID}").let {
|
||||
if (it.exists()) {
|
||||
val target = File(getDownloadDirectory(this@GalleryDownloader), galleryID.toString())
|
||||
val target = File(
|
||||
getDownloadDirectory(
|
||||
this@GalleryDownloader
|
||||
), galleryID.toString())
|
||||
|
||||
if (!target.exists())
|
||||
target.mkdirs()
|
||||
|
||||
142
app/src/main/java/xyz/quaver/pupil/util/download/Cache.kt
Normal file
142
app/src/main/java/xyz/quaver/pupil/util/download/Cache.kt
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Pupil, Hitomi.la viewer for Android
|
||||
* Copyright (C) 2020 tom5079
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.quaver.pupil.util.download
|
||||
|
||||
import android.content.Context
|
||||
import android.content.ContextWrapper
|
||||
import androidx.core.content.ContextCompat
|
||||
import kotlinx.serialization.ImplicitReflectionSerializer
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.parse
|
||||
import kotlinx.serialization.stringify
|
||||
import xyz.quaver.hitomi.GalleryBlock
|
||||
import xyz.quaver.hitomi.Reader
|
||||
import java.io.File
|
||||
|
||||
class Cache(context: Context) : ContextWrapper(context) {
|
||||
|
||||
// Search in this order
|
||||
// Download -> Cache
|
||||
fun getCachedGallery(galleryID: Int) : File? {
|
||||
var file : File
|
||||
|
||||
ContextCompat.getExternalFilesDirs(this, null).forEach {
|
||||
file = File(it, galleryID.toString())
|
||||
|
||||
if (file.exists())
|
||||
return file
|
||||
}
|
||||
|
||||
file = File(cacheDir, "imageCache/$galleryID")
|
||||
|
||||
return if (file.exists())
|
||||
file
|
||||
else
|
||||
null
|
||||
}
|
||||
|
||||
@UseExperimental(ImplicitReflectionSerializer::class)
|
||||
fun getCachedMetadata(galleryID: Int) : Metadata? {
|
||||
val file = File(getCachedGallery(galleryID) ?: return null, ".metadata")
|
||||
|
||||
if (!file.exists())
|
||||
return null
|
||||
|
||||
return try {
|
||||
Json.parse(file.readText())
|
||||
} catch (e: Exception) {
|
||||
//File corrupted
|
||||
file.delete()
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
@UseExperimental(ImplicitReflectionSerializer::class)
|
||||
fun setCachedMetadata(galleryID: Int, metadata: Metadata) {
|
||||
val file = File(getCachedGallery(galleryID), ".metadata")
|
||||
|
||||
if (!file.exists())
|
||||
return
|
||||
|
||||
try {
|
||||
file.writeText(Json.stringify(metadata))
|
||||
} catch (e: Exception) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
fun getGalleryBlock(galleryID: Int): GalleryBlock {
|
||||
var meta = Cache(this).getCachedMetadata(galleryID)
|
||||
|
||||
if (meta == null) {
|
||||
meta = Metadata(galleryBlock = xyz.quaver.hitomi.getGalleryBlock(galleryID))
|
||||
|
||||
Cache(this).setCachedMetadata(
|
||||
galleryID,
|
||||
meta
|
||||
)
|
||||
} else if (meta.galleryBlock == null)
|
||||
Cache(this).setCachedMetadata(
|
||||
galleryID,
|
||||
meta.apply {
|
||||
galleryBlock = xyz.quaver.hitomi.getGalleryBlock(galleryID)
|
||||
}
|
||||
)
|
||||
|
||||
return meta.galleryBlock!!
|
||||
}
|
||||
|
||||
fun getReaders(galleryID: Int): List<Reader> {
|
||||
var meta = getCachedMetadata(galleryID)
|
||||
|
||||
if (meta == null) {
|
||||
meta = Metadata(reader = mutableListOf(xyz.quaver.hitomi.getReader(galleryID)))
|
||||
|
||||
setCachedMetadata(
|
||||
galleryID,
|
||||
meta
|
||||
)
|
||||
} else if (meta.reader == null)
|
||||
setCachedMetadata(
|
||||
galleryID,
|
||||
meta.apply {
|
||||
reader = mutableListOf(xyz.quaver.hitomi.getReader(galleryID))
|
||||
}
|
||||
)
|
||||
else if (!meta.reader!!.any { it.code == Reader.Code.HITOMI })
|
||||
setCachedMetadata(
|
||||
galleryID,
|
||||
meta.apply {
|
||||
reader!!.add(xyz.quaver.hitomi.getReader(galleryID))
|
||||
}
|
||||
)
|
||||
|
||||
return meta.reader!!
|
||||
}
|
||||
|
||||
fun getImage(galleryID: Int, index: Int): File {
|
||||
val cache = getCachedGallery(galleryID)
|
||||
|
||||
if (cache == null)
|
||||
;//TODO: initiate image download
|
||||
|
||||
return File(cache, "%04d".format(index))
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Pupil, Hitomi.la viewer for Android
|
||||
* Copyright (C) 2020 tom5079
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.quaver.pupil.util.download
|
||||
|
||||
import android.content.Context
|
||||
import android.content.ContextWrapper
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.asCoroutineDispatcher
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.launch
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.ResponseBody
|
||||
import okio.*
|
||||
import java.util.concurrent.Executors
|
||||
|
||||
class DownloadWorker(context: Context) : ContextWrapper(context) {
|
||||
|
||||
interface ProgressListener {
|
||||
fun update(bytesRead : Long, contentLength: Long, done: Boolean)
|
||||
}
|
||||
|
||||
//region ProgressResponseBody
|
||||
class ProgressResponseBody(
|
||||
val responseBody: ResponseBody,
|
||||
val progressListener : ProgressListener
|
||||
) : ResponseBody() {
|
||||
var bufferedSource : BufferedSource? = null
|
||||
|
||||
override fun contentLength() = responseBody.contentLength()
|
||||
override fun contentType() = responseBody.contentType()
|
||||
|
||||
override fun source(): BufferedSource {
|
||||
if (bufferedSource == null)
|
||||
bufferedSource = source(responseBody.source()).buffer()
|
||||
|
||||
return bufferedSource!!
|
||||
}
|
||||
|
||||
private fun source(source: Source) = object: ForwardingSource(source) {
|
||||
|
||||
var totalBytesRead = 0L
|
||||
|
||||
override fun read(sink: Buffer, byteCount: Long): Long {
|
||||
val bytesRead = super.read(sink, byteCount)
|
||||
|
||||
totalBytesRead += if (bytesRead == -1L) 0L else bytesRead
|
||||
progressListener.update(totalBytesRead, responseBody.contentLength(), bytesRead == -1L)
|
||||
|
||||
return bytesRead
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
//endregion
|
||||
|
||||
val queue = Channel<Int>()
|
||||
val worker = Executors.newFixedThreadPool(4).asCoroutineDispatcher()
|
||||
|
||||
val progressListener = object: ProgressListener {
|
||||
override fun update(bytesRead: Long, contentLength: Long, done: Boolean) {
|
||||
|
||||
}
|
||||
}
|
||||
val client = OkHttpClient.Builder()
|
||||
.addNetworkInterceptor { chain ->
|
||||
chain.proceed(chain.request()).let { originalResponse ->
|
||||
originalResponse.newBuilder()
|
||||
.body(ProgressResponseBody(originalResponse.body!!, progressListener))
|
||||
.build()
|
||||
}
|
||||
}.build()
|
||||
|
||||
init {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
while (true) {
|
||||
val galleryID = queue.receive()
|
||||
|
||||
val reader = Cache(context).getReaders(galleryID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
30
app/src/main/java/xyz/quaver/pupil/util/download/Metadata.kt
Normal file
30
app/src/main/java/xyz/quaver/pupil/util/download/Metadata.kt
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Pupil, Hitomi.la viewer for Android
|
||||
* Copyright (C) 2020 tom5079
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.quaver.pupil.util.download
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import xyz.quaver.hitomi.GalleryBlock
|
||||
import xyz.quaver.hitomi.Reader
|
||||
|
||||
@Serializable
|
||||
data class Metadata(
|
||||
var thumbnail: String? = null,
|
||||
var galleryBlock: GalleryBlock? = null,
|
||||
var reader: MutableList<Reader>? = null
|
||||
)
|
||||
@@ -49,6 +49,7 @@ fun URL.download(to: File, onDownloadProgress: ((Long, Long) -> Unit)? = null) {
|
||||
|
||||
var bytesCopied: Long = 0
|
||||
val buffer = ByteArray(DEFAULT_BUFFER_SIZE)
|
||||
|
||||
var bytes = it.read(buffer)
|
||||
while (bytes >= 0) {
|
||||
out.write(buffer, 0, bytes)
|
||||
|
||||
Reference in New Issue
Block a user