Download added
This commit is contained in:
232
app/src/main/java/xyz/quaver/pupil/util/GalleryDownloader.kt
Normal file
232
app/src/main/java/xyz/quaver/pupil/util/GalleryDownloader.kt
Normal file
@@ -0,0 +1,232 @@
|
||||
package xyz.quaver.pupil.util
|
||||
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.ContextWrapper
|
||||
import android.content.Intent
|
||||
import android.util.SparseArray
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import androidx.core.app.TaskStackBuilder
|
||||
import androidx.preference.PreferenceManager
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.io.IOException
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.JsonConfiguration
|
||||
import kotlinx.serialization.list
|
||||
import xyz.quaver.hitomi.*
|
||||
import xyz.quaver.pupil.R
|
||||
import xyz.quaver.pupil.ReaderActivity
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.net.URL
|
||||
import javax.net.ssl.HttpsURLConnection
|
||||
|
||||
class GalleryDownloader(
|
||||
base: Context,
|
||||
private val galleryBlock: GalleryBlock
|
||||
) : ContextWrapper(base) {
|
||||
|
||||
var notify: Boolean = false
|
||||
set(value) {
|
||||
if (value) {
|
||||
field = true
|
||||
notificationManager.notify(galleryBlock.id, notificationBuilder.build())
|
||||
|
||||
if (downloadJob?.isActive != true)
|
||||
field = false
|
||||
} else {
|
||||
field = false
|
||||
}
|
||||
|
||||
onNotifyChangedHandler?.invoke(value)
|
||||
}
|
||||
|
||||
private val reader: Deferred<Reader>
|
||||
private var downloadJob: Job? = null
|
||||
|
||||
private lateinit var notificationBuilder: NotificationCompat.Builder
|
||||
private lateinit var notificationManager: NotificationManagerCompat
|
||||
|
||||
var onReaderLoadedHandler: ((Reader) -> Unit)? = null
|
||||
var onProgressHandler: ((Int) -> Unit)? = null
|
||||
var onDownloadedHandler: ((List<String>) -> Unit)? = null
|
||||
var onErrorHandler: (() -> Unit)? = null
|
||||
var onCompleteHandler: (() -> Unit)? = null
|
||||
var onNotifyChangedHandler: ((Boolean) -> Unit)? = null
|
||||
|
||||
companion object : SparseArray<GalleryDownloader>()
|
||||
|
||||
init {
|
||||
put(galleryBlock.id, this)
|
||||
|
||||
initNotification()
|
||||
|
||||
reader = CoroutineScope(Dispatchers.IO).async {
|
||||
val json = Json(JsonConfiguration.Stable)
|
||||
val serializer = ReaderItem.serializer().list
|
||||
val preference = PreferenceManager.getDefaultSharedPreferences(this@GalleryDownloader)
|
||||
val useHiyobi = preference.getBoolean("use_hiyobi", false)
|
||||
|
||||
//Check cache
|
||||
val cache = File(cacheDir, "imageCache/${galleryBlock.id}/reader.json")
|
||||
|
||||
if (cache.exists()) {
|
||||
val cached = json.parse(serializer, cache.readText())
|
||||
|
||||
if (cached.isNotEmpty())
|
||||
return@async cached
|
||||
}
|
||||
|
||||
//Cache doesn't exist. Load from internet
|
||||
val reader = when {
|
||||
useHiyobi -> {
|
||||
xyz.quaver.hiyobi.getReader(galleryBlock.id).let {
|
||||
when {
|
||||
it.isEmpty() -> getReader(galleryBlock.id)
|
||||
else -> it
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
getReader(galleryBlock.id)
|
||||
}
|
||||
}
|
||||
|
||||
//Could not retrieve reader
|
||||
if (reader.isEmpty())
|
||||
throw IOException("Can't retrieve Reader")
|
||||
|
||||
//Save cache
|
||||
if (!cache.parentFile.exists())
|
||||
cache.parentFile.mkdirs()
|
||||
|
||||
cache.writeText(json.stringify(serializer, reader))
|
||||
|
||||
reader
|
||||
}
|
||||
}
|
||||
|
||||
private fun webpUrlFromUrl(url: String) = url.replace("/galleries/", "/webp/") + ".webp"
|
||||
|
||||
fun start() {
|
||||
downloadJob = CoroutineScope(Dispatchers.Default).launch {
|
||||
val reader = reader.await()
|
||||
|
||||
val list = ArrayList<String>()
|
||||
|
||||
onReaderLoadedHandler?.invoke(reader)
|
||||
|
||||
notificationBuilder
|
||||
.setProgress(reader.size, 0, false)
|
||||
.setContentText("0/${reader.size}")
|
||||
|
||||
reader.chunked(4).forEachIndexed { chunkIndex, chunked ->
|
||||
chunked.mapIndexed { i, it ->
|
||||
val index = chunkIndex*4+i
|
||||
|
||||
onProgressHandler?.invoke(index)
|
||||
|
||||
notificationBuilder
|
||||
.setProgress(reader.size, index, false)
|
||||
.setContentText("$index/${reader.size}")
|
||||
|
||||
if (notify)
|
||||
notificationManager.notify(galleryBlock.id, notificationBuilder.build())
|
||||
|
||||
async(Dispatchers.IO) {
|
||||
val url = if (it.galleryInfo?.haswebp == 1) webpUrlFromUrl(it.url) else it.url
|
||||
|
||||
val name = "$index".padStart(4, '0')
|
||||
val ext = url.split('.').last()
|
||||
|
||||
val cache = File(cacheDir, "/imageCache/${galleryBlock.id}/images/$name.$ext")
|
||||
|
||||
if (!cache.exists())
|
||||
try {
|
||||
with(URL(url).openConnection() as HttpsURLConnection) {
|
||||
setRequestProperty("Referer", getReferer(galleryBlock.id))
|
||||
|
||||
if (!cache.parentFile.exists())
|
||||
cache.parentFile.mkdirs()
|
||||
|
||||
inputStream.copyTo(FileOutputStream(cache))
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
cache.delete()
|
||||
|
||||
onErrorHandler?.invoke()
|
||||
|
||||
notificationBuilder
|
||||
.setContentTitle(galleryBlock.title)
|
||||
.setContentText(getString(R.string.reader_notification_error))
|
||||
.setProgress(0, 0, false)
|
||||
|
||||
notificationManager.notify(galleryBlock.id, notificationBuilder.build())
|
||||
}
|
||||
|
||||
cache.absolutePath
|
||||
}
|
||||
}.forEach {
|
||||
list.add(it.await())
|
||||
onDownloadedHandler?.invoke(list)
|
||||
}
|
||||
}
|
||||
|
||||
onCompleteHandler?.invoke()
|
||||
|
||||
notificationBuilder
|
||||
.setContentTitle(galleryBlock.title)
|
||||
.setContentText(getString(R.string.reader_notification_complete))
|
||||
.setProgress(0, 0, false)
|
||||
|
||||
if (notify)
|
||||
notificationManager.notify(galleryBlock.id, notificationBuilder.build())
|
||||
|
||||
notify = false
|
||||
|
||||
remove(galleryBlock.id)
|
||||
}
|
||||
}
|
||||
|
||||
fun cancel() {
|
||||
downloadJob?.cancel()
|
||||
|
||||
remove(galleryBlock.id)
|
||||
}
|
||||
|
||||
fun invokeOnReaderLoaded() {
|
||||
CoroutineScope(Dispatchers.Default).launch {
|
||||
onReaderLoadedHandler?.invoke(reader.await())
|
||||
}
|
||||
}
|
||||
|
||||
fun clearNotification() {
|
||||
notificationManager.cancel(galleryBlock.id)
|
||||
}
|
||||
|
||||
fun invokeOnNotifyChanged() {
|
||||
onNotifyChangedHandler?.invoke(notify)
|
||||
}
|
||||
|
||||
private fun initNotification() {
|
||||
val intent = Intent(this, ReaderActivity::class.java).apply {
|
||||
putExtra("galleryblock", Json(JsonConfiguration.Stable).stringify(GalleryBlock.serializer(), galleryBlock))
|
||||
}
|
||||
val pendingIntent = TaskStackBuilder.create(this).run {
|
||||
addNextIntentWithParentStack(intent)
|
||||
getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
}
|
||||
|
||||
notificationBuilder = NotificationCompat.Builder(this, "download").apply {
|
||||
setContentTitle(galleryBlock.title)
|
||||
setContentText(getString(R.string.reader_notification_text))
|
||||
setSmallIcon(R.drawable.ic_download)
|
||||
setContentIntent(pendingIntent)
|
||||
setProgress(0, 0, true)
|
||||
priority = NotificationCompat.PRIORITY_LOW
|
||||
}
|
||||
notificationManager = NotificationManagerCompat.from(this)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
package xyz.quaver.pupil.util
|
||||
|
||||
import kotlinx.io.IOException
|
||||
import kotlinx.serialization.ImplicitReflectionSerializer
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.JsonConfiguration
|
||||
@@ -8,7 +7,6 @@ import kotlinx.serialization.parseList
|
||||
import kotlinx.serialization.stringify
|
||||
import java.io.File
|
||||
|
||||
|
||||
class Histories(private val file: File) : ArrayList<Int>() {
|
||||
|
||||
init {
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
package xyz.quaver.pupil.util
|
||||
|
||||
Reference in New Issue
Block a user