Compare commits

..

3 Commits

Author SHA1 Message Date
tom5079
e498efc493 Fixed Download location dialog keep popping up 2022-01-08 10:13:20 +09:00
tom5079
74bbc71741 Fixed thumbnail not loading 2022-01-08 10:06:45 +09:00
tom5079
502b4890e3 5.2.8 Fix for loading not finishing 2022-01-07 18:47:07 +09:00
7 changed files with 72 additions and 69 deletions

View File

@@ -7,11 +7,11 @@
<deviceKey>
<Key>
<type value="VIRTUAL_DEVICE_PATH" />
<value value="$USER_HOME$/.android/avd/Pixel_2_API_30.avd" />
<value value="$USER_HOME$/.android/avd/Pixel_2_API_31.avd" />
</Key>
</deviceKey>
</Target>
</targetSelectedWithDropDown>
<timeTargetWasSelectedWithDropDown value="2022-01-04T14:31:24.587053Z" />
<timeTargetWasSelectedWithDropDown value="2022-01-08T00:45:48.713777Z" />
</component>
</project>

View File

@@ -2,7 +2,7 @@
*Pupil, Hitomi.la viewer for Android*
![](https://img.shields.io/github/downloads/tom5079/Pupil/total)
[![](https://img.shields.io/github/downloads/tom5079/Pupil/5.2.7/Pupil-v5.2.7.apk?color=%234fc3f7&label=DOWNLOAD%20APP&style=for-the-badge)](https://github.com/tom5079/Pupil/releases/download/5.2.7/Pupil-v5.2.7.apk)
[![](https://img.shields.io/github/downloads/tom5079/Pupil/5.2.8/Pupil-v5.2.8.apk?color=%234fc3f7&label=DOWNLOAD%20APP&style=for-the-badge)](https://github.com/tom5079/Pupil/releases/download/5.2.8/Pupil-v5.2.8.apk)
[![](https://discordapp.com/api/guilds/610452916612104194/embed.png?style=banner2)](https://discord.gg/Stj4b5v)
# Features

View File

@@ -38,7 +38,7 @@ android {
minSdkVersion 16
targetSdkVersion 31
versionCode 69
versionName "5.2.8-BETA01"
versionName "5.2.8"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true
}

View File

@@ -12,7 +12,7 @@
"filters": [],
"attributes": [],
"versionCode": 69,
"versionName": "5.2.8-BETA01",
"versionName": "5.2.8",
"outputFile": "app-release.apk"
}
],

View File

@@ -39,7 +39,6 @@ import com.github.piasy.biv.loader.fresco.FrescoImageLoader
import com.google.android.gms.common.GooglePlayServicesNotAvailableException
import com.google.android.gms.common.GooglePlayServicesRepairableException
import com.google.android.gms.security.ProviderInstaller
import com.google.android.material.snackbar.Snackbar
import com.google.firebase.crashlytics.FirebaseCrashlytics
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.BufferOverflow
@@ -47,13 +46,12 @@ import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.asSharedFlow
import okhttp3.*
import xyz.quaver.io.FileX
import xyz.quaver.pupil.hitomi.evaluations
import xyz.quaver.pupil.hitomi.evaluationContext
import xyz.quaver.pupil.types.Tag
import xyz.quaver.pupil.util.*
import java.io.File
import java.net.URL
import java.util.*
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
import kotlin.reflect.KClass
@@ -96,31 +94,29 @@ fun reloadWebView() {
if (reloadJob?.isActive == true) return
reloadJob = CoroutineScope(Dispatchers.IO).launch {
if (evaluations.isEmpty()) {
webViewReady = false
webViewFailed = false
webViewReady = false
webViewFailed = false
while (evaluations.isNotEmpty()) yield()
evaluationContext.cancelChildren()
runCatching {
URL(
if (isDebugBuild)
"https://tom5079.github.io/Pupil/hitomi-dev.html"
else
"https://tom5079.github.io/Pupil/hitomi.html"
).readText()
}.onFailure {
webViewFailed = true
}.getOrNull()?.let { html ->
launch(Dispatchers.Main) {
webView.loadDataWithBaseURL(
"https://hitomi.la/",
html,
"text/html",
null,
null
)
}
runCatching {
URL(
if (isDebugBuild)
"https://tom5079.github.io/Pupil/hitomi-dev.html"
else
"https://tom5079.github.io/Pupil/hitomi.html"
).readText()
}.onFailure {
webViewFailed = true
}.getOrNull()?.let { html ->
launch(Dispatchers.Main) {
webView.loadDataWithBaseURL(
"https://hitomi.la/",
html,
"text/html",
null,
null
)
}
}
}
@@ -152,7 +148,7 @@ fun reloadWhenFailedOrUpdate() = CoroutineScope(Dispatchers.Default).launch {
}
var isDebugBuild: Boolean = false
private lateinit var userAgent: String
lateinit var userAgent: String
class Pupil : Application() {
@@ -191,7 +187,6 @@ class Pupil : Application() {
"onReceivedError: ${error?.description}"
)
}
webViewFailed = true
}
}
@@ -257,10 +252,11 @@ class Pupil : Application() {
try {
Preferences.get<String>("download_folder").also {
contentResolver.takePersistableUriPermission(
Uri.parse(it),
Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
)
if (it.startsWith("content://"))
contentResolver.takePersistableUriPermission(
Uri.parse(it),
Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
)
if (!FileX(this, it).canWrite())
throw Exception()

View File

@@ -16,6 +16,7 @@
package xyz.quaver.pupil.hitomi
import android.util.Log
import android.webkit.WebView
import android.widget.Toast
import com.google.common.collect.ConcurrentHashMultiset
@@ -37,21 +38,25 @@ import kotlin.coroutines.suspendCoroutine
const val protocol = "https:"
val evaluations = Collections.newSetFromMap<String>(ConcurrentHashMap())
val evaluationContext = Dispatchers.Main + Job()
suspend fun WebView.evaluate(script: String): String = withContext(Dispatchers.Main) {
val result: String = withTimeout(10000) {
while (webViewFailed || !webViewReady) yield()
suspend fun WebView.evaluate(script: String): String = coroutineScope {
var result: String? = null
val uid = UUID.randomUUID().toString()
while (result == null) {
try {
result = withContext(evaluationContext) {
while (webViewFailed || !webViewReady) yield()
evaluations.add(uid)
suspendCoroutine { continuation ->
evaluateJavascript(script) {
continuation.resume(it)
}
}
suspendCoroutine { continuation ->
evaluateJavascript(script) {
evaluations.remove(uid)
continuation.resume(it)
}
} catch (e: CancellationException) {
continue
}
}
@@ -59,26 +64,36 @@ suspend fun WebView.evaluate(script: String): String = withContext(Dispatchers.M
}
@OptIn(ExperimentalCoroutinesApi::class)
suspend fun WebView.evaluatePromise(script: String, then: String = ".then(result => Callback.onResult(%uid, JSON.stringify(result))).catch(err => Callback.onError(%uid, JSON.stringify(error)))"): String? = withContext(Dispatchers.Main) {
val flow: Flow<Pair<String, String?>> = withTimeout(10000) {
while (webViewFailed || !webViewReady) yield()
suspend fun WebView.evaluatePromise(
script: String,
then: String = ".then(result => Callback.onResult(%uid, JSON.stringify(result))).catch(err => Callback.onError(%uid, JSON.stringify(error)))"
): String? = coroutineScope {
var result: String? = null
val uid = UUID.randomUUID().toString()
while (result == null) {
try {
result = withContext(evaluationContext) {
while (webViewFailed || !webViewReady) yield()
evaluations.add(uid)
val uid = UUID.randomUUID().toString()
evaluateJavascript((script+then).replace("%uid", "'$uid'"), null)
evaluateJavascript((script + then).replace("%uid", "'$uid'"), null)
webViewFlow.transformWhile { (currentUid, result) ->
if (currentUid == uid) {
evaluations.remove(uid)
emit(currentUid to result)
val flow: Flow<Pair<String, String?>> = webViewFlow.transformWhile { (currentUid, result) ->
if (currentUid == uid) {
emit(currentUid to result)
}
currentUid != uid
}
flow.first().second
}
currentUid != uid
} catch (e: CancellationException) {
continue
}
}
flow.first().second
result
}
@Suppress("EXPERIMENTAL_API_USAGE")
@@ -108,16 +123,6 @@ suspend fun urlFromUrlFromHash(galleryID: Int, image: GalleryFiles, dir: String?
""".trimIndent()
)
FirebaseCrashlytics.getInstance().log(
"""
url_from_url_from_hash(
${galleryID.toString().js},
${Json.encodeToString(image)},
${dir.js}, ${ext.js}, ${base.js}
)
""".trimIndent()
)
return Json.decodeFromString(result)
}

View File

@@ -40,6 +40,7 @@ import xyz.quaver.pupil.hitomi.GalleryBlock
import xyz.quaver.pupil.hitomi.GalleryInfo
import xyz.quaver.pupil.hitomi.getGalleryBlock
import xyz.quaver.pupil.hitomi.getGalleryInfo
import xyz.quaver.pupil.userAgent
import java.io.File
import java.io.IOException
import java.util.concurrent.ConcurrentHashMap
@@ -172,6 +173,7 @@ class Cache private constructor(context: Context, val galleryID: Int) : ContextW
kotlin.runCatching {
val request = Request.Builder()
.url(it)
.header("Referer", "https://hitomi.la/")
.build()
client.newCall(request).execute().also { if (it.code() != 200) throw IOException() }.body()?.use { it.bytes() }