Rebuilding Downloader

This commit is contained in:
Pupil
2020-01-28 10:48:31 +09:00
parent d73dc19d3d
commit 10712e6e62
5 changed files with 103 additions and 64 deletions

1
.idea/vcs.xml generated
View File

@@ -2,6 +2,5 @@
<project version="4"> <project version="4">
<component name="VcsDirectoryMappings"> <component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" /> <mapping directory="" vcs="Git" />
<mapping directory="$PROJECT_DIR$/gh-pages" vcs="Git" />
</component> </component>
</project> </project>

View File

@@ -19,6 +19,7 @@
package xyz.quaver.pupil.adapters package xyz.quaver.pupil.adapters
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.util.Log
import android.util.SparseBooleanArray import android.util.SparseBooleanArray
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
@@ -129,6 +130,8 @@ class GalleryBlockAdapter(private val glide: RequestManager, private val galleri
with(view.galleryblock_progressbar) { with(view.galleryblock_progressbar) {
progress = imageCache.invoke().list()?.size ?: 0 progress = imageCache.invoke().list()?.size ?: 0
Log.i("PUPILD", progress.toString())
if (!readerCache.invoke().exists()) { if (!readerCache.invoke().exists()) {
visibility = View.GONE visibility = View.GONE
max = 0 max = 0

View File

@@ -21,6 +21,8 @@ package xyz.quaver.pupil.util.download
import android.content.Context import android.content.Context
import android.content.ContextWrapper import android.content.ContextWrapper
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.preference.PreferenceManager
import kotlinx.coroutines.*
import kotlinx.serialization.ImplicitReflectionSerializer import kotlinx.serialization.ImplicitReflectionSerializer
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import kotlinx.serialization.parse import kotlinx.serialization.parse
@@ -31,6 +33,8 @@ import java.io.File
class Cache(context: Context) : ContextWrapper(context) { class Cache(context: Context) : ContextWrapper(context) {
private val preference = PreferenceManager.getDefaultSharedPreferences(this)
// Search in this order // Search in this order
// Download -> Cache // Download -> Cache
fun getCachedGallery(galleryID: Int) : File? { fun getCachedGallery(galleryID: Int) : File? {
@@ -81,62 +85,63 @@ class Cache(context: Context) : ContextWrapper(context) {
} }
} }
fun getGalleryBlock(galleryID: Int): GalleryBlock { suspend fun getGalleryBlock(galleryID: Int): GalleryBlock? {
var meta = Cache(this).getCachedMetadata(galleryID) val metadata = Cache(this).getCachedMetadata(galleryID)
if (meta == null) { val galleryBlock = if (metadata?.galleryBlock == null)
meta = Metadata(galleryBlock = xyz.quaver.hitomi.getGalleryBlock(galleryID)) withContext(Dispatchers.IO) {
try {
xyz.quaver.hitomi.getGalleryBlock(galleryID)
} catch (e: Exception) {
null
}
}
else
metadata.galleryBlock
Cache(this).setCachedMetadata( setCachedMetadata(
galleryID, galleryID,
meta Metadata(metadata, galleryBlock = galleryBlock)
) )
} else if (meta.galleryBlock == null)
Cache(this).setCachedMetadata(
galleryID,
meta.apply {
galleryBlock = xyz.quaver.hitomi.getGalleryBlock(galleryID)
}
)
return meta.galleryBlock!! return galleryBlock
} }
fun getReaders(galleryID: Int): List<Reader> { suspend fun getReader(galleryID: Int): Reader? {
var meta = getCachedMetadata(galleryID) val metadata = getCachedMetadata(galleryID)
if (meta == null) { val readers = if (metadata?.readers == null) {
meta = Metadata(reader = mutableListOf(xyz.quaver.hitomi.getReader(galleryID))) listOf(
{ xyz.quaver.hitomi.getReader(galleryID) },
setCachedMetadata( { xyz.quaver.hiyobi.getReader(galleryID) }
galleryID, ).map {
meta CoroutineScope(Dispatchers.IO).async {
) try {
} else if (meta.reader == null) it.invoke()
setCachedMetadata( } catch (e: Exception) {
galleryID, null
meta.apply { }
reader = mutableListOf(xyz.quaver.hitomi.getReader(galleryID))
} }
) }.awaitAll().filterNotNull()
else if (!meta.reader!!.any { it.code == Reader.Code.HITOMI }) } else {
metadata.readers
}
if (readers.isNotEmpty())
setCachedMetadata( setCachedMetadata(
galleryID, galleryID,
meta.apply { Metadata(metadata, readers = readers)
reader!!.add(xyz.quaver.hitomi.getReader(galleryID))
}
) )
return meta.reader!! val mirrors = preference.getString("mirrors", "")!!.split('>')
return readers.firstOrNull {
mirrors.contains(it.code.name)
}
} }
fun getImage(galleryID: Int, index: Int): File { suspend fun getImage(galleryID: Int): File? {
val cache = getCachedGallery(galleryID) TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
if (cache == null)
;//TODO: initiate image download
return File(cache, "%04d".format(index))
} }
} }

View File

@@ -20,24 +20,26 @@ package xyz.quaver.pupil.util.download
import android.content.Context import android.content.Context
import android.content.ContextWrapper import android.content.ContextWrapper
import kotlinx.coroutines.CoroutineScope import androidx.preference.PreferenceManager
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.*
import kotlinx.coroutines.asCoroutineDispatcher
import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.launch
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.ResponseBody import okhttp3.ResponseBody
import okio.* import okio.*
import java.util.concurrent.Executors import java.util.concurrent.Executors
@UseExperimental(ExperimentalCoroutinesApi::class)
class DownloadWorker(context: Context) : ContextWrapper(context) { class DownloadWorker(context: Context) : ContextWrapper(context) {
val preferences = PreferenceManager.getDefaultSharedPreferences(context)
//region ProgressListener
interface ProgressListener { interface ProgressListener {
fun update(bytesRead : Long, contentLength: Long, done: Boolean) fun update(tag: Any?, bytesRead : Long, contentLength: Long, done: Boolean)
} }
//region ProgressResponseBody
class ProgressResponseBody( class ProgressResponseBody(
val tag: Any?,
val responseBody: ResponseBody, val responseBody: ResponseBody,
val progressListener : ProgressListener val progressListener : ProgressListener
) : ResponseBody() { ) : ResponseBody() {
@@ -61,7 +63,7 @@ class DownloadWorker(context: Context) : ContextWrapper(context) {
val bytesRead = super.read(sink, byteCount) val bytesRead = super.read(sink, byteCount)
totalBytesRead += if (bytesRead == -1L) 0L else bytesRead totalBytesRead += if (bytesRead == -1L) 0L else bytesRead
progressListener.update(totalBytesRead, responseBody.contentLength(), bytesRead == -1L) progressListener.update(tag, totalBytesRead, responseBody.contentLength(), bytesRead == -1L)
return bytesRead return bytesRead
} }
@@ -71,28 +73,47 @@ class DownloadWorker(context: Context) : ContextWrapper(context) {
//endregion //endregion
val queue = Channel<Int>() val queue = Channel<Int>()
val worker = Executors.newFixedThreadPool(4).asCoroutineDispatcher() val progress = mutableMapOf<String, Double>()
val worker = Executors.newCachedThreadPool().asCoroutineDispatcher()
val progressListener = object: ProgressListener { val progressListener = object: ProgressListener {
override fun update(bytesRead: Long, contentLength: Long, done: Boolean) { override fun update(tag: Any?, bytesRead: Long, contentLength: Long, done: Boolean) {
} }
} }
val client = OkHttpClient.Builder() val client = OkHttpClient.Builder()
.addNetworkInterceptor { chain -> .addNetworkInterceptor { chain ->
chain.proceed(chain.request()).let { originalResponse -> val request = chain.request()
originalResponse.newBuilder() var response = chain.proceed(request)
.body(ProgressResponseBody(originalResponse.body!!, progressListener))
.build() var retry = preferences.getInt("retry", 3)
while (!response.isSuccessful && retry > 0) {
response = chain.proceed(request)
retry--
} }
response.newBuilder()
.body(ProgressResponseBody(request.tag(), response.body!!, progressListener))
.build()
}.build() }.build()
init { init {
CoroutineScope(Dispatchers.IO).launch { val maxThread = preferences.getInt("max_thread", 4)
while (true) {
CoroutineScope(Dispatchers.Unconfined).launch {
while (!(queue.isEmpty && queue.isClosedForReceive)) {
val lowQuality = preferences.getBoolean("low_quality", false)
val galleryID = queue.receive() val galleryID = queue.receive()
val reader = Cache(context).getReaders(galleryID) launch(Dispatchers.IO) {
val reader = Cache(context).getReader(galleryID) ?: return@launch
reader.galleryInfo.forEachIndexed { index, galleryInfo ->
when(reader.code) {
}
}
}
} }
} }
} }

View File

@@ -24,7 +24,18 @@ import xyz.quaver.hitomi.Reader
@Serializable @Serializable
data class Metadata( data class Metadata(
var thumbnail: String? = null, val thumbnail: String? = null,
var galleryBlock: GalleryBlock? = null, val galleryBlock: GalleryBlock? = null,
var reader: MutableList<Reader>? = null val readers: List<Reader>? = null
) ) {
constructor(
metadata: Metadata?,
thumbnail: String? = null,
galleryBlock: GalleryBlock? = null,
readers: List<Reader>? = null
) : this(
thumbnail ?: metadata?.thumbnail,
galleryBlock ?: metadata?.galleryBlock,
readers ?: metadata?.readers
)
}