Added mirror selector

Developing new Downloader under xyz.quaver.pupil.util.download
This commit is contained in:
Pupil
2020-01-24 15:11:35 +09:00
parent 37123a2cd5
commit c204353220
27 changed files with 651 additions and 92 deletions

View File

@@ -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()

View 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))
}
}

View File

@@ -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)
}
}
}
}

View 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
)

View File

@@ -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)