mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-10-30 22:07:57 +01:00 
			
		
		
		
	Allow glide to use source's network client. Catalogue fixes
This commit is contained in:
		| @@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.data.glide | ||||
| import android.content.Context | ||||
| import android.util.LruCache | ||||
| import com.bumptech.glide.Glide | ||||
| import com.bumptech.glide.integration.okhttp3.OkHttpStreamFetcher | ||||
| import com.bumptech.glide.load.data.DataFetcher | ||||
| import com.bumptech.glide.load.model.* | ||||
| import com.bumptech.glide.load.model.stream.StreamModelLoader | ||||
| @@ -89,15 +90,18 @@ class MangaModelLoader(context: Context) : StreamModelLoader<Manga> { | ||||
|         } | ||||
|  | ||||
|         if (url.startsWith("http")) { | ||||
|             val source = sourceManager.get(manga.source) as? HttpSource | ||||
|  | ||||
|             // Obtain the request url and the file for this url from the LRU cache, or calculate it | ||||
|             // and add them to the cache. | ||||
|             val (glideUrl, file) = lruCache.get(url) ?: | ||||
|                     Pair(GlideUrl(url, getHeaders(manga)), coverCache.getCoverFile(url)).apply { | ||||
|                     Pair(GlideUrl(url, getHeaders(manga, source)), coverCache.getCoverFile(url)).apply { | ||||
|                         lruCache.put(url, this) | ||||
|                     } | ||||
|  | ||||
|             // Get the resource fetcher for this request url. | ||||
|             val networkFetcher = baseUrlLoader.getResourceFetcher(glideUrl, width, height) | ||||
|             val networkFetcher = source?.let { OkHttpStreamFetcher(it.client, glideUrl) } | ||||
|                 ?: baseUrlLoader.getResourceFetcher(glideUrl, width, height) | ||||
|  | ||||
|             // Return an instance of the fetcher providing the needed elements. | ||||
|             return MangaUrlFetcher(networkFetcher, file, manga) | ||||
| @@ -118,8 +122,9 @@ class MangaModelLoader(context: Context) : StreamModelLoader<Manga> { | ||||
|      * | ||||
|      * @param manga the model. | ||||
|      */ | ||||
|     fun getHeaders(manga: Manga): Headers { | ||||
|         val source = sourceManager.get(manga.source) as? HttpSource ?: return LazyHeaders.DEFAULT | ||||
|     fun getHeaders(manga: Manga, source: HttpSource?): Headers { | ||||
|         if (source == null) return LazyHeaders.DEFAULT | ||||
|  | ||||
|         return cachedHeaders.getOrPut(manga.source) { | ||||
|             LazyHeaders.Builder().apply { | ||||
|                 val nullStr: String? = null | ||||
|   | ||||
| @@ -6,7 +6,7 @@ import okhttp3.Interceptor | ||||
| import okhttp3.Request | ||||
| import okhttp3.Response | ||||
|  | ||||
| class CloudflareInterceptor(private val cookies: PersistentCookieStore) : Interceptor { | ||||
| class CloudflareInterceptor : Interceptor { | ||||
|  | ||||
|     //language=RegExp | ||||
|     private val operationPattern = Regex("""setTimeout\(function\(\)\{\s+(var (?:\w,)+f.+?\r?\n[\s\S]+?a\.value =.+?)\r?\n""") | ||||
| @@ -17,18 +17,12 @@ class CloudflareInterceptor(private val cookies: PersistentCookieStore) : Interc | ||||
|     //language=RegExp | ||||
|     private val challengePattern = Regex("""name="jschl_vc" value="(\w+)"""") | ||||
|  | ||||
|     @Synchronized | ||||
|     override fun intercept(chain: Interceptor.Chain): Response { | ||||
|         val response = chain.proceed(chain.request()) | ||||
|  | ||||
|         // Check if we already solved a challenge | ||||
|         if (response.code() != 503 && | ||||
|                 cookies.get(response.request().url()).any { it.name() == "cf_clearance" }) { | ||||
|             return response | ||||
|         } | ||||
|  | ||||
|         // Check if Cloudflare anti-bot is on | ||||
|         if ("URL=/cdn-cgi/" in response.header("Refresh", "") | ||||
|                 && response.header("Server", "") == "cloudflare-nginx") { | ||||
|         if (response.code() == 503 && "cloudflare-nginx" == response.header("Server")) { | ||||
|             return chain.proceed(resolveChallenge(response)) | ||||
|         } | ||||
|  | ||||
| @@ -36,10 +30,10 @@ class CloudflareInterceptor(private val cookies: PersistentCookieStore) : Interc | ||||
|     } | ||||
|  | ||||
|     private fun resolveChallenge(response: Response): Request { | ||||
|         val duktape = Duktape.create() | ||||
|         try { | ||||
|         Duktape.create().use { duktape -> | ||||
|             val originalRequest = response.request() | ||||
|             val domain = originalRequest.url().host() | ||||
|             val url = originalRequest.url() | ||||
|             val domain = url.host() | ||||
|             val content = response.body().string() | ||||
|  | ||||
|             // CloudFlare requires waiting 4 seconds before resolving the challenge | ||||
| @@ -64,16 +58,19 @@ class CloudflareInterceptor(private val cookies: PersistentCookieStore) : Interc | ||||
|  | ||||
|             val answer = "${result + domain.length}" | ||||
|  | ||||
|             val url = HttpUrl.parse("http://$domain/cdn-cgi/l/chk_jschl").newBuilder() | ||||
|             val cloudflareUrl = HttpUrl.parse("${url.scheme()}://$domain/cdn-cgi/l/chk_jschl") | ||||
|                     .newBuilder() | ||||
|                     .addQueryParameter("jschl_vc", challenge) | ||||
|                     .addQueryParameter("pass", pass) | ||||
|                     .addQueryParameter("jschl_answer", answer) | ||||
|                     .toString() | ||||
|  | ||||
|             val referer = originalRequest.url().toString() | ||||
|             return GET(url, originalRequest.headers().newBuilder().add("Referer", referer).build()) | ||||
|         } finally { | ||||
|             duktape.close() | ||||
|             val cloudflareHeaders = originalRequest.headers() | ||||
|                     .newBuilder() | ||||
|                     .add("Referer", url.toString()) | ||||
|                     .build() | ||||
|  | ||||
|             return GET(cloudflareUrl, cloudflareHeaders) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -29,7 +29,7 @@ class NetworkHelper(context: Context) { | ||||
|             .build() | ||||
|  | ||||
|     val cloudflareClient = client.newBuilder() | ||||
|             .addInterceptor(CloudflareInterceptor(cookies)) | ||||
|             .addInterceptor(CloudflareInterceptor()) | ||||
|             .build() | ||||
|  | ||||
|     val cookies: PersistentCookieStore | ||||
|   | ||||
| @@ -28,38 +28,36 @@ class PersistentCookieStore(context: Context) { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Synchronized | ||||
|     fun addAll(url: HttpUrl, cookies: List<Cookie>) { | ||||
|         synchronized(this) { | ||||
|             val key = url.uri().host | ||||
|         val key = url.uri().host | ||||
|  | ||||
|             // Append or replace the cookies for this domain. | ||||
|             val cookiesForDomain = cookieMap[key].orEmpty().toMutableList() | ||||
|             for (cookie in cookies) { | ||||
|                 // Find a cookie with the same name. Replace it if found, otherwise add a new one. | ||||
|                 val pos = cookiesForDomain.indexOfFirst { it.name() == cookie.name() } | ||||
|                 if (pos == -1) { | ||||
|                     cookiesForDomain.add(cookie) | ||||
|                 } else { | ||||
|                     cookiesForDomain[pos] = cookie | ||||
|                 } | ||||
|         // Append or replace the cookies for this domain. | ||||
|         val cookiesForDomain = cookieMap[key].orEmpty().toMutableList() | ||||
|         for (cookie in cookies) { | ||||
|             // Find a cookie with the same name. Replace it if found, otherwise add a new one. | ||||
|             val pos = cookiesForDomain.indexOfFirst { it.name() == cookie.name() } | ||||
|             if (pos == -1) { | ||||
|                 cookiesForDomain.add(cookie) | ||||
|             } else { | ||||
|                 cookiesForDomain[pos] = cookie | ||||
|             } | ||||
|             cookieMap.put(key, cookiesForDomain) | ||||
|  | ||||
|             // Get cookies to be stored in disk | ||||
|             val newValues = cookiesForDomain.asSequence() | ||||
|                     .filter { it.persistent() && !it.hasExpired() } | ||||
|                     .map { it.toString() } | ||||
|                     .toSet() | ||||
|  | ||||
|             prefs.edit().putStringSet(key, newValues).apply() | ||||
|         } | ||||
|         cookieMap.put(key, cookiesForDomain) | ||||
|  | ||||
|         // Get cookies to be stored in disk | ||||
|         val newValues = cookiesForDomain.asSequence() | ||||
|                 .filter { it.persistent() && !it.hasExpired() } | ||||
|                 .map(Cookie::toString) | ||||
|                 .toSet() | ||||
|  | ||||
|         prefs.edit().putStringSet(key, newValues).apply() | ||||
|     } | ||||
|  | ||||
|     @Synchronized | ||||
|     fun removeAll() { | ||||
|         synchronized(this) { | ||||
|             prefs.edit().clear().apply() | ||||
|             cookieMap.clear() | ||||
|         } | ||||
|         prefs.edit().clear().apply() | ||||
|         cookieMap.clear() | ||||
|     } | ||||
|  | ||||
|     fun get(url: HttpUrl) = get(url.uri().host) | ||||
|   | ||||
| @@ -16,7 +16,6 @@ import eu.davidea.flexibleadapter.items.IFlexible | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.database.models.Manga | ||||
| import eu.kanade.tachiyomi.source.model.FilterList | ||||
| import eu.kanade.tachiyomi.source.online.LoginSource | ||||
| import eu.kanade.tachiyomi.ui.base.fragment.BaseRxFragment | ||||
| import eu.kanade.tachiyomi.ui.main.MainActivity | ||||
| import eu.kanade.tachiyomi.ui.manga.MangaActivity | ||||
| @@ -151,14 +150,6 @@ open class CatalogueFragment : BaseRxFragment<CataloguePresenter>(), | ||||
|     } | ||||
|  | ||||
|     override fun onViewCreated(view: View, savedState: Bundle?) { | ||||
|         // If the source list is empty or it only has unlogged sources, return to main screen. | ||||
|         val sources = presenter.sources | ||||
|         if (sources.isEmpty() || sources.all { it is LoginSource && !it.isLogged() }) { | ||||
|             context.toast(R.string.no_valid_sources) | ||||
|             activity.onBackPressed() | ||||
|             return | ||||
|         } | ||||
|  | ||||
|         // Initialize adapter, scroll listener and recycler views | ||||
|         adapter = FlexibleAdapter(null, this) | ||||
|         setupRecycler() | ||||
|   | ||||
| @@ -24,7 +24,6 @@ import rx.schedulers.Schedulers | ||||
| import rx.subjects.PublishSubject | ||||
| import timber.log.Timber | ||||
| import uy.kohesive.injekt.injectLazy | ||||
| import java.util.* | ||||
|  | ||||
| /** | ||||
|  * Presenter of [CatalogueFragment]. | ||||
| @@ -118,12 +117,8 @@ open class CataloguePresenter : BasePresenter<CatalogueFragment>() { | ||||
|     override fun onCreate(savedState: Bundle?) { | ||||
|         super.onCreate(savedState) | ||||
|  | ||||
|         try { | ||||
|             source = getLastUsedSource() | ||||
|             sourceFilters = source.getFilterList() | ||||
|         } catch (error: NoSuchElementException) { | ||||
|             return | ||||
|         } | ||||
|         source = getLastUsedSource() | ||||
|         sourceFilters = source.getFilterList() | ||||
|  | ||||
|         if (savedState != null) { | ||||
|             query = savedState.getString(CataloguePresenter::query.name, "") | ||||
| @@ -291,8 +286,8 @@ open class CataloguePresenter : BasePresenter<CatalogueFragment>() { | ||||
|     fun getLastUsedSource(): CatalogueSource { | ||||
|         val id = prefs.lastUsedCatalogueSource().get() ?: -1 | ||||
|         val source = sourceManager.get(id) | ||||
|         if (!isValidSource(source)) { | ||||
|             return findFirstValidSource() | ||||
|         if (!isValidSource(source) || source !in sources) { | ||||
|             return sources.first { isValidSource(it) } | ||||
|         } | ||||
|         return source as CatalogueSource | ||||
|     } | ||||
| @@ -313,15 +308,6 @@ open class CataloguePresenter : BasePresenter<CatalogueFragment>() { | ||||
|         return true | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Finds the first valid source. | ||||
|      * | ||||
|      * @return the index of the first valid source. | ||||
|      */ | ||||
|     fun findFirstValidSource(): CatalogueSource { | ||||
|         return sources.first { isValidSource(it) } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns a list of enabled sources ordered by language and name. | ||||
|      */ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user