Skip to content

Commit

Permalink
Merge pull request #68 from tom5079/dev
Browse files Browse the repository at this point in the history
Version 4.7
  • Loading branch information
tom5079 authored Feb 24, 2020
2 parents 4a8bff0 + 5fd35b4 commit 4f249c0
Show file tree
Hide file tree
Showing 8 changed files with 5,699 additions and 46 deletions.
4 changes: 2 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ android {
applicationId "xyz.quaver.pupil"
minSdkVersion 16
targetSdkVersion 29
versionCode 42
versionName "4.6"
versionCode 43
versionName "4.7"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
multiDexEnabled true
vectorDrawables.useSupportLibrary = true
Expand Down
2 changes: 1 addition & 1 deletion app/release/output.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
[{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":42,"versionName":"4.6","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release"},"path":"app-release.apk","properties":{}}]
[{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":43,"versionName":"4.7","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release"},"path":"app-release.apk","properties":{}}]
23 changes: 21 additions & 2 deletions app/src/main/java/xyz/quaver/pupil/adapters/ReaderAdapter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
package xyz.quaver.pupil.adapters

import android.content.Context
import android.graphics.BitmapFactory
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
Expand Down Expand Up @@ -119,20 +120,38 @@ class ReaderAdapter(private val context: Context,
holder.view.reader_index.text = (position+1).toString()

val images = Cache(context).getImage(galleryID, position)
val progress = DownloadWorker.getInstance(context).progress[galleryID]?.get(position)

if (progress?.isInfinite() == true && images != null) {
holder.view.reader_item_progressbar.visibility = View.INVISIBLE
holder.view.container.apply {
val options = BitmapFactory.Options().apply {
inJustDecodeBounds = true
}

BitmapFactory.decodeFile(images.canonicalPath, options)

maxWidth = options.outWidth
maxHeight = options.outHeight
}

if (images != null) {
glide
.load(images)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.skipMemoryCache(true)
.dontTransform()
.error(R.drawable.image_broken_variant)
.apply {
if (BuildConfig.CENSOR)
override(5, 8)
}
.into(holder.view.image)
} else {
val progress = DownloadWorker.getInstance(context).progress[galleryID]?.get(position)
holder.view.reader_item_progressbar.visibility = View.VISIBLE
holder.view.container.apply {
maxWidth = Integer.MAX_VALUE
maxHeight = Integer.MAX_VALUE
}

if (progress?.isNaN() == true) {
if (Fabric.isInitialized())
Expand Down
4 changes: 3 additions & 1 deletion app/src/main/java/xyz/quaver/pupil/ui/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -961,7 +961,9 @@ class MainActivity : AppCompatActivity() {
}
Mode.DOWNLOAD -> {
val downloads = getDownloadDirectory(this@MainActivity).listFiles()?.filter { file ->
file.isDirectory && (file.name.toIntOrNull() != null) && File(file, ".metadata").exists()
file.isDirectory && file.name.toIntOrNull() != null
}?.sortedByDescending {
it.lastModified()
}?.map {
it.name.toInt()
} ?: emptyList()
Expand Down
38 changes: 30 additions & 8 deletions app/src/main/java/xyz/quaver/pupil/util/download/Cache.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,23 +21,43 @@ package xyz.quaver.pupil.util.download
import android.content.Context
import android.content.ContextWrapper
import android.util.Base64
import android.util.SparseArray
import androidx.preference.PreferenceManager
import com.crashlytics.android.Crashlytics
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.withContext
import kotlinx.io.InputStream
import xyz.quaver.Code
import xyz.quaver.hitomi.GalleryBlock
import xyz.quaver.hitomi.Reader
import xyz.quaver.proxy
import xyz.quaver.pupil.util.getCachedGallery
import xyz.quaver.pupil.util.getDownloadDirectory
import xyz.quaver.pupil.util.json
import java.io.File
import java.io.FileOutputStream
import java.net.URL
import java.util.concurrent.locks.Lock
import java.util.concurrent.locks.ReentrantLock

class Cache(context: Context) : ContextWrapper(context) {

private val locks = SparseArray<Lock>()
private fun lock(galleryID: Int) {
synchronized(locks) {
if (locks.indexOfKey(galleryID) < 0)
locks.put(galleryID, ReentrantLock())
}

locks[galleryID].lock()
}

private fun unlock(galleryID: Int) {
locks[galleryID]?.unlock()
}

private val preference = PreferenceManager.getDefaultSharedPreferences(this)

// Search in this order
Expand Down Expand Up @@ -78,7 +98,9 @@ class Cache(context: Context) : ContextWrapper(context) {
withContext(Dispatchers.IO) {
val thumbnails = getGalleryBlock(galleryID)?.thumbnails
try {
Base64.encodeToString(URL(thumbnails?.firstOrNull()).readBytes(), Base64.DEFAULT)
Base64.encodeToString(URL(thumbnails?.firstOrNull()).openConnection(proxy).getInputStream().use {
it.readBytes()
}, Base64.DEFAULT)
} catch (e: Exception) {
null
}
Expand Down Expand Up @@ -212,16 +234,16 @@ class Cache(context: Context) : ContextWrapper(context) {
return null
}

fun putImage(galleryID: Int, name: String, data: ByteArray) {
val cache = File(getCachedGallery(galleryID), name).also {

fun putImage(galleryID: Int, index: Int, ext: String, data: InputStream) {
val cache = File(getCachedGallery(galleryID), "%05d.$ext".format(index)).also {
if (!it.exists())
it.createNewFile()
}

if (!Regex("""^[0-9]+.+$""").matches(name))
throw IllegalArgumentException("File name is not a number")

cache.writeBytes(data)
data.use {
it.copyTo(FileOutputStream(cache))
}
}

fun moveToDownload(galleryID: Int) {
Expand All @@ -231,7 +253,7 @@ class Cache(context: Context) : ContextWrapper(context) {
}
val download = File(getDownloadDirectory(this), galleryID.toString())

cache.copyRecursively(download, true)
cache.copyRecursively(download, true) { _, _ -> OnErrorAction.SKIP }
cache.deleteRecursively()
}

Expand Down
117 changes: 85 additions & 32 deletions app/src/main/java/xyz/quaver/pupil/util/download/DownloadWorker.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import android.content.Context
import android.content.ContextWrapper
import android.content.Intent
import android.content.SharedPreferences
import android.util.Log
import android.util.SparseArray
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
Expand All @@ -36,16 +37,18 @@ import okio.*
import xyz.quaver.Code
import xyz.quaver.hitomi.Reader
import xyz.quaver.hitomi.getReferer
import xyz.quaver.hitomi.urlFromUrlFromHash
import xyz.quaver.hitomi.imageUrlFromImage
import xyz.quaver.hiyobi.cookie
import xyz.quaver.hiyobi.createImgList
import xyz.quaver.hiyobi.user_agent
import xyz.quaver.proxy
import xyz.quaver.pupil.R
import xyz.quaver.pupil.ui.ReaderActivity
import java.io.File
import java.io.IOException
import java.util.concurrent.Executors
import java.util.concurrent.LinkedBlockingQueue
import java.util.concurrent.TimeUnit

@UseExperimental(ExperimentalCoroutinesApi::class)
class DownloadWorker private constructor(context: Context) : ContextWrapper(context) {
Expand Down Expand Up @@ -153,12 +156,14 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont
val response = chain.proceed(request)

response.newBuilder()
.body(ProgressResponseBody(request.tag(), response.body(), progressListener))
.build()
.body(ProgressResponseBody(request.tag(), response.body(), progressListener))
.build()
}
fun buildClient() =
OkHttpClient.Builder()
.addInterceptor(interceptor)
.connectTimeout(0, TimeUnit.SECONDS)
.readTimeout(0, TimeUnit.SECONDS)
.dispatcher(Dispatcher(Executors.newFixedThreadPool(4)))
.proxy(proxy)
.build()
Expand Down Expand Up @@ -211,10 +216,10 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont
when (reader.code) {
Code.HITOMI -> {
url(
urlFromUrlFromHash(
imageUrlFromImage(
galleryID,
reader.galleryInfo.files[index],
if (lowQuality) "webp" else null
lowQuality
)
)
addHeader("Referer", getReferer(galleryID))
Expand Down Expand Up @@ -252,7 +257,7 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont
val cache = Cache(this@DownloadWorker).getImages(galleryID)

progress.put(galleryID, reader.galleryInfo.files.indices.map { index ->
if (cache?.getOrNull(index) != null)
if (cache?.firstOrNull { it?.nameWithoutExtension?.toIntOrNull() == index } != null)
Float.POSITIVE_INFINITY
else
0F
Expand All @@ -279,6 +284,7 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont
for (i in reader.galleryInfo.files.indices) {
val callback = object : Callback {
override fun onFailure(call: Call, e: IOException) {
Log.i("PUPILD", "FAIL ${call.request().tag()} (${e.message})")
if (Fabric.isInitialized() && e.message != "Canceled")
Crashlytics.logException(e)

Expand All @@ -287,57 +293,95 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont

notify(galleryID)

if (isCompleted(galleryID)) {
with(Cache(this@DownloadWorker)) {
if (isDownloading(galleryID)) {
moveToDownload(galleryID)
setDownloading(galleryID, false)
CoroutineScope(Dispatchers.IO).launch {
if (isCompleted(galleryID) && clients.indexOfKey(galleryID) >= 0) {
clients.remove(galleryID)
with(Cache(this@DownloadWorker)) {
if (isDownloading(galleryID)) {
moveToDownload(galleryID)
setDownloading(galleryID, false)
}
}
}
clients.remove(galleryID)
}
}

override fun onResponse(call: Call, response: Response) {
response.body().use {
val res = it.bytes()
val ext =
call.request().url().encodedPath().split('.').last()
Log.i("PUPILD", "OK ${call.request().tag()}")

val ext = call.request().url().encodedPath().split('.').last()

Cache(this@DownloadWorker).putImage(galleryID, "%05d.%s".format(i, ext), res)
try {
response.body().use {
Cache(this@DownloadWorker).putImage(galleryID, i, ext, it.byteStream())
}
progress[galleryID]?.set(i, Float.POSITIVE_INFINITY)
}

notify(galleryID)
notify(galleryID)

CoroutineScope(Dispatchers.IO).launch {
if (isCompleted(galleryID) && clients.indexOfKey(galleryID) >= 0) {
clients.remove(galleryID)
with(Cache(this@DownloadWorker)) {
if (isDownloading(galleryID)) {
moveToDownload(galleryID)
setDownloading(galleryID, false)
}
}
}
}

Log.i("PUPILD", "SUCCESS ${call.request().tag()}")
} catch (e: Exception) {

progress[galleryID]?.set(i, Float.NaN)
exception[galleryID]?.set(i, e)

if (isCompleted(galleryID)) {
with(Cache(this@DownloadWorker)) {
if (isDownloading(galleryID)) {
moveToDownload(galleryID)
setDownloading(galleryID, false)
notify(galleryID)

CoroutineScope(Dispatchers.IO).launch {
if (isCompleted(galleryID) && clients.indexOfKey(galleryID) >= 0) {
clients.remove(galleryID)
with(Cache(this@DownloadWorker)) {
if (isDownloading(galleryID)) {
moveToDownload(galleryID)
setDownloading(galleryID, false)
}
}
}
}
clients.remove(galleryID)

File(Cache(this@DownloadWorker).getCachedGallery(galleryID), "%05d.$ext".format(i)).delete()

Log.i("PUPILD", "FAIL ON OK ${call.request().tag()} (${e.message})")
}
}
}

if (progress[galleryID]?.get(i)?.isFinite() == true)
if (progress[galleryID]?.get(i)?.isFinite() == true) {
queueDownload(galleryID, reader, i, callback)
Log.i("PUPILD", "$galleryID QUEUED $i")
} else {
Log.i("PUPILD", "$galleryID SKIPPED $i (${progress[galleryID]?.get(i)})")
}
}
}

private fun notify(galleryID: Int) {
val max = progress[galleryID]?.size ?: 0
val progress = progress[galleryID]?.count { !it.isFinite() } ?: 0

if (isCompleted(galleryID))
Log.i("PUPILD", "NOTIFY $galleryID ${isCompleted(galleryID)} $progress/$max")

if (isCompleted(galleryID)) {
notification[galleryID]
?.setContentText(getString(R.string.reader_notification_complete))
?.setSmallIcon(android.R.drawable.stat_sys_download_done)
?.setProgress(0, 0, false)
?.setOngoing(false)
else

notificationManager.cancel(galleryID)
} else
notification[galleryID]
?.setProgress(max, progress, false)
?.setContentText("$progress/$max")
Expand All @@ -354,7 +398,7 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont
}
val pendingIntent = TaskStackBuilder.create(this).run {
addNextIntentWithParentStack(intent)
getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT)
getPendingIntent(galleryID, PendingIntent.FLAG_UPDATE_CURRENT)
}

notification.put(galleryID, NotificationCompat.Builder(this, "download").apply {
Expand All @@ -369,18 +413,27 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont

private fun loop() = CoroutineScope(Dispatchers.Default).launch {
while (true) {
if (queue.isEmpty() || clients.size() > preferences.getInt("max_download", 4))
if (queue.isEmpty())
continue

val galleryID = queue.poll() ?: continue
val galleryID = queue.peek() ?: continue

if (clients.indexOfKey(galleryID) >= 0) // Gallery already downloading!
continue

initNotification(galleryID)
if (notification[galleryID] == null)
initNotification(galleryID)

if (Cache(this@DownloadWorker).isDownloading(galleryID))
notificationManager.notify(galleryID, notification[galleryID].build())

if (clients.size() >= preferences.getInt("max_download", 4))
continue

Log.i("PUPILD", "QUEUED $galleryID #${clients.size()+1}")

worker.put(galleryID, download(galleryID))
queue.poll()
}
}

Expand Down
Loading

0 comments on commit 4f249c0

Please sign in to comment.