(Almost) Full OkHTTP implementation

This commit is contained in:
tom5079
2020-08-28 22:43:47 +09:00
parent ece127e982
commit fdd9b02388
24 changed files with 307 additions and 97 deletions

View File

@@ -51,5 +51,10 @@
<option name="name" value="maven4" />
<option name="url" value="https://maven.fabric.io/public" />
</remote-repository>
<remote-repository>
<option name="id" value="MavenLocal" />
<option name="name" value="MavenLocal" />
<option name="url" value="file:/$USER_HOME$/.m2/repository/" />
</remote-repository>
</component>
</project>

View File

@@ -48,6 +48,7 @@ android {
}
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_1_8.toString()
freeCompilerArgs += '-Xuse-experimental=kotlin.Experimental'
}
compileOptions {
@@ -68,7 +69,6 @@ dependencies {
implementation 'androidx.preference:preference:1.1.1'
implementation 'androidx.gridlayout:gridlayout:1.0.0'
implementation "androidx.biometric:biometric:1.0.1"
implementation 'androidx.multidex:multidex:2.0.1'
implementation 'androidx.fragment:fragment-ktx:1.2.5'
implementation "com.daimajia.swipelayout:library:1.2.0@aar"
implementation 'com.google.android.material:material:1.3.0-alpha02'
@@ -78,8 +78,12 @@ dependencies {
implementation 'com.google.firebase:firebase-perf:19.0.8'
implementation 'com.github.arimorty:floatingsearchview:2.1.1'
implementation 'com.github.clans:fab:1.6.4'
//noinspection GradleDependency
implementation 'com.squareup.okhttp3:okhttp:3.12.12'
implementation 'com.github.bumptech.glide:glide:4.11.0'
implementation "com.github.bumptech.glide:okhttp3-integration:4.11.0"
implementation ("com.github.bumptech.glide:okhttp3-integration:4.11.0") {
transitive = false
}
implementation 'com.github.bumptech.glide:annotations:4.11.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
kapt 'com.github.bumptech.glide:compiler:4.11.0'
@@ -92,7 +96,7 @@ dependencies {
implementation 'com.andrognito.patternlockview:patternlockview:1.0.0'
//implementation 'com.andrognito.pinlockview:pinlockview:2.1.0'
implementation "ru.noties.markwon:core:3.1.0"
implementation ("xyz.quaver:libpupil:1.0") {
implementation ("xyz.quaver:libpupil:1.1") {
exclude group: 'org.jetbrains.kotlinx', module: 'kotlinx-serialization-core-jvm'
}
testImplementation 'junit:junit:4.13'

View File

@@ -37,8 +37,11 @@
</provider>
<service android:name=".services.DownloadService"
android:exported="false"/>
<receiver
android:name=".BroadcastReciever"
android:name=".reciever.UpdateBroadcastReciever"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.DOWNLOAD_COMPLETE" />

View File

@@ -18,6 +18,7 @@
package xyz.quaver.pupil
import android.app.Application
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
@@ -25,7 +26,6 @@ import android.content.Context
import android.os.Build
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.content.ContextCompat
import androidx.multidex.MultiDexApplication
import androidx.preference.PreferenceManager
import com.google.android.gms.common.GooglePlayServicesNotAvailableException
import com.google.android.gms.common.GooglePlayServicesRepairableException
@@ -35,16 +35,37 @@ import com.google.firebase.crashlytics.FirebaseCrashlytics
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import xyz.quaver.proxy
import okhttp3.Dispatcher
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.Response
import xyz.quaver.pupil.util.GalleryList
import xyz.quaver.pupil.util.getProxy
import xyz.quaver.pupil.util.getProxyInfo
import xyz.quaver.setClient
import java.io.File
import java.util.*
import java.util.concurrent.TimeUnit
import kotlin.reflect.KClass
class Pupil : MultiDexApplication() {
typealias PupilInterceptor = (Interceptor.Chain) -> Response
lateinit var histories: GalleryList
private set
lateinit var favorites: GalleryList
private set
val interceptors = mutableMapOf<KClass<out Any>, PupilInterceptor>()
lateinit var clientBuilder: OkHttpClient.Builder
var clientHolder: OkHttpClient? = null
val client: OkHttpClient
get() = clientHolder ?: clientBuilder.build().also {
clientHolder = it
setClient(it)
}
class Pupil : Application() {
init {
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
@@ -63,7 +84,19 @@ class Pupil : MultiDexApplication() {
FirebaseCrashlytics.getInstance().setUserId(userID)
proxy = getProxy(this)
val proxyInfo = getProxyInfo(this)
clientBuilder = OkHttpClient.Builder()
.connectTimeout(0, TimeUnit.SECONDS)
.readTimeout(0, TimeUnit.SECONDS)
.proxy(proxyInfo.proxy())
.proxyAuthenticator(proxyInfo.authenticator())
.addInterceptor { chain ->
val request = chain.request()
val tag = request.tag() ?: return@addInterceptor chain.proceed(request)
interceptors[tag::class]?.invoke(chain) ?: chain.proceed(request)
}
try {
preference.getString("dl_location", null).also {
@@ -112,6 +145,13 @@ class Pupil : MultiDexApplication() {
lockscreenVisibility = Notification.VISIBILITY_SECRET
})
manager.createNotificationChannel(NotificationChannel("downloader", getString(R.string.channel_downloader), NotificationManager.IMPORTANCE_LOW).apply {
description = getString(R.string.channel_downloader_description)
enableLights(false)
enableVibration(false)
lockscreenVisibility = Notification.VISIBILITY_SECRET
})
manager.createNotificationChannel(NotificationChannel("update", getString(R.string.channel_update), NotificationManager.IMPORTANCE_HIGH).apply {
description = getString(R.string.channel_update_description)
enableLights(true)
@@ -127,7 +167,6 @@ class Pupil : MultiDexApplication() {
})
}
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
AppCompatDelegate.setDefaultNightMode(when (preference.getBoolean("dark_mode", false)) {
true -> AppCompatDelegate.MODE_NIGHT_YES
false -> AppCompatDelegate.MODE_NIGHT_NO

View File

@@ -35,7 +35,7 @@ class PupilGlideModule : AppGlideModule() {
registry.append(
GlideUrl::class.java,
InputStream::class.java,
OkHttpUrlLoader.Factory(DownloadWorker.getInstance(context).client)
OkHttpUrlLoader.Factory(client)
)
}

View File

@@ -52,6 +52,7 @@ import xyz.quaver.hitomi.getReader
import xyz.quaver.pupil.BuildConfig
import xyz.quaver.pupil.Pupil
import xyz.quaver.pupil.R
import xyz.quaver.pupil.favorites
import xyz.quaver.pupil.types.Tag
import xyz.quaver.pupil.util.GalleryList
import xyz.quaver.pupil.util.download.Cache
@@ -68,8 +69,6 @@ class GalleryBlockAdapter(private val glide: RequestManager, private val galleri
PREV
}
private lateinit var favorites: GalleryList
val timer = Timer()
var isThin = false
@@ -257,9 +256,6 @@ class GalleryBlockAdapter(private val glide: RequestManager, private val galleri
}
}
if (!::favorites.isInitialized)
favorites = (context.applicationContext as Pupil).favorites
with(galleryblock_favorite) {
setImageResource(if (favorites.contains(galleryBlock.id)) R.drawable.ic_star_filled else R.drawable.ic_star_empty)
setOnClickListener {

View File

@@ -16,7 +16,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package xyz.quaver.pupil
package xyz.quaver.pupil.reciever
import android.app.DownloadManager
import android.app.PendingIntent
@@ -29,15 +29,10 @@ import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.FileProvider
import androidx.preference.PreferenceManager
import xyz.quaver.pupil.R
import java.io.File
class BroadcastReciever : BroadcastReceiver() {
companion object {
const val ACTION_CANCEL_IMPORT = "ACTION_CANCEL_IMPORT"
const val EXTRA_IMPORT_NOTIFICATION_ID = "EXTRA_IMPORT_NOTIFICATION_ID"
}
class UpdateBroadcastReciever : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
context ?: return

View File

@@ -0,0 +1,155 @@
/*
* 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.services
import android.app.Service
import android.content.Context
import android.content.ContextWrapper
import android.content.Intent
import android.os.Binder
import android.os.IBinder
import android.util.SparseArray
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import okhttp3.Interceptor
import okhttp3.ResponseBody
import okio.*
import xyz.quaver.pupil.R
private typealias ProgressListener = (Any?, Long, Long, Boolean) -> Unit
class Cache(context: Context) : ContextWrapper(context) {
}
class DownloadService : Service() {
//region Notification
private val notificationManager by lazy {
NotificationManagerCompat.from(this)
}
private val serviceNotification by lazy {
NotificationCompat.Builder(this, "downloader")
.setContentTitle(getString(R.string.downloader_running))
.setProgress(0, 0, false)
.setSmallIcon(R.drawable.ic_notification)
.setOngoing(true)
}
//endregion
//region ProgressListener
@Suppress("UNCHECKED_CAST")
private val progressListener: ProgressListener = listener@{ tag, bytesRead, contentLength, done ->
val (galleryID, index) = (tag as? Pair<Int, Int>) ?: return@listener
if (!done && progress[galleryID]?.get(index)?.isFinite() == true)
progress[galleryID]?.set(index, bytesRead * 100F / contentLength)
}
private class ProgressResponseBody(
val tag: Any?,
val responseBody: ResponseBody,
val progressListener : ProgressListener
) : ResponseBody() {
private var bufferedSource : BufferedSource? = null
override fun contentLength() = responseBody.contentLength()
override fun contentType() = responseBody.contentType()
override fun source(): BufferedSource {
if (bufferedSource == null)
bufferedSource = Okio.buffer(source(responseBody.source()))
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.invoke(tag, totalBytesRead, responseBody.contentLength(), bytesRead == -1L)
return bytesRead
}
}
}
val interceptor = Interceptor { chain ->
val request = chain.request()
var response = chain.proceed(request)
var retry = 5
while (!response.isSuccessful && retry > 0) {
response = chain.proceed(request)
retry--
}
response.newBuilder()
.body(response.body()?.let {
ProgressResponseBody(request.tag(), it, progressListener)
}).build()
}
//endregion
/**
* KEY
* primary galleryID
* secondary index
* PRIMARY VALUE
* MutableList -> Download in progress
* null -> Loading / Gallery doesn't exist
* SECONDARY VALUE
* 0 <= value < 100 -> Download in progress
* Float.POSITIVE_INFINITY -> Download completed
*/
val progress = SparseArray<MutableList<Float>?>()
override fun onCreate() {
startForeground(R.id.downloader_notification_id, serviceNotification.build())
}
override fun onDestroy() {
}
inner class Binder : android.os.Binder() {
val service = this@DownloadService
}
private val binder = Binder()
override fun onBind(p0: Intent?) = binder
fun load(galleryID: Int) {
}
fun download(galleryID: Int) = CoroutineScope(Dispatchers.IO).launch {
}
}

View File

@@ -22,7 +22,9 @@ import android.annotation.SuppressLint
import android.app.Activity
import android.content.Intent
import android.graphics.drawable.Animatable
import android.net.Proxy
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.text.*
import android.text.style.AlignmentSpan
@@ -59,9 +61,11 @@ import xyz.quaver.hitomi.GalleryBlock
import xyz.quaver.hitomi.doSearch
import xyz.quaver.hitomi.getGalleryIDsFromNozomi
import xyz.quaver.hitomi.getSuggestionsForQuery
import xyz.quaver.pupil.Pupil
import xyz.quaver.pupil.R
import xyz.quaver.pupil.adapters.GalleryBlockAdapter
import xyz.quaver.pupil.favorites
import xyz.quaver.pupil.histories
import xyz.quaver.pupil.services.DownloadService
import xyz.quaver.pupil.types.TagSuggestion
import xyz.quaver.pupil.types.Tags
import xyz.quaver.pupil.ui.dialog.GalleryDialog
@@ -110,9 +114,6 @@ class MainActivity : AppCompatActivity() {
private var loadingJob: Job? = null
private var currentPage = 0
private lateinit var histories: GalleryList
private lateinit var favorites: GalleryList
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -147,11 +148,6 @@ class MainActivity : AppCompatActivity() {
}
}
with(application as Pupil) {
this@MainActivity.histories = histories
this@MainActivity.favorites = favorites
}
if (intent.action == Intent.ACTION_VIEW) {
intent.dataString?.let { url ->
restore(favorites, url,
@@ -166,6 +162,15 @@ class MainActivity : AppCompatActivity() {
setContentView(R.layout.activity_main)
Intent(this, DownloadService::class.java).let {
when {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ->
startForegroundService(it)
else ->
startService(it)
}
}
checkUpdate(this)
initView()

View File

@@ -46,6 +46,8 @@ import xyz.quaver.Code
import xyz.quaver.pupil.Pupil
import xyz.quaver.pupil.R
import xyz.quaver.pupil.adapters.ReaderAdapter
import xyz.quaver.pupil.favorites
import xyz.quaver.pupil.histories
import xyz.quaver.pupil.util.GalleryList
import xyz.quaver.pupil.util.download.Cache
import xyz.quaver.pupil.util.download.DownloadWorker
@@ -78,16 +80,12 @@ class ReaderActivity : AppCompatActivity() {
private var menu: Menu? = null
private lateinit var favorites: GalleryList
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
title = getString(R.string.reader_loading)
supportActionBar?.setDisplayHomeAsUpEnabled(false)
favorites = (application as Pupil).favorites
window.setFlags(
WindowManager.LayoutParams.FLAG_SECURE,
WindowManager.LayoutParams.FLAG_SECURE)
@@ -96,7 +94,7 @@ class ReaderActivity : AppCompatActivity() {
handleIntent(intent)
(application as Pupil).histories.add(galleryID)
histories.add(galleryID)
FirebaseCrashlytics.getInstance().setCustomKey("GalleryID", galleryID)
if (galleryID == 0) {

View File

@@ -35,6 +35,7 @@ import kotlinx.serialization.json.Json
import net.rdrei.android.dirchooser.DirectoryChooserActivity
import xyz.quaver.pupil.Pupil
import xyz.quaver.pupil.R
import xyz.quaver.pupil.favorites
import xyz.quaver.pupil.ui.fragment.LockSettingsFragment
import xyz.quaver.pupil.ui.fragment.SettingsFragment
import xyz.quaver.pupil.util.*
@@ -100,7 +101,7 @@ class SettingsActivity : AppCompatActivity() {
inputStream.readBytes().toString(Charset.defaultCharset())
}
(application as Pupil).favorites.addAll(Json.decodeFromString<List<Int>>(str).also {
favorites.addAll(Json.decodeFromString<List<Int>>(str).also {
Snackbar.make(
window.decorView,
getString(R.string.settings_restore_success, it.size),

View File

@@ -48,6 +48,7 @@ import xyz.quaver.pupil.Pupil
import xyz.quaver.pupil.R
import xyz.quaver.pupil.adapters.GalleryBlockAdapter
import xyz.quaver.pupil.adapters.ThumbnailPageAdapter
import xyz.quaver.pupil.histories
import xyz.quaver.pupil.types.Tag
import xyz.quaver.pupil.ui.ReaderActivity
import xyz.quaver.pupil.util.ItemClickSupport
@@ -81,7 +82,7 @@ class GalleryDialog(context: Context, private val glide: RequestManager, private
context.startActivity(Intent(context, ReaderActivity::class.java).apply {
putExtra("galleryID", galleryID)
})
(context.applicationContext as Pupil).histories.add(galleryID)
histories.add(galleryID)
}
}
@@ -264,7 +265,7 @@ class GalleryDialog(context: Context, private val glide: RequestManager, private
context.startActivity(Intent(context, ReaderActivity::class.java).apply {
putExtra("galleryID", galleries[position].id)
})
(context.applicationContext as Pupil).histories.add(galleries[position].id)
histories.add(galleries[position].id)
}
onItemLongClickListener = { _, position, _ ->
GalleryDialog(

View File

@@ -31,8 +31,10 @@ import androidx.preference.PreferenceManager
import kotlinx.android.synthetic.main.dialog_proxy.view.*
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import xyz.quaver.proxy
import xyz.quaver.pupil.R
import xyz.quaver.pupil.client
import xyz.quaver.pupil.clientBuilder
import xyz.quaver.pupil.clientHolder
import xyz.quaver.pupil.util.ProxyInfo
import xyz.quaver.pupil.util.getProxyInfo
import java.net.Proxy
@@ -117,12 +119,15 @@ class ProxyDialog(context: Context) : Dialog(context) {
}
ProxyInfo(type, addr, port, username, password).let {
PreferenceManager.getDefaultSharedPreferences(context).edit().putString("proxy",
Json.encodeToString(it)
).apply()
proxy = it.proxy()
clientBuilder
.proxy(it.proxy())
.proxyAuthenticator(it.authenticator())
clientHolder = null
client
}
dismiss()

View File

@@ -30,6 +30,8 @@ import com.google.android.material.snackbar.Snackbar
import okhttp3.*
import xyz.quaver.pupil.Pupil
import xyz.quaver.pupil.R
import xyz.quaver.pupil.client
import xyz.quaver.pupil.favorites
import xyz.quaver.pupil.util.restore
import java.io.File
import java.io.IOException
@@ -52,7 +54,7 @@ class ManageFavoritesFragment : PreferenceFragmentCompat() {
.build()
).build()
OkHttpClient().newCall(request).enqueue(object: Callback {
client.newCall(request).enqueue(object: Callback {
override fun onFailure(call: Call, e: IOException) {
val view = view ?: return
Snackbar.make(view, R.string.settings_backup_failed, Snackbar.LENGTH_LONG).show()
@@ -79,7 +81,6 @@ class ManageFavoritesFragment : PreferenceFragmentCompat() {
.setTitle(R.string.settings_restore_title)
.setView(editText)
.setPositiveButton(android.R.string.ok) { _, _ ->
val favorites = (activity?.application as? Pupil)?.favorites ?: return@setPositiveButton
restore(favorites, editText.text.toString(),
onFailure = onFailure@{
val view = view ?: return@onFailure

View File

@@ -40,6 +40,7 @@ import net.rdrei.android.dirchooser.DirectoryChooserActivity
import net.rdrei.android.dirchooser.DirectoryChooserConfig
import xyz.quaver.pupil.Pupil
import xyz.quaver.pupil.R
import xyz.quaver.pupil.histories
import xyz.quaver.pupil.ui.LockActivity
import xyz.quaver.pupil.ui.SettingsActivity
import xyz.quaver.pupil.ui.dialog.DefaultQueryDialog
@@ -143,8 +144,6 @@ class SettingsFragment :
}.show()
}
"clear_history" -> {
val histories = (requireContext().applicationContext as Pupil).histories
AlertDialog.Builder(requireContext()).apply {
setTitle(R.string.warning)
setMessage(R.string.settings_clear_history_alert_message)
@@ -220,10 +219,10 @@ class SettingsFragment :
when (key) {
"proxy" -> {
summary = getProxyInfo(requireContext()).type.name
summary = context?.let { getProxyInfo(it).type.name }
}
"dl_location" -> {
summary = getDownloadDirectory(requireContext()).canonicalPath
summary = context?.let { getDownloadDirectory(it).canonicalPath }
}
}
}
@@ -286,7 +285,6 @@ class SettingsFragment :
onPreferenceClickListener = this@SettingsFragment
}
"clear_history" -> {
val histories = (requireActivity().application as Pupil).histories
summary = getString(R.string.settings_clear_history_summary, histories.size)
onPreferenceClickListener = this@SettingsFragment

View File

@@ -28,14 +28,13 @@ import kotlinx.coroutines.*
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import okhttp3.Dispatcher
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.isParentOf
import xyz.quaver.readBytes
import java.io.BufferedInputStream
import java.io.File
import java.io.FileOutputStream
@@ -91,11 +90,12 @@ class Cache(context: Context) : ContextWrapper(context) {
@Suppress("BlockingMethodInNonBlockingContext")
val thumbnail = if (metadata?.thumbnail == null)
withContext(Dispatchers.IO) {
val thumbnails = getGalleryBlock(galleryID)?.thumbnails
val thumbnail = getGalleryBlock(galleryID)?.thumbnails?.firstOrNull() ?: return@withContext null
try {
Base64.encodeToString(URL(thumbnails?.firstOrNull()).openConnection(proxy).getInputStream().use {
it.readBytes()
}, Base64.DEFAULT)
val data = URL(thumbnail).readBytes().apply {
if (isEmpty()) return@withContext null
}
Base64.encodeToString(data, Base64.DEFAULT)
} catch (e: Exception) {
null
}

View File

@@ -40,13 +40,13 @@ 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.client
import xyz.quaver.pupil.interceptors
import xyz.quaver.pupil.ui.ReaderActivity
import java.io.File
import java.io.IOException
import java.util.concurrent.LinkedBlockingQueue
import java.util.concurrent.TimeUnit
@OptIn(ExperimentalCoroutinesApi::class)
class DownloadWorker private constructor(context: Context) : ContextWrapper(context) {
@@ -86,7 +86,6 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont
}
private fun source(source: Source) = object: ForwardingSource(source) {
var totalBytesRead = 0L
override fun read(sink: Buffer, byteCount: Long): Long {
@@ -100,6 +99,24 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont
}
}
init {
interceptors[Pair::class] = { chain ->
val request = chain.request()
var response = chain.proceed(request)
var retry = 5
while (!response.isSuccessful && retry > 0) {
response = chain.proceed(request)
retry--
}
response.newBuilder()
.body(response.body()?.let {
ProgressResponseBody(request.tag(), it, progressListener)
}).build()
}
}
//endregion
//region Singleton
@@ -135,34 +152,6 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont
private val loop = loop()
private val worker = SparseArray<Job?>()
val interceptor = Interceptor { chain ->
val request = chain.request()
var response = chain.proceed(request)
var retry = 5
while (!response.isSuccessful && retry > 0) {
response = chain.proceed(request)
retry--
}
response.newBuilder()
.body(response.body()?.let {
ProgressResponseBody(request.tag(), it, progressListener)
}).build()
}
val client : OkHttpClient =
OkHttpClient.Builder()
.connectTimeout(0, TimeUnit.SECONDS)
.addInterceptor(interceptor)
.readTimeout(0, TimeUnit.SECONDS)
.dispatcher(Dispatcher().apply {
maxRequests = 4
maxRequestsPerHost = 4
})
.proxy(proxy)
.build()
fun stop() {
queue.clear()
@@ -300,8 +289,8 @@ class DownloadWorker private constructor(context: Context) : ContextWrapper(cont
val ext = call.request().url().encodedPath().split('.').last()
try {
response.body().use {
Cache(this@DownloadWorker).putImage(galleryID, i, ext, it!!.byteStream())
response.body()!!.use {
Cache(this@DownloadWorker).putImage(galleryID, i, ext, it.byteStream())
}
progress[galleryID]?.set(i, Float.POSITIVE_INFINITY)

View File

@@ -53,7 +53,7 @@ fun byteToString(byte: Long, precision : Int = 1) : String {
}
/*
/**
* Convert android generated ID to requestCode
* to prevent java.lang.IllegalArgumentException: Can only use lower 16 bits for requestCode
*

View File

@@ -23,8 +23,7 @@ import androidx.preference.PreferenceManager
import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import okhttp3.Authenticator
import okhttp3.Credentials
import okhttp3.*
import java.net.InetSocketAddress
import java.net.Proxy

View File

@@ -35,6 +35,7 @@ import okhttp3.*
import ru.noties.markwon.Markwon
import xyz.quaver.pupil.BuildConfig
import xyz.quaver.pupil.R
import xyz.quaver.pupil.client
import java.io.File
import java.io.IOException
import java.net.URL
@@ -187,7 +188,7 @@ fun restore(favorites: GalleryList, url: String, onFailure: ((Exception) -> Unit
.get()
.build()
OkHttpClient().newCall(request).enqueue(object: Callback {
client.newCall(request).enqueue(object: Callback {
override fun onFailure(call: Call, e: IOException) {
onFailure?.invoke(e)
}

View File

@@ -140,4 +140,7 @@
<string name="settings_manage_favorites">ブックマーク管理</string>
<string name="settings_backup_failed">エラーが発生しました</string>
<string name="settings_backup_share">バックアップ共有</string>
<string name="channel_downloader">ダウンローダ</string>
<string name="channel_downloader_description">ダウンローダの状態を表示</string>
<string name="downloader_running">ダウンローダー起動中</string>
</resources>

View File

@@ -140,4 +140,7 @@
<string name="settings_manage_favorites">즐겨찾기 관리</string>
<string name="settings_backup_failed">업로드 실패</string>
<string name="settings_backup_share">백업 공유</string>
<string name="channel_downloader">다운로더</string>
<string name="channel_downloader_description">다운로더 작동 여부 표시</string>
<string name="downloader_running">다운로더 작동중…</string>
</resources>

View File

@@ -10,4 +10,7 @@
<item name="request_write_permission_and_saf" type="id" />
<item name="notification_id_update" type="id" />
<item name="downloader_notification_id" type="id" />
<item name="downloader_notification_request" type="id" />
</resources>

View File

@@ -29,6 +29,9 @@
<string name="channel_download">Download</string>
<string name="channel_download_description">Shows download status</string>
<string name="channel_downloader">Downloader</string>
<string name="channel_downloader_description">Shows downloader status</string>
<string name="channel_update">Update</string>
<string name="channel_update_description">Shows update progress</string>
@@ -103,6 +106,9 @@
<string name="reader_notification_text">Downloading&#8230;</string>
<string name="reader_notification_complete">Download complete</string>
<!-- DOWNLOADER -->
<string name="downloader_running">Downloader running…</string>
<!-- SETTINGS -->
<string name="settings_title">Settings</string>