Update Manamoa Extension (#2289)

* Search Update

* Update BaseUrl

* Manga ID Access + Url Activity

* Fix Url Activity

* Fix Filter Request

* Bump up version [*Not ready to release]

* Fix details parser bug by previous site changes.

Didn't find cuz title is keep used from searched result

* Remove Log.d

* Experiment latest fetch

* Rename filename from MSM(MangaShowMe) to MM(ManaMoa)

* Enable Latest Pagination

Site error is render failure from server, which is quite interesting. But If fails, there's no pagination shows so enabled.

* Update BaseUrl
This commit is contained in:
DitFranXX 2020-02-27 20:52:15 +09:00 committed by GitHub
parent a780a18058
commit 33749811cb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 272 additions and 94 deletions

View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<activity
android:name=".ManaMoaUrlActivity"
android:theme="@android:style/Theme.NoDisplay"
android:excludeFromRecents="true">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<!-- Current domain -->
<data
android:scheme="https"
android:host="manamoa28.net"
android:pathPattern="/bbs/page.php"/>
<!-- Future domains -->
<data
android:scheme="https"
android:host="manamoa29.net"
android:pathPattern="/bbs/page.php"/>
<data
android:scheme="https"
android:host="manamoa30.net"
android:pathPattern="/bbs/page.php"/>
<data
android:scheme="https"
android:host="manamoa31.net"
android:pathPattern="/bbs/page.php"/>
<data
android:scheme="https"
android:host="manamoa32.net"
android:pathPattern="/bbs/page.php"/>
</intent-filter>
</activity>
</application>
</manifest>

View File

@ -5,7 +5,7 @@ ext {
appName = 'Tachiyomi: ManaMoa'
pkgNameSuffix = 'ko.mangashowme'
extClass = '.ManaMoa'
extVersionCode = 18
extVersionCode = 19
libVersion = '1.2'
}

View File

@ -13,9 +13,12 @@ private class TextField(name: String, val key: String) : Filter.Text(name)
private class SearchCheckBox(name: String, val id: String = name) : Filter.CheckBox(name)
private class SearchMatch : Filter.Select<String>("Match", arrayOf("AND", "OR"))
private class SearchType : Filter.Select<String>("Type", arrayOf("Title", "Artist"))
private class SearchGenresList(genres: List<SearchCheckBox>) : Filter.Group<SearchCheckBox>("Genres", genres)
private class SearchNamingList : Filter.Select<String>("Naming", searchNaming())
private class SearchStatusList : Filter.Select<String>("Status", searchStatus())
private class SearchOrderList : Filter.Select<String>("Order", order())
// [`"Not Set"`, ...[...document.querySelectorAll(".categories ul[data-type='1'] li")].map((el, i) => `"${el.innerText.trim()}"`)].join(',\n')
private fun searchNaming() = arrayOf(
@ -55,6 +58,15 @@ private fun searchStatus() = arrayOf(
"완결"
)
// [...document.querySelectorAll(".categories ul[data-type='2'] li")].map((el, i) => `"${el.innerText.trim()}"`).join(',\n')
private fun order() = arrayOf(
"Recent",
"Likes",
"Popular",
"Comments",
"Bookmarks"
)
// [...document.querySelectorAll(".categories ul[data-type='3'] li")].map((el, i) => `SearchCheckBox("${el.innerText.trim()}")`).join(',\n')
private fun searchGenres() = listOf(
SearchCheckBox("17"),
@ -92,9 +104,9 @@ fun getFilters() = FilterList(
SearchStatusList(),
SearchGenresList(searchGenres()),
Filter.Separator(),
SearchType(),
SearchMatch(),
Filter.Separator(),
TextField("Author/Artist (Exact search)", "author")
SearchOrderList()
)
fun searchComplexFilterMangaRequestBuilder(baseUrl: String, page: Int, query: String, filters: FilterList): Request {
@ -102,7 +114,8 @@ fun searchComplexFilterMangaRequestBuilder(baseUrl: String, page: Int, query: St
var statusFilter: Int? = null
val genresFilter = mutableListOf<String>()
var matchFilter = 1
var authorFilter: String? = null
var orderFilter = 0
var typeFilter = 0
filters.forEach { filter ->
when (filter) {
@ -110,20 +123,14 @@ fun searchComplexFilterMangaRequestBuilder(baseUrl: String, page: Int, query: St
matchFilter = filter.state + 1
}
is TextField -> {
if (filter.key == "author" && filter.state.isNotEmpty()) {
authorFilter = filter.state
}
}
}
is SearchOrderList -> {
orderFilter = filter.state
}
if (!authorFilter.isNullOrEmpty()) {
return GET("$baseUrl/bbs/page.php?hid=manga_list&sfl=4&stx=$authorFilter&page=${page - 1}")
is SearchType -> {
typeFilter = arrayOf(0, 5)[filter.state]
}
filters.forEach { filter ->
when (filter) {
is SearchNamingList -> {
if (filter.state > 0) {
nameFilter = filter.state - 1
@ -146,16 +153,26 @@ fun searchComplexFilterMangaRequestBuilder(baseUrl: String, page: Int, query: St
}
}
if (query.isEmpty() && nameFilter == null && statusFilter == null && genresFilter.isEmpty()) {
return GET("$baseUrl/bbs/page.php?hid=manga_list")
/*
if (!authorFilter.isNullOrEmpty()) {
Log.println(Log.DEBUG, "TACHI REQUEST", "ARTIST REQU")
return GET("$baseUrl/bbs/page.php?hid=manga_list&search_type=1&sfl=5&_0=$authorFilter&_1=&_2=&_3=&_4=$orderFilter")
}
*/
if (query.isEmpty() && nameFilter == null && statusFilter == null && orderFilter == 0 && matchFilter == 1 && genresFilter.isEmpty()) {
return GET("$baseUrl/bbs/page.php?hid=manga_list" +
if (page > 1) "&page=${page - 1}" else "")
}
val url = HttpUrl.parse("$baseUrl/bbs/page.php?hid=manga_list")!!.newBuilder()
url.addQueryParameter("search_type", matchFilter.toString())
url.addQueryParameter("sfl", typeFilter.toString())
url.addQueryParameter("_0", query)
url.addQueryParameter("_1", nameFilter?.toString() ?: "")
url.addQueryParameter("_2", statusFilter?.toString() ?: "")
url.addQueryParameter("_3", genresFilter.joinToString(","))
url.addQueryParameter("_4", orderFilter.toString())
if (page > 1) {
url.addQueryParameter("page", "${page - 1}")
}

View File

@ -38,7 +38,12 @@ internal class ImageDecoder(scripts: String) {
internal class ImageDecoderInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val req = chain.request()
val response = chain.proceed(req)
val newReq = req.newBuilder()!!
.removeHeader("ImageRequest")
.removeHeader("ImageDecodeRequest")
.removeHeader("SecondUrlToRequest")
.build()!!
val response = chain.proceed(newReq)
val decodeHeader = req.header("ImageDecodeRequest")

View File

@ -11,6 +11,7 @@ import android.support.v7.preference.PreferenceScreen
import android.widget.Toast
import eu.kanade.tachiyomi.extension.BuildConfig
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.asObservableSuccess
import eu.kanade.tachiyomi.source.ConfigurableSource
import eu.kanade.tachiyomi.source.model.*
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
@ -20,6 +21,7 @@ import org.json.JSONArray
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import org.jsoup.select.Elements
import rx.Observable
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import java.io.IOException
@ -44,13 +46,15 @@ class ManaMoa : ConfigurableSource, ParsedHttpSource() {
override val name = "ManaMoa"
// This keeps updating: https://twitter.com/manamoa24
private val defaultBaseUrl = "https://manamoa27.net"
private val defaultBaseUrl = "https://manamoa29.net"
override val baseUrl by lazy { getCurrentBaseUrl() }
override val lang: String = "ko"
// Latest updates currently returns duplicate manga as it separates manga into chapters
override val supportsLatest = false
// But allowing to fetch from chapters with experimental setting.
override val supportsLatest by lazy { getExperimentLatest() }
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
@ -97,7 +101,22 @@ class ManaMoa : ConfigurableSource, ParsedHttpSource() {
override fun searchMangaFromElement(element: Element) = popularMangaFromElement(element)
override fun searchMangaNextPageSelector() = popularMangaSelector()
override fun searchMangaParse(response: Response) = popularMangaParse(response)
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request = searchComplexFilterMangaRequestBuilder(baseUrl, page, query, filters)
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
return if (query.startsWith(PREFIX_ID_SEARCH)) {
val realQuery = query.removePrefix(PREFIX_ID_SEARCH)
val urlPath = "/bbs/page.php?hid=manga_detail&manga_id=$realQuery"
client.newCall(GET("$baseUrl$urlPath"))
.asObservableSuccess()
.map { response ->
val details = mangaDetailsParse(response)
details.url = urlPath
MangasPage(listOf(details), false)
}
} else super.fetchSearchManga(page, query, filters)
}
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request =
searchComplexFilterMangaRequestBuilder(baseUrl, page, query, filters)
override fun mangaDetailsParse(document: Document): SManga {
@ -120,7 +139,7 @@ class ManaMoa : ConfigurableSource, ParsedHttpSource() {
}
val manga = SManga.create()
manga.title = info.select("div.red").html()
manga.title = info.select("div.red.title").html().trim()
// They using background-image style tag for cover. extract url from style attribute.
manga.thumbnail_url = urlFinder(thumbnailElement.attr("style"))
manga.description =
@ -259,10 +278,29 @@ class ManaMoa : ConfigurableSource, ParsedHttpSource() {
// Latest not supported
override fun latestUpdatesSelector() = throw UnsupportedOperationException("This method should not be called!")
override fun latestUpdatesFromElement(element: Element) = throw UnsupportedOperationException("This method should not be called!")
override fun latestUpdatesRequest(page: Int) = throw UnsupportedOperationException("This method should not be called!")
override fun latestUpdatesNextPageSelector() = throw UnsupportedOperationException("This method should not be called!")
override fun latestUpdatesSelector() = ".post-row > div.media.post-list"
override fun latestUpdatesFromElement(element: Element): SManga {
val linkElement = element.select("a.btn-primary")
val rawTitle = element.select(".post-subject > a").first().ownText()
// TODO: Make Clear Regex.
val chapterRegex = Regex("""((?:\s+)(?:(?:(?:[0-9]+권)?(?:[0-9]+부)?(?:[0-9]*?시즌[0-9]*?)?)?(?:\s*)(?:(?:[0-9]+)(?:[-.](?:[0-9]+))?)?(?:\s*[~,]\s*)?(?:[0-9]+)(?:[-.](?:[0-9]+))?)(?:화))""")
val title = rawTitle.trim().replace(chapterRegex, "")
//val regexSpecialChapter = Regex("(부록|단편|외전|.+편)")
//val lastTitleWord = excludeChapterTitle.split(" ").last()
//val title = excludeChapterTitle.replace(lastTitleWord, lastTitleWord.replace(regexSpecialChapter, ""))
val manga = SManga.create()
manga.url = linkElement.attr("href")
manga.title = title
manga.thumbnail_url = element.select(".img-item > img").attr("src")
manga.initialized = false
return manga
}
override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/bbs/board.php?bo_table=manga" + if (page > 1) "&page=$page" else "")
override fun latestUpdatesNextPageSelector() = "ul.pagination > li:not(.disabled)"
//We are able to get the image URL directly from the page list
@ -321,8 +359,26 @@ class ManaMoa : ConfigurableSource, ParsedHttpSource() {
}
}
val latestExperimentPref = androidx.preference.CheckBoxPreference(screen.context).apply {
key = EXPERIMENTAL_LATEST_PREF_TITLE
title = EXPERIMENTAL_LATEST_PREF_TITLE
summary = EXPERIMENTAL_LATEST_PREF_SUMMARY
setOnPreferenceChangeListener { _, newValue ->
try {
val res = preferences.edit().putBoolean(EXPERIMENTAL_LATEST_PREF, newValue as Boolean).commit()
Toast.makeText(screen.context, RESTART_TACHIYOMI, Toast.LENGTH_LONG).show()
res
} catch (e: Exception) {
e.printStackTrace()
false
}
}
}
screen.addPreference(baseUrlPref)
screen.addPreference(autoFetchUrlPref)
screen.addPreference(latestExperimentPref)
}
override fun setupPreferenceScreen(screen: PreferenceScreen) {
@ -364,8 +420,26 @@ class ManaMoa : ConfigurableSource, ParsedHttpSource() {
}
}
val latestExperimentPref = CheckBoxPreference(screen.context).apply {
key = EXPERIMENTAL_LATEST_PREF_TITLE
title = EXPERIMENTAL_LATEST_PREF_TITLE
summary = EXPERIMENTAL_LATEST_PREF_SUMMARY
setOnPreferenceChangeListener { _, newValue ->
try {
val res = preferences.edit().putBoolean(EXPERIMENTAL_LATEST_PREF, newValue as Boolean).commit()
Toast.makeText(screen.context, RESTART_TACHIYOMI, Toast.LENGTH_LONG).show()
res
} catch (e: Exception) {
e.printStackTrace()
false
}
}
}
screen.addPreference(baseUrlPref)
screen.addPreference(autoFetchUrlPref)
screen.addPreference(latestExperimentPref)
}
private fun getCurrentBaseUrl(): String {
@ -414,6 +488,7 @@ class ManaMoa : ConfigurableSource, ParsedHttpSource() {
private fun getPrefBaseUrl(): String = preferences.getString(BASE_URL_PREF, defaultBaseUrl)!!
private fun getExperimentLatest(): Boolean = preferences.getBoolean(EXPERIMENTAL_LATEST_PREF, false)
override fun getFilterList() = getFilters()
@ -429,6 +504,11 @@ class ManaMoa : ConfigurableSource, ParsedHttpSource() {
"Experimental, May cause Tachiyomi *very* unstable.\n" +
"Requires Android Oreo or newer."
// Setting: Experimental Latest Fetcher
private const val EXPERIMENTAL_LATEST_PREF_TITLE = "Enable Latest (Experimental)"
private const val EXPERIMENTAL_LATEST_PREF = "fetchLatestExperiment"
private const val EXPERIMENTAL_LATEST_PREF_SUMMARY = "Fetch Latest Manga using Latest Chapters. May has duplicates or invalid name."
private const val RESTART_TACHIYOMI = "Restart Tachiyomi to apply new setting."
// Image Decoder
@ -437,5 +517,8 @@ class ManaMoa : ConfigurableSource, ParsedHttpSource() {
// Url Handler
internal const val MINIMUM_IMAGE_SIZE = 10000
// Activity Url Handler
const val PREFIX_ID_SEARCH = "id:"
}
}

View File

@ -0,0 +1,35 @@
package eu.kanade.tachiyomi.extension.ko.mangashowme
import android.app.Activity
import android.content.ActivityNotFoundException
import android.content.Intent
import android.os.Bundle
import android.util.Log
import kotlin.system.exitProcess
class ManaMoaUrlActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val titleid = intent?.data?.getQueryParameter("manga_id")
if (titleid != null && titleid.toInt() > 1) {
val mainIntent = Intent().apply {
action = "eu.kanade.tachiyomi.SEARCH"
putExtra("query", "${ManaMoa.PREFIX_ID_SEARCH}$titleid")
putExtra("filter", packageName)
}
try {
startActivity(mainIntent)
} catch (e: ActivityNotFoundException) {
Log.e("ManaMoaUrlActivity", e.toString())
}
} else {
Log.e("ManaMoaUrlActivity", "could not parse uri from intent $intent")
}
finish()
exitProcess(0)
}
}