Add Mehgazone and remove Latisbooks (#9040)
* Add initial version of mehgazone * Update Mehgazone and remove Latisbooks Latisbooks now redirects to Mehgazone * Update Mehgazone.kt * implement requested changes * implement requested changes
@ -1,8 +0,0 @@
|
||||
ext {
|
||||
extName = 'Latis Books'
|
||||
extClass = '.Latisbooks'
|
||||
extVersionCode = 6
|
||||
isNsfw = true
|
||||
}
|
||||
|
||||
apply from: "$rootDir/common.gradle"
|
Before Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 5.8 KiB |
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 17 KiB |
@ -1,146 +0,0 @@
|
||||
package eu.kanade.tachiyomi.extension.en.latisbooks
|
||||
|
||||
import android.net.Uri.encode
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||
import eu.kanade.tachiyomi.source.model.Page
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import rx.Observable
|
||||
import java.util.Calendar
|
||||
|
||||
class Latisbooks : HttpSource() {
|
||||
|
||||
override val name = "Latis Books"
|
||||
|
||||
override val baseUrl = "https://www.latisbooks.com"
|
||||
|
||||
override val lang = "en"
|
||||
|
||||
override val supportsLatest = false
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient
|
||||
|
||||
private val textToImageURL = "https://fakeimg.ryd.tools/1500x2126/ffffff/000000/?font=museo&font_size=42"
|
||||
|
||||
private fun String.image() = textToImageURL + "&text=" + encode(this)
|
||||
|
||||
private fun createManga(response: Response): SManga {
|
||||
return SManga.create().apply {
|
||||
initialized = true
|
||||
title = "Bodysuit 23"
|
||||
url = "/archive/"
|
||||
thumbnail_url = "https://images.squarespace-cdn.com/content/v1/56595108e4b01110e1cf8735/1511856223610-NSB8O5OJ1F6KPQL0ZGBH/image-asset.jpeg"
|
||||
}
|
||||
}
|
||||
|
||||
// Popular
|
||||
|
||||
override fun fetchPopularManga(page: Int): Observable<MangasPage> {
|
||||
return client.newCall(popularMangaRequest(page))
|
||||
.asObservableSuccess()
|
||||
.map { response ->
|
||||
MangasPage(listOf(createManga(response)), false)
|
||||
}
|
||||
}
|
||||
|
||||
override fun popularMangaRequest(page: Int): Request {
|
||||
return (GET("$baseUrl/archive/", headers))
|
||||
}
|
||||
|
||||
override fun popularMangaParse(response: Response): MangasPage = throw UnsupportedOperationException()
|
||||
|
||||
// Latest
|
||||
|
||||
override fun latestUpdatesRequest(page: Int): Request = throw UnsupportedOperationException()
|
||||
|
||||
override fun latestUpdatesParse(response: Response): MangasPage = throw UnsupportedOperationException()
|
||||
|
||||
// Search
|
||||
|
||||
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> = Observable.just(MangasPage(emptyList(), false))
|
||||
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request = throw UnsupportedOperationException()
|
||||
|
||||
override fun searchMangaParse(response: Response): MangasPage = throw UnsupportedOperationException()
|
||||
|
||||
// Details
|
||||
|
||||
override fun fetchMangaDetails(manga: SManga): Observable<SManga> {
|
||||
return client.newCall(mangaDetailsRequest(manga))
|
||||
.asObservableSuccess()
|
||||
.map { response ->
|
||||
createManga(response)
|
||||
}
|
||||
}
|
||||
|
||||
override fun mangaDetailsParse(response: Response): SManga = throw UnsupportedOperationException()
|
||||
|
||||
// Chapters
|
||||
|
||||
override fun chapterListParse(response: Response): List<SChapter> {
|
||||
val cal: Calendar = Calendar.getInstance()
|
||||
|
||||
return response.asJsoup().select("ul.archive-item-list li a").map {
|
||||
val date: List<String> = it.attr("abs:href").split("/")
|
||||
cal.set(date[4].toInt(), date[5].toInt() - 1, date[6].toInt())
|
||||
|
||||
SChapter.create().apply {
|
||||
name = it.text()
|
||||
url = it.attr("abs:href")
|
||||
date_upload = cal.timeInMillis
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pages
|
||||
|
||||
// Adapted from the xkcd source's wordWrap function
|
||||
private fun wordWrap(text: String) = buildString {
|
||||
var charCount = 0
|
||||
text.replace("\r\n", " ").split(' ').forEach { w ->
|
||||
if (charCount > 25) {
|
||||
append("\n")
|
||||
charCount = 0
|
||||
}
|
||||
append(w).append(' ')
|
||||
charCount += w.length + 1
|
||||
}
|
||||
}
|
||||
|
||||
override fun pageListRequest(chapter: SChapter): Request = GET(chapter.url, headers)
|
||||
|
||||
override fun pageListParse(response: Response): List<Page> {
|
||||
val blocks = response.asJsoup().select("div.content-wrapper div.row div.col")
|
||||
|
||||
// Handle multiple images per page (e.g. Page 23+24)
|
||||
val pages = blocks.select("div.image-block-wrapper img")
|
||||
.mapIndexed { i, it -> Page(i, "", it.attr("abs:data-src")) }
|
||||
.toMutableList()
|
||||
|
||||
val numImages = pages.size
|
||||
|
||||
// Add text above/below the image as xkcd-esque text pages after the image itself
|
||||
pages.addAll(
|
||||
blocks.select("div.html-block")
|
||||
.map { it.select("div.sqs-block-content").first()!! }
|
||||
// Some pages have empty html blocks (e.g. Page 1), so ignore them
|
||||
.filter { it.childrenSize() > 0 }
|
||||
.mapIndexed { i, it -> Page(i + numImages, "", wordWrap(it.text()).image()) }
|
||||
.toList(),
|
||||
)
|
||||
|
||||
return pages.toList()
|
||||
}
|
||||
|
||||
override fun imageUrlParse(response: Response): String = throw UnsupportedOperationException()
|
||||
|
||||
override fun getFilterList() = FilterList()
|
||||
}
|
8
src/en/mehgazone/build.gradle
Normal file
@ -0,0 +1,8 @@
|
||||
ext {
|
||||
extName = 'Mehgazone'
|
||||
extClass = '.Mehgazone'
|
||||
extVersionCode = 1
|
||||
isNsfw = true
|
||||
}
|
||||
|
||||
apply from: "$rootDir/common.gradle"
|
BIN
src/en/mehgazone/res/mipmap-hdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 9.1 KiB |
BIN
src/en/mehgazone/res/mipmap-mdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 4.4 KiB |
BIN
src/en/mehgazone/res/mipmap-xhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
src/en/mehgazone/res/mipmap-xxhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 29 KiB |
BIN
src/en/mehgazone/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 47 KiB |
@ -0,0 +1,330 @@
|
||||
package eu.kanade.tachiyomi.extension.en.mehgazone
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import android.text.InputType
|
||||
import android.text.SpannableString
|
||||
import android.text.method.LinkMovementMethod
|
||||
import android.text.util.Linkify
|
||||
import android.util.Log
|
||||
import android.view.ViewGroup
|
||||
import android.widget.EditText
|
||||
import android.widget.TextView
|
||||
import androidx.preference.EditTextPreference
|
||||
import androidx.preference.PreferenceScreen
|
||||
import eu.kanade.tachiyomi.extension.en.mehgazone.interceptors.BasicAuthInterceptor
|
||||
import eu.kanade.tachiyomi.extension.en.mehgazone.serialization.ChapterListDto
|
||||
import eu.kanade.tachiyomi.extension.en.mehgazone.serialization.PageListDto
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.source.ConfigurableSource
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||
import eu.kanade.tachiyomi.source.model.Page
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import keiyoushi.utils.getPreferencesLazy
|
||||
import keiyoushi.utils.parseAs
|
||||
import keiyoushi.utils.tryParse
|
||||
import okhttp3.Headers
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import org.jsoup.Jsoup
|
||||
import org.jsoup.helper.Validate
|
||||
import org.jsoup.nodes.Element
|
||||
import org.jsoup.parser.Parser.unescapeEntities
|
||||
import org.jsoup.select.Collector
|
||||
import org.jsoup.select.Elements
|
||||
import org.jsoup.select.QueryParser
|
||||
import rx.Observable
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
|
||||
class Mehgazone : ConfigurableSource, HttpSource() {
|
||||
|
||||
override val name = "Mehgazone"
|
||||
|
||||
override val baseUrl = "https://mehgazone.com"
|
||||
|
||||
override val lang = "en"
|
||||
|
||||
override val supportsLatest = false
|
||||
|
||||
override val client: OkHttpClient by lazy {
|
||||
network.cloudflareClient
|
||||
.newBuilder()
|
||||
.addInterceptor(authInterceptor)
|
||||
.build()
|
||||
}
|
||||
|
||||
private val uploadDateFormat: SimpleDateFormat by lazy {
|
||||
SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.US)
|
||||
}
|
||||
|
||||
private val textToImageURL = "https://fakeimg.ryd.tools/1500x2126/ffffff/000000/?font=museo&font_size=42".toHttpUrl()
|
||||
|
||||
private fun String.image() = textToImageURL.newBuilder().setQueryParameter("text", this).build().toString()
|
||||
|
||||
private fun String.unescape() = unescapeEntities(this, false)
|
||||
|
||||
private fun String.linkify() = SpannableString(this).apply { Linkify.addLinks(this, Linkify.WEB_URLS) }
|
||||
|
||||
override fun popularMangaRequest(page: Int) = GET(baseUrl, headers)
|
||||
|
||||
override fun getMangaUrl(manga: SManga) = manga.url
|
||||
|
||||
private fun Elements.selectFirstBackport(cssQuery: String) = selectFirst(cssQuery, this)
|
||||
|
||||
// backport from jsoup 1.19.1
|
||||
private fun selectFirst(cssQuery: String, roots: Elements): Element? {
|
||||
Validate.notEmpty(cssQuery)
|
||||
Validate.notNull(roots)
|
||||
val evaluator = QueryParser.parse(cssQuery)
|
||||
|
||||
for (root in roots) {
|
||||
val first = Collector.findFirst(evaluator, root)
|
||||
if (first != null) return first
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
override fun popularMangaParse(response: Response) = MangasPage(
|
||||
response.asJsoup()
|
||||
.selectFirst("#main aside.primary-sidebar .sidebar-group")!!
|
||||
.select("h2")
|
||||
.filter { el -> el.text().contains("Latest", true) }
|
||||
.map {
|
||||
SManga.create().apply {
|
||||
title = it.text().split('"')[1].unescape()
|
||||
url = it.nextElementSiblings().selectFirstBackport("a[href*='/feed']")!!.attr("href").toHttpUrl().resolve("/").toString()
|
||||
thumbnail_url = it.nextElementSiblings().selectFirstBackport("img")!!.attr("src")
|
||||
}
|
||||
},
|
||||
false,
|
||||
)
|
||||
|
||||
override fun mangaDetailsRequest(manga: SManga) =
|
||||
GET(manga.url, headers)
|
||||
|
||||
override fun mangaDetailsParse(response: Response): SManga = SManga.create().apply {
|
||||
val html = response.asJsoup()
|
||||
val thumbnailRegex = Regex("/[^/]+-([0-9]+\\.png)\$", RegexOption.IGNORE_CASE)
|
||||
|
||||
title = html.head().selectFirst("title")!!.text().unescape()
|
||||
url = response.request.url.toString()
|
||||
author = "Patricia Barton"
|
||||
status = SManga.ONGOING
|
||||
thumbnail_url =
|
||||
html.select("#content img[src*='.png']")
|
||||
.firstOrNull { it.attr("src").matches(thumbnailRegex) }
|
||||
?.attr("src")
|
||||
?.replace(thumbnailRegex, "/\$1")
|
||||
}
|
||||
|
||||
override fun chapterListRequest(manga: SManga): Request = chapterListRequest(manga.url, 1)
|
||||
|
||||
private fun chapterListRequest(url: String, page: Int): Request =
|
||||
GET(
|
||||
"$url/wp-json/wp/v2/posts?per_page=100&page=$page&_fields=id,title,date_gmt,excerpt",
|
||||
headers,
|
||||
)
|
||||
|
||||
private fun hasNextPage(headers: Headers, responseSize: Int, page: Int): Boolean {
|
||||
val pages = headers["X-Wp-Totalpages"]?.toInt()
|
||||
?: return responseSize == 100
|
||||
return page < pages
|
||||
}
|
||||
|
||||
override fun getChapterUrl(chapter: SChapter): String = chapter.url
|
||||
|
||||
override fun chapterListParse(response: Response): List<SChapter> {
|
||||
val apiResponse = response.parseAs<List<ChapterListDto>>().toMutableList()
|
||||
val mangaUrl = response.request.url.toString().substringBefore("/wp-json/")
|
||||
|
||||
if (hasNextPage(response.headers, apiResponse.size, 1)) {
|
||||
var page = 1
|
||||
do {
|
||||
page++
|
||||
val tempResponse = client.newCall(chapterListRequest(mangaUrl, page)).execute()
|
||||
val headers = tempResponse.headers
|
||||
val tempApiResponse = tempResponse.parseAs<List<ChapterListDto>>()
|
||||
|
||||
apiResponse.addAll(tempApiResponse)
|
||||
tempResponse.close()
|
||||
} while (hasNextPage(headers, tempApiResponse.size, page))
|
||||
}
|
||||
|
||||
return apiResponse
|
||||
.filter { !it.excerpt.rendered.contains("Unlock with Patreon") }
|
||||
.distinctBy { it.id }
|
||||
.sortedBy { it.date }
|
||||
.mapIndexed { i, it ->
|
||||
SChapter.create().apply {
|
||||
url = "$mangaUrl/?p=${it.id}"
|
||||
name = it.title.rendered.unescape()
|
||||
.ifEmpty { it.date.substringBefore('T') }
|
||||
date_upload = uploadDateFormat.tryParse(it.date)
|
||||
chapter_number = i.toFloat()
|
||||
}
|
||||
}.reversed()
|
||||
}
|
||||
|
||||
// Adapted from the xkcd source's wordWrap function
|
||||
private fun wordWrap(text: String) = buildString {
|
||||
var charCount = 0
|
||||
text.replace('\n', ' ').split(' ').forEach { w ->
|
||||
if (charCount > 25) {
|
||||
append("\n")
|
||||
charCount = 0
|
||||
}
|
||||
append(w).append(' ')
|
||||
charCount += w.length + 1
|
||||
}
|
||||
}
|
||||
|
||||
override fun pageListRequest(chapter: SChapter): Request {
|
||||
val chapterUrl = chapter.url.toHttpUrl()
|
||||
val pageListUrl = chapterUrl
|
||||
.newBuilder("/wp-json/wp/v2/posts?per_page=1&_fields=link,content,excerpt,date,title")!!
|
||||
.setQueryParameter("include", chapterUrl.queryParameter("p"))
|
||||
.build()
|
||||
return GET(pageListUrl.toString(), headers)
|
||||
}
|
||||
|
||||
override fun pageListParse(response: Response): List<Page> {
|
||||
val apiResponse: PageListDto = response.parseAs<List<PageListDto>>().first()
|
||||
|
||||
val content = Jsoup.parseBodyFragment(apiResponse.content.rendered, apiResponse.link)
|
||||
|
||||
val images = content.select("img")
|
||||
.mapIndexed { i, it -> Page(i, "", it.attr("src")) }
|
||||
.toMutableList()
|
||||
|
||||
if (apiResponse.excerpt.rendered.isNotBlank()) {
|
||||
images.add(
|
||||
Page(
|
||||
images.size,
|
||||
"",
|
||||
wordWrap(Jsoup.parseBodyFragment(apiResponse.excerpt.rendered.unescape()).text()).image(),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
return images.toList()
|
||||
}
|
||||
|
||||
private val preferences: SharedPreferences by getPreferencesLazy()
|
||||
|
||||
companion object {
|
||||
private const val WORDPRESS_USERNAME_PREF_KEY = "WORDPRESS_USERNAME"
|
||||
private const val WORDPRESS_USERNAME_PREF_TITLE = "WordPress username"
|
||||
private const val WORDPRESS_USERNAME_PREF_SUMMARY = "The WordPress username"
|
||||
private const val WORDPRESS_USERNAME_PREF_DIALOG = "To see your username:\n\n" +
|
||||
"Go to https://bodysuit23.mehgazone.com/wp-admin/profile.php and you should see your username near the top of the page."
|
||||
private const val WORDPRESS_USERNAME_PREF_DEFAULT_VALUE = ""
|
||||
|
||||
private const val WORDPRESS_APP_PASSWORD_PREF_KEY = "WORDPRESS_APP_PASSWORD"
|
||||
private const val WORDPRESS_APP_PASSWORD_PREF_TITLE = "WordPress app password"
|
||||
private const val WORDPRESS_APP_PASSWORD_PREF_SUMMARY = "The WordPress app password (not your account password)"
|
||||
private const val WORDPRESS_APP_PASSWORD_PREF_DIALOG = "To setup:\n\n" +
|
||||
"Go to https://bodysuit23.mehgazone.com/wp-admin/profile.php and you should be able to create a new app password near the bottom of the page."
|
||||
private const val WORDPRESS_APP_PASSWORD_PREF_DEFAULT_VALUE = ""
|
||||
}
|
||||
|
||||
private val authInterceptor: BasicAuthInterceptor by lazy {
|
||||
BasicAuthInterceptor(
|
||||
preferences.getString(WORDPRESS_USERNAME_PREF_KEY, WORDPRESS_USERNAME_PREF_DEFAULT_VALUE),
|
||||
preferences.getString(WORDPRESS_APP_PASSWORD_PREF_KEY, WORDPRESS_APP_PASSWORD_PREF_DEFAULT_VALUE),
|
||||
)
|
||||
}
|
||||
|
||||
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
||||
EditTextPreference(screen.context).apply {
|
||||
val name = preferences.getString(WORDPRESS_USERNAME_PREF_KEY, WORDPRESS_USERNAME_PREF_DEFAULT_VALUE)!!
|
||||
|
||||
key = WORDPRESS_USERNAME_PREF_KEY
|
||||
title = WORDPRESS_USERNAME_PREF_TITLE
|
||||
dialogMessage = WORDPRESS_USERNAME_PREF_DIALOG.linkify()
|
||||
summary = name.ifBlank { WORDPRESS_USERNAME_PREF_SUMMARY }
|
||||
setDefaultValue(WORDPRESS_USERNAME_PREF_DEFAULT_VALUE)
|
||||
|
||||
setOnBindEditTextListener {
|
||||
getDialogMessageFromEditText(it).let {
|
||||
@Suppress("NestedLambdaShadowedImplicitParameter")
|
||||
if (it == null) {
|
||||
Log.e(name, "Could not find dialog TextView")
|
||||
} else {
|
||||
it.movementMethod = LinkMovementMethod.getInstance()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setOnPreferenceChangeListener { preference, newValue ->
|
||||
authInterceptor.setUser(newValue as String)
|
||||
preference.summary = newValue.ifBlank { WORDPRESS_USERNAME_PREF_SUMMARY }
|
||||
true
|
||||
}
|
||||
}.also(screen::addPreference)
|
||||
|
||||
EditTextPreference(screen.context).apply {
|
||||
val pwd = preferences.getString(WORDPRESS_APP_PASSWORD_PREF_KEY, WORDPRESS_APP_PASSWORD_PREF_DEFAULT_VALUE)!!
|
||||
|
||||
key = WORDPRESS_APP_PASSWORD_PREF_KEY
|
||||
title = WORDPRESS_APP_PASSWORD_PREF_TITLE
|
||||
dialogMessage = WORDPRESS_APP_PASSWORD_PREF_DIALOG.linkify()
|
||||
summary = if (pwd.isBlank()) WORDPRESS_APP_PASSWORD_PREF_SUMMARY else "●".repeat(pwd.length)
|
||||
setDefaultValue(WORDPRESS_APP_PASSWORD_PREF_DEFAULT_VALUE)
|
||||
|
||||
setOnBindEditTextListener {
|
||||
it.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD
|
||||
getDialogMessageFromEditText(it).let {
|
||||
@Suppress("NestedLambdaShadowedImplicitParameter")
|
||||
if (it == null) {
|
||||
Log.e(name, "Could not find dialog TextView")
|
||||
} else {
|
||||
it.movementMethod = LinkMovementMethod.getInstance()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setOnPreferenceChangeListener { preference, newValue ->
|
||||
authInterceptor.setPassword(newValue as String)
|
||||
preference.summary = if (newValue.isBlank()) WORDPRESS_APP_PASSWORD_PREF_SUMMARY else "●".repeat(newValue.length)
|
||||
true
|
||||
}
|
||||
}.also(screen::addPreference)
|
||||
}
|
||||
|
||||
private fun getDialogMessageFromEditText(editText: EditText): TextView? {
|
||||
val parent = editText.parent
|
||||
if (parent !is ViewGroup || parent.childCount == 0) return null
|
||||
|
||||
for (i in 1..parent.childCount) {
|
||||
val child = parent.getChildAt(i - 1)
|
||||
if (child is TextView && child !is EditText) return child
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> =
|
||||
fetchPopularManga(0).map {
|
||||
MangasPage(
|
||||
it.mangas.filter { m -> m.title.contains(query) },
|
||||
false,
|
||||
)
|
||||
}
|
||||
|
||||
override fun imageUrlParse(response: Response): String = throw UnsupportedOperationException()
|
||||
|
||||
override fun latestUpdatesRequest(page: Int): Request = throw UnsupportedOperationException()
|
||||
|
||||
override fun latestUpdatesParse(response: Response): MangasPage = throw UnsupportedOperationException()
|
||||
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request = throw UnsupportedOperationException()
|
||||
|
||||
override fun searchMangaParse(response: Response): MangasPage = throw UnsupportedOperationException()
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package eu.kanade.tachiyomi.extension.en.mehgazone.interceptors
|
||||
|
||||
import okhttp3.Credentials
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.Response
|
||||
|
||||
class BasicAuthInterceptor(private var user: String?, private var password: String?) : Interceptor {
|
||||
fun setUser(user: String?) {
|
||||
setAuth(user, password)
|
||||
}
|
||||
|
||||
fun setPassword(password: String?) {
|
||||
setAuth(user, password)
|
||||
}
|
||||
|
||||
fun setAuth(user: String?, password: String?) {
|
||||
this.user = user
|
||||
this.password = password
|
||||
credentials = getCredentials()
|
||||
}
|
||||
|
||||
private fun getCredentials(): String? =
|
||||
if (!user.isNullOrBlank() && !password.isNullOrBlank()) {
|
||||
Credentials.basic(user!!, password!!)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
private var credentials: String? = getCredentials()
|
||||
|
||||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
val request = chain.request()
|
||||
|
||||
if (
|
||||
!request.url.encodedPath.contains("/wp-json/wp/v2/") ||
|
||||
user.isNullOrBlank() ||
|
||||
password.isNullOrBlank() ||
|
||||
credentials.isNullOrBlank()
|
||||
) {
|
||||
return chain.proceed(request)
|
||||
}
|
||||
|
||||
val authenticatedRequest = request.newBuilder()
|
||||
.header("Authorization", credentials!!)
|
||||
.build()
|
||||
|
||||
return chain.proceed(authenticatedRequest)
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package eu.kanade.tachiyomi.extension.en.mehgazone.serialization
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
class ChapterListDto(
|
||||
val id: Int,
|
||||
@SerialName("date_gmt")
|
||||
val date: String,
|
||||
val title: RenderedDto,
|
||||
val excerpt: RenderedDto,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
class PageListDto(
|
||||
val link: String,
|
||||
val content: RenderedDto,
|
||||
val excerpt: RenderedDto,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
class RenderedDto(
|
||||
val rendered: String,
|
||||
)
|