diff --git a/.idea/runConfigurations/TestsAndReport.xml b/.idea/runConfigurations/TestsAndReport.xml
new file mode 100644
index 000000000..614cfdf37
--- /dev/null
+++ b/.idea/runConfigurations/TestsAndReport.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/MangaParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/MangaParser.kt
index 0ee27c34d..eb04d3dd3 100644
--- a/src/main/kotlin/org/koitharu/kotatsu/parsers/MangaParser.kt
+++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/MangaParser.kt
@@ -1,6 +1,8 @@
package org.koitharu.kotatsu.parsers
import androidx.annotation.CallSuper
+import androidx.annotation.VisibleForTesting
+import okhttp3.Headers
import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.exception.ParseException
import org.koitharu.kotatsu.parsers.model.*
@@ -31,6 +33,9 @@ abstract class MangaParser @InternalParsersApi constructor(val source: MangaSour
*/
protected abstract val configKeyDomain: ConfigKey.Domain
+ @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
+ internal open val headers: Headers? = null
+
/**
* Used as fallback if value of `sortOrder` passed to [getList] is null
*/
@@ -113,7 +118,7 @@ abstract class MangaParser @InternalParsersApi constructor(val source: MangaSour
open fun getFaviconUrl() = "https://${getDomain()}/favicon.ico"
open suspend fun parseFavicons(): Favicons {
- return FaviconParser(context, getDomain()).parseFavicons()
+ return FaviconParser(context, getDomain(), headers).parseFavicons()
}
@CallSuper
diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/NineMangaParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/NineMangaParser.kt
index 20c88be1b..26eee91bd 100644
--- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/NineMangaParser.kt
+++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/NineMangaParser.kt
@@ -26,7 +26,7 @@ internal abstract class NineMangaParser(
context.cookieJar.insertCookies(getDomain(), "ninemanga_template_desk=yes")
}
- private val headers = Headers.Builder()
+ override val headers = Headers.Builder()
.add("Accept-Language", "en-US;q=0.7,en;q=0.3")
.build()
@@ -171,10 +171,6 @@ internal abstract class NineMangaParser(
} ?: parseFailed("Root not found")
}
- override suspend fun parseFavicons(): Favicons {
- return FaviconParser(context, getDomain()).addHeaders(headers).parseFavicons()
- }
-
private fun parseStatus(status: String) = when {
status.contains("Ongoing") -> MangaState.ONGOING
status.contains("Completed") -> MangaState.FINISHED
diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/grouple/GroupleParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/grouple/GroupleParser.kt
index 073b68bfd..f7425c1d1 100644
--- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/grouple/GroupleParser.kt
+++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/grouple/GroupleParser.kt
@@ -24,7 +24,7 @@ internal abstract class GroupleParser(
private val siteId: Int,
) : MangaParser(source), MangaParserAuthProvider {
- private val headers = Headers.Builder()
+ override val headers = Headers.Builder()
.add("User-Agent", userAgent)
.build()
diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/util/FaviconParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/util/FaviconParser.kt
index b7767a33f..fec7f706a 100644
--- a/src/main/kotlin/org/koitharu/kotatsu/parsers/util/FaviconParser.kt
+++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/util/FaviconParser.kt
@@ -7,18 +7,15 @@ import org.koitharu.kotatsu.parsers.model.Favicon
import org.koitharu.kotatsu.parsers.model.Favicons
import org.koitharu.kotatsu.parsers.util.json.mapJSON
-class FaviconParser(private val context: MangaLoaderContext, private val domain: String) {
-
- private val headers = Headers.Builder()
-
- fun addHeaders(headers: Headers): FaviconParser {
- this.headers.addAll(headers)
- return this
- }
+class FaviconParser(
+ private val context: MangaLoaderContext,
+ private val domain: String,
+ private val headers: Headers?,
+) {
suspend fun parseFavicons(): Favicons {
val url = "https://$domain"
- val doc = context.httpGet(url, headers.build()).parseHtml()
+ val doc = context.httpGet(url, headers).parseHtml()
val result = HashSet()
val manifestLink = doc.getElementsByAttributeValue("rel", "manifest").firstOrNull()
?.attrAsAbsoluteUrlOrNull("href")
@@ -59,7 +56,7 @@ class FaviconParser(private val context: MangaLoaderContext, private val domain:
}
private suspend fun parseManifest(url: String): List {
- val json = context.httpGet(url, headers.build()).parseJson()
+ val json = context.httpGet(url, headers).parseJson()
val icons = json.getJSONArray("icons")
return icons.mapJSON { jo ->
Favicon(
diff --git a/src/test/kotlin/org/koitharu/kotatsu/parsers/MangaLoaderContextMock.kt b/src/test/kotlin/org/koitharu/kotatsu/parsers/MangaLoaderContextMock.kt
index 60357aa43..95ebb59c3 100644
--- a/src/test/kotlin/org/koitharu/kotatsu/parsers/MangaLoaderContextMock.kt
+++ b/src/test/kotlin/org/koitharu/kotatsu/parsers/MangaLoaderContextMock.kt
@@ -1,6 +1,7 @@
package org.koitharu.kotatsu.parsers
import com.koushikdutta.quack.QuackContext
+import okhttp3.Headers
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
@@ -45,10 +46,13 @@ internal class MangaLoaderContextMock : MangaLoaderContext() {
return SourceConfigMock()
}
- suspend fun doRequest(url: String, referer: String? = null): Response {
+ suspend fun doRequest(url: String, referer: String? = null, extraHeaders: Headers? = null): Response {
val request = Request.Builder()
.get()
.url(url)
+ if (extraHeaders != null) {
+ request.headers(extraHeaders)
+ }
if (referer != null) {
request.header("Referer", referer)
}
diff --git a/src/test/kotlin/org/koitharu/kotatsu/parsers/MangaParserTest.kt b/src/test/kotlin/org/koitharu/kotatsu/parsers/MangaParserTest.kt
index d02d3d6f9..4055cd8e0 100644
--- a/src/test/kotlin/org/koitharu/kotatsu/parsers/MangaParserTest.kt
+++ b/src/test/kotlin/org/koitharu/kotatsu/parsers/MangaParserTest.kt
@@ -141,7 +141,7 @@ internal class MangaParserTest {
.host(defaultDomain)
.scheme("https")
.toString()
- val response = context.doRequest(url)
+ val response = context.doRequest(url, extraHeaders = parser.headers)
val realUrl = response.request.url
val realDomain = realUrl.topPrivateDomain()
val realHost = realUrl.host