mirror of
https://github.com/rebelonion/Dantotsu.git
synced 2026-01-20 17:03:56 +00:00
chore: code cleanup
This commit is contained in:
@@ -17,7 +17,7 @@ class BasePreferences(
|
||||
fun incognitoMode() = preferenceStore.getBoolean("incognito_mode", false)
|
||||
|
||||
fun extensionInstaller() = ExtensionInstallerPreference(context, preferenceStore)
|
||||
|
||||
|
||||
fun deviceHasPip() =
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && context.packageManager.hasSystemFeature(
|
||||
PackageManager.FEATURE_PICTURE_IN_PICTURE
|
||||
|
||||
@@ -23,7 +23,6 @@ import uy.kohesive.injekt.injectLazy
|
||||
import java.net.URI
|
||||
import java.net.URISyntaxException
|
||||
import java.security.MessageDigest
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
/**
|
||||
* A simple implementation for sources from a website.
|
||||
@@ -89,14 +88,15 @@ abstract class AnimeHttpSource : AnimeCatalogueSource {
|
||||
protected fun generateId(name: String, lang: String, versionId: Int): Long {
|
||||
val key = "${name.lowercase()}/$lang/$versionId"
|
||||
val bytes = MessageDigest.getInstance("MD5").digest(key.toByteArray())
|
||||
return (0..7).map { bytes[it].toLong() and 0xff shl 8 * (7 - it) }.reduce(Long::or) and Long.MAX_VALUE
|
||||
return (0..7).map { bytes[it].toLong() and 0xff shl 8 * (7 - it) }
|
||||
.reduce(Long::or) and Long.MAX_VALUE
|
||||
}
|
||||
|
||||
/**
|
||||
* Headers builder for requests. Implementations can override this method for custom headers.
|
||||
*/
|
||||
protected open fun headersBuilder() = Headers.Builder().apply {
|
||||
add("User-Agent", NetworkHelper.defaultUserAgentProvider())
|
||||
add("User-Agent", defaultUserAgentProvider())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -148,7 +148,11 @@ abstract class AnimeHttpSource : AnimeCatalogueSource {
|
||||
"Use the non-RxJava API instead",
|
||||
ReplaceWith("getSearchAnime"),
|
||||
)
|
||||
override fun fetchSearchAnime(page: Int, query: String, filters: AnimeFilterList): Observable<AnimesPage> {
|
||||
override fun fetchSearchAnime(
|
||||
page: Int,
|
||||
query: String,
|
||||
filters: AnimeFilterList
|
||||
): Observable<AnimesPage> {
|
||||
return Observable.defer {
|
||||
try {
|
||||
client.newCall(searchAnimeRequest(page, query, filters)).asObservableSuccess()
|
||||
@@ -170,7 +174,11 @@ abstract class AnimeHttpSource : AnimeCatalogueSource {
|
||||
* @param query the search query.
|
||||
* @param filters the list of filters to apply.
|
||||
*/
|
||||
protected abstract fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request
|
||||
protected abstract fun searchAnimeRequest(
|
||||
page: Int,
|
||||
query: String,
|
||||
filters: AnimeFilterList
|
||||
): Request
|
||||
|
||||
/**
|
||||
* Parses the response from the site and returns a [AnimesPage] object.
|
||||
@@ -403,7 +411,8 @@ abstract class AnimeHttpSource : AnimeCatalogueSource {
|
||||
video: Video,
|
||||
tries: Int,
|
||||
): Long {
|
||||
val headers = Headers.Builder().addAll(video.headers ?: headers).add("Range", "bytes=0-1").build()
|
||||
val headers =
|
||||
Headers.Builder().addAll(video.headers ?: headers).add("Range", "bytes=0-1").build()
|
||||
val request = GET(video.videoUrl!!, headers)
|
||||
val response = client.newCall(request).execute()
|
||||
// parse the response headers to get the size of the video, in particular the content-range header
|
||||
|
||||
@@ -207,8 +207,10 @@ class AnimeExtensionManager(
|
||||
* @param extension The anime extension to be installed.
|
||||
*/
|
||||
fun installExtension(extension: AnimeExtension.Available): Observable<InstallStep> {
|
||||
return installer.downloadAndInstall(api.getAnimeApkUrl(extension), extension.pkgName,
|
||||
extension.name, MediaType.ANIME)
|
||||
return installer.downloadAndInstall(
|
||||
api.getAnimeApkUrl(extension), extension.pkgName,
|
||||
extension.name, MediaType.ANIME
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -28,18 +28,19 @@ class PackageInstallerInstaller(private val service: Service) : Installer(servic
|
||||
PackageInstaller.STATUS_FAILURE
|
||||
)) {
|
||||
PackageInstaller.STATUS_PENDING_USER_ACTION -> {
|
||||
val userAction = intent.getParcelableExtraCompat<Intent>(Intent.EXTRA_INTENT)?.run {
|
||||
IntentSanitizer.Builder()
|
||||
.allowAction(this.action!!)
|
||||
.allowExtra(PackageInstaller.EXTRA_SESSION_ID) { id -> id == activeSession?.second }
|
||||
.allowAnyComponent()
|
||||
.allowPackage {
|
||||
// There is no way to check the actual installer name so allow all.
|
||||
true
|
||||
}
|
||||
.build()
|
||||
.sanitizeByFiltering(this)
|
||||
}
|
||||
val userAction =
|
||||
intent.getParcelableExtraCompat<Intent>(Intent.EXTRA_INTENT)?.run {
|
||||
IntentSanitizer.Builder()
|
||||
.allowAction(this.action!!)
|
||||
.allowExtra(PackageInstaller.EXTRA_SESSION_ID) { id -> id == activeSession?.second }
|
||||
.allowAnyComponent()
|
||||
.allowPackage {
|
||||
// There is no way to check the actual installer name so allow all.
|
||||
true
|
||||
}
|
||||
.build()
|
||||
.sanitizeByFiltering(this)
|
||||
}
|
||||
if (userAction == null) {
|
||||
Logger.log("Fatal error for $intent")
|
||||
continueQueue(InstallStep.Error)
|
||||
|
||||
@@ -204,8 +204,10 @@ class MangaExtensionManager(
|
||||
* @param extension The extension to be installed.
|
||||
*/
|
||||
fun installExtension(extension: MangaExtension.Available): Observable<InstallStep> {
|
||||
return installer.downloadAndInstall(api.getMangaApkUrl(extension), extension.pkgName,
|
||||
extension.name, MediaType.MANGA)
|
||||
return installer.downloadAndInstall(
|
||||
api.getMangaApkUrl(extension), extension.pkgName,
|
||||
extension.name, MediaType.MANGA
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -41,9 +41,11 @@ class ExtensionInstallActivity : AppCompatActivity() {
|
||||
ThemeManager(this).applyTheme()
|
||||
|
||||
if (intent.hasExtra(ExtensionInstaller.EXTRA_EXTENSION_TYPE))
|
||||
mediaType = intent.getSerializableExtraCompat<MediaType>(ExtensionInstaller.EXTRA_EXTENSION_TYPE)
|
||||
mediaType =
|
||||
intent.getSerializableExtraCompat<MediaType>(ExtensionInstaller.EXTRA_EXTENSION_TYPE)
|
||||
if (intent.hasExtra(ExtensionInstaller.EXTRA_ADDON_TYPE))
|
||||
addonType = intent.getSerializableExtraCompat<AddonType>(ExtensionInstaller.EXTRA_ADDON_TYPE)
|
||||
addonType =
|
||||
intent.getSerializableExtraCompat<AddonType>(ExtensionInstaller.EXTRA_ADDON_TYPE)
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
val installIntent = Intent(Intent.ACTION_INSTALL_PACKAGE)
|
||||
|
||||
@@ -37,14 +37,14 @@ internal class ExtensionInstallReceiver : BroadcastReceiver() {
|
||||
ContextCompat.registerReceiver(context, this, filter, ContextCompat.RECEIVER_EXPORTED)
|
||||
}
|
||||
|
||||
fun setAnimeListener(listener: AnimeListener) : ExtensionInstallReceiver {
|
||||
fun setAnimeListener(listener: AnimeListener): ExtensionInstallReceiver {
|
||||
this.type = MediaType.ANIME
|
||||
animeListener = listener
|
||||
this.animeListener
|
||||
return this
|
||||
}
|
||||
|
||||
fun setMangaListener(listener: MangaListener) : ExtensionInstallReceiver {
|
||||
fun setMangaListener(listener: MangaListener): ExtensionInstallReceiver {
|
||||
this.type = MediaType.MANGA
|
||||
mangaListener = listener
|
||||
return this
|
||||
@@ -66,21 +66,33 @@ internal class ExtensionInstallReceiver : BroadcastReceiver() {
|
||||
when (type) {
|
||||
MediaType.ANIME -> {
|
||||
when (val result = getAnimeExtensionFromIntent(context, intent)) {
|
||||
is AnimeLoadResult.Success -> animeListener?.onExtensionInstalled(result.extension)
|
||||
is AnimeLoadResult.Success -> animeListener?.onExtensionInstalled(
|
||||
result.extension
|
||||
)
|
||||
|
||||
is AnimeLoadResult.Untrusted -> animeListener?.onExtensionUntrusted(
|
||||
result.extension
|
||||
)
|
||||
|
||||
is AnimeLoadResult.Untrusted -> animeListener?.onExtensionUntrusted(result.extension)
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
MediaType.MANGA -> {
|
||||
when (val result = getMangaExtensionFromIntent(context, intent)) {
|
||||
is MangaLoadResult.Success -> mangaListener?.onExtensionInstalled(result.extension)
|
||||
is MangaLoadResult.Success -> mangaListener?.onExtensionInstalled(
|
||||
result.extension
|
||||
)
|
||||
|
||||
is MangaLoadResult.Untrusted -> mangaListener?.onExtensionUntrusted(
|
||||
result.extension
|
||||
)
|
||||
|
||||
is MangaLoadResult.Untrusted -> mangaListener?.onExtensionUntrusted(result.extension)
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
else -> { }
|
||||
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -90,17 +102,25 @@ internal class ExtensionInstallReceiver : BroadcastReceiver() {
|
||||
when (type) {
|
||||
MediaType.ANIME -> {
|
||||
when (val result = getAnimeExtensionFromIntent(context, intent)) {
|
||||
is AnimeLoadResult.Success -> animeListener?.onExtensionUpdated(result.extension)
|
||||
is AnimeLoadResult.Success -> animeListener?.onExtensionUpdated(
|
||||
result.extension
|
||||
)
|
||||
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
MediaType.MANGA -> {
|
||||
when (val result = getMangaExtensionFromIntent(context, intent)) {
|
||||
is MangaLoadResult.Success -> mangaListener?.onExtensionUpdated(result.extension)
|
||||
is MangaLoadResult.Success -> mangaListener?.onExtensionUpdated(
|
||||
result.extension
|
||||
)
|
||||
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
else -> { }
|
||||
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -114,10 +134,12 @@ internal class ExtensionInstallReceiver : BroadcastReceiver() {
|
||||
MediaType.ANIME -> {
|
||||
animeListener?.onPackageUninstalled(pkgName)
|
||||
}
|
||||
|
||||
MediaType.MANGA -> {
|
||||
mangaListener?.onPackageUninstalled(pkgName)
|
||||
}
|
||||
else -> { }
|
||||
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -131,7 +153,10 @@ internal class ExtensionInstallReceiver : BroadcastReceiver() {
|
||||
* @param intent The intent containing the package name of the extension.
|
||||
*/
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
private suspend fun getAnimeExtensionFromIntent(context: Context, intent: Intent?): AnimeLoadResult {
|
||||
private suspend fun getAnimeExtensionFromIntent(
|
||||
context: Context,
|
||||
intent: Intent?
|
||||
): AnimeLoadResult {
|
||||
val pkgName = getPackageNameFromIntent(intent)
|
||||
if (pkgName == null) {
|
||||
Logger.log("Package name not found")
|
||||
@@ -146,7 +171,10 @@ internal class ExtensionInstallReceiver : BroadcastReceiver() {
|
||||
}
|
||||
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
private suspend fun getMangaExtensionFromIntent(context: Context, intent: Intent?): MangaLoadResult {
|
||||
private suspend fun getMangaExtensionFromIntent(
|
||||
context: Context,
|
||||
intent: Intent?
|
||||
): MangaLoadResult {
|
||||
val pkgName = getPackageNameFromIntent(intent)
|
||||
if (pkgName == null) {
|
||||
Logger.log("Package name not found")
|
||||
|
||||
@@ -14,8 +14,8 @@ import ani.dantotsu.media.Type
|
||||
import ani.dantotsu.util.Logger
|
||||
import eu.kanade.domain.base.BasePreferences
|
||||
import eu.kanade.tachiyomi.data.notification.Notifications
|
||||
import eu.kanade.tachiyomi.extension.installer.PackageInstallerInstaller
|
||||
import eu.kanade.tachiyomi.extension.installer.Installer
|
||||
import eu.kanade.tachiyomi.extension.installer.PackageInstallerInstaller
|
||||
import eu.kanade.tachiyomi.extension.util.ExtensionInstaller.Companion.EXTRA_DOWNLOAD_ID
|
||||
import eu.kanade.tachiyomi.extension.util.ExtensionInstaller.Companion.EXTRA_EXTENSION_TYPE
|
||||
import eu.kanade.tachiyomi.util.system.getSerializableExtraCompat
|
||||
@@ -48,7 +48,8 @@ class ExtensionInstallService : Service() {
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
val uri = intent?.data
|
||||
val mediaType = intent?.getSerializableExtraCompat<MediaType>(EXTRA_EXTENSION_TYPE)
|
||||
val addonType = intent?.getSerializableExtraCompat<AddonType>(ExtensionInstaller.EXTRA_ADDON_TYPE)
|
||||
val addonType =
|
||||
intent?.getSerializableExtraCompat<AddonType>(ExtensionInstaller.EXTRA_ADDON_TYPE)
|
||||
val id = intent?.getLongExtra(EXTRA_DOWNLOAD_ID, -1)?.takeIf { it != -1L }
|
||||
val installerUsed = intent?.getSerializableExtraCompat<BasePreferences.ExtensionInstaller>(
|
||||
EXTRA_INSTALLER
|
||||
|
||||
@@ -14,14 +14,11 @@ import androidx.core.net.toUri
|
||||
import ani.dantotsu.media.AddonType
|
||||
import ani.dantotsu.media.MediaType
|
||||
import ani.dantotsu.media.Type
|
||||
import ani.dantotsu.parsers.novel.NovelExtension
|
||||
import ani.dantotsu.util.Logger
|
||||
import com.jakewharton.rxrelay.PublishRelay
|
||||
import eu.kanade.domain.base.BasePreferences
|
||||
import eu.kanade.tachiyomi.extension.InstallStep
|
||||
import eu.kanade.tachiyomi.extension.anime.model.AnimeExtension
|
||||
import eu.kanade.tachiyomi.extension.installer.Installer
|
||||
import eu.kanade.tachiyomi.extension.manga.model.MangaExtension
|
||||
import eu.kanade.tachiyomi.util.storage.getUriCompat
|
||||
import rx.Observable
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
@@ -67,7 +64,12 @@ class ExtensionInstaller(private val context: Context) {
|
||||
* @param url The url of the apk.
|
||||
* @param extension The extension to install.
|
||||
*/
|
||||
fun <T : Type> downloadAndInstall(url: String, pkgName: String, name: String, type: T): Observable<InstallStep> = Observable.defer {
|
||||
fun <T : Type> downloadAndInstall(
|
||||
url: String,
|
||||
pkgName: String,
|
||||
name: String,
|
||||
type: T
|
||||
): Observable<InstallStep> = Observable.defer {
|
||||
val oldDownload = activeDownloads[pkgName]
|
||||
if (oldDownload != null) {
|
||||
deleteDownload(pkgName)
|
||||
@@ -264,11 +266,15 @@ class ExtensionInstaller(private val context: Context) {
|
||||
val localUri = cursor.getString(
|
||||
cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_LOCAL_URI),
|
||||
).removePrefix(FILE_SCHEME)
|
||||
val type = MediaType.fromText(cursor.getString(
|
||||
cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_DESCRIPTION),
|
||||
)) ?: AddonType.fromText(cursor.getString(
|
||||
cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_DESCRIPTION),
|
||||
)) ?: return
|
||||
val type = MediaType.fromText(
|
||||
cursor.getString(
|
||||
cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_DESCRIPTION),
|
||||
)
|
||||
) ?: AddonType.fromText(
|
||||
cursor.getString(
|
||||
cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_DESCRIPTION),
|
||||
)
|
||||
) ?: return
|
||||
|
||||
installApk(type, id, File(localUri).getUriCompat(context))
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ internal object ExtensionLoader {
|
||||
|
||||
val PACKAGE_FLAGS = PackageManager.GET_CONFIGURATIONS or
|
||||
PackageManager.GET_META_DATA or
|
||||
@Suppress ("DEPRECATION") PackageManager.GET_SIGNATURES or
|
||||
@Suppress("DEPRECATION") PackageManager.GET_SIGNATURES or
|
||||
(if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
|
||||
PackageManager.GET_SIGNING_CERTIFICATES else 0)
|
||||
|
||||
@@ -145,7 +145,7 @@ internal object ExtensionLoader {
|
||||
Logger.log(error)
|
||||
return AnimeLoadResult.Error
|
||||
}
|
||||
if (!isPackageAnExtension(MediaType.ANIME,pkgInfo)) {
|
||||
if (!isPackageAnExtension(MediaType.ANIME, pkgInfo)) {
|
||||
Logger.log("Tried to load a package that wasn't a extension ($pkgName)")
|
||||
return AnimeLoadResult.Error
|
||||
}
|
||||
@@ -201,8 +201,9 @@ internal object ExtensionLoader {
|
||||
// Validate lib version
|
||||
val libVersion = versionName.substringBeforeLast('.').toDoubleOrNull()
|
||||
if (libVersion == null || libVersion < ANIME_LIB_VERSION_MIN || libVersion > ANIME_LIB_VERSION_MAX) {
|
||||
Logger.log("Lib version is $libVersion, while only versions " +
|
||||
"$ANIME_LIB_VERSION_MIN to $ANIME_LIB_VERSION_MAX are allowed"
|
||||
Logger.log(
|
||||
"Lib version is $libVersion, while only versions " +
|
||||
"$ANIME_LIB_VERSION_MIN to $ANIME_LIB_VERSION_MAX are allowed"
|
||||
)
|
||||
return AnimeLoadResult.Error
|
||||
}
|
||||
@@ -232,7 +233,8 @@ internal object ExtensionLoader {
|
||||
}
|
||||
|
||||
val hasReadme = appInfo.metaData.getInt("$ANIME_PACKAGE$XX_METADATA_HAS_README", 0) == 1
|
||||
val hasChangelog = appInfo.metaData.getInt("$ANIME_PACKAGE$XX_METADATA_HAS_CHANGELOG", 0) == 1
|
||||
val hasChangelog =
|
||||
appInfo.metaData.getInt("$ANIME_PACKAGE$XX_METADATA_HAS_CHANGELOG", 0) == 1
|
||||
|
||||
val classLoader = PathClassLoader(appInfo.sourceDir, null, context.classLoader)
|
||||
|
||||
@@ -248,7 +250,8 @@ internal object ExtensionLoader {
|
||||
}
|
||||
.flatMap {
|
||||
try {
|
||||
when (val obj = Class.forName(it, false, classLoader).getDeclaredConstructor().newInstance()) {
|
||||
when (val obj = Class.forName(it, false, classLoader).getDeclaredConstructor()
|
||||
.newInstance()) {
|
||||
is AnimeSource -> listOf(obj)
|
||||
is AnimeSourceFactory -> obj.createSources()
|
||||
else -> throw Exception("Unknown source class type! ${obj.javaClass}")
|
||||
@@ -314,8 +317,9 @@ internal object ExtensionLoader {
|
||||
// Validate lib version
|
||||
val libVersion = versionName.substringBeforeLast('.').toDoubleOrNull()
|
||||
if (libVersion == null || libVersion < MANGA_LIB_VERSION_MIN || libVersion > MANGA_LIB_VERSION_MAX) {
|
||||
Logger.log("Lib version is $libVersion, while only versions " +
|
||||
"$MANGA_LIB_VERSION_MIN to $MANGA_LIB_VERSION_MAX are allowed"
|
||||
Logger.log(
|
||||
"Lib version is $libVersion, while only versions " +
|
||||
"$MANGA_LIB_VERSION_MIN to $MANGA_LIB_VERSION_MAX are allowed"
|
||||
)
|
||||
return MangaLoadResult.Error
|
||||
}
|
||||
@@ -340,7 +344,8 @@ internal object ExtensionLoader {
|
||||
}
|
||||
|
||||
val hasReadme = appInfo.metaData.getInt("$MANGA_PACKAGE$XX_METADATA_HAS_README", 0) == 1
|
||||
val hasChangelog = appInfo.metaData.getInt("$MANGA_PACKAGE$XX_METADATA_HAS_CHANGELOG", 0) == 1
|
||||
val hasChangelog =
|
||||
appInfo.metaData.getInt("$MANGA_PACKAGE$XX_METADATA_HAS_CHANGELOG", 0) == 1
|
||||
|
||||
val classLoader = PathClassLoader(appInfo.sourceDir, null, context.classLoader)
|
||||
|
||||
@@ -401,11 +406,13 @@ internal object ExtensionLoader {
|
||||
* @param pkgInfo The package info of the application.
|
||||
*/
|
||||
private fun isPackageAnExtension(type: MediaType, pkgInfo: PackageInfo): Boolean {
|
||||
return pkgInfo.reqFeatures.orEmpty().any { it.name == when (type) {
|
||||
MediaType.ANIME -> ANIME_PACKAGE
|
||||
MediaType.MANGA -> MANGA_PACKAGE
|
||||
else -> ""
|
||||
} }
|
||||
return pkgInfo.reqFeatures.orEmpty().any {
|
||||
it.name == when (type) {
|
||||
MediaType.ANIME -> ANIME_PACKAGE
|
||||
MediaType.MANGA -> MANGA_PACKAGE
|
||||
else -> ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -417,7 +424,7 @@ internal object ExtensionLoader {
|
||||
val signatures = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
|
||||
pkgInfo.signingInfo.signingCertificateHistory
|
||||
else
|
||||
@Suppress ("DEPRECATION") pkgInfo.signatures
|
||||
@Suppress("DEPRECATION") pkgInfo.signatures
|
||||
return if (signatures != null && signatures.isNotEmpty()) {
|
||||
Hash.sha256(signatures.first().toByteArray())
|
||||
} else {
|
||||
|
||||
@@ -11,8 +11,8 @@ import eu.kanade.tachiyomi.network.interceptor.UncaughtExceptionInterceptor
|
||||
import eu.kanade.tachiyomi.network.interceptor.UserAgentInterceptor
|
||||
import okhttp3.Cache
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.logging.HttpLoggingInterceptor
|
||||
import okhttp3.brotli.BrotliInterceptor
|
||||
import okhttp3.logging.HttpLoggingInterceptor
|
||||
import java.io.File
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
|
||||
Reference in New Issue
Block a user