diff --git a/src/ko/mangashowme/AndroidManifest.xml b/src/ko/mangashowme/AndroidManifest.xml
new file mode 100644
index 000000000..6bb3d95eb
--- /dev/null
+++ b/src/ko/mangashowme/AndroidManifest.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/ko/mangashowme/build.gradle b/src/ko/mangashowme/build.gradle
index 3d80f77bf..f5f5bdc4b 100644
--- a/src/ko/mangashowme/build.gradle
+++ b/src/ko/mangashowme/build.gradle
@@ -5,7 +5,7 @@ ext {
appName = 'Tachiyomi: ManaMoa'
pkgNameSuffix = 'ko.mangashowme'
extClass = '.ManaMoa'
- extVersionCode = 18
+ extVersionCode = 19
libVersion = '1.2'
}
diff --git a/src/ko/mangashowme/src/eu/kanade/tachiyomi/extension/ko/mangashowme/MNCDNUrlHandler.kt b/src/ko/mangashowme/src/eu/kanade/tachiyomi/extension/ko/mangashowme/MMCDNUrlHandler.kt
similarity index 100%
rename from src/ko/mangashowme/src/eu/kanade/tachiyomi/extension/ko/mangashowme/MNCDNUrlHandler.kt
rename to src/ko/mangashowme/src/eu/kanade/tachiyomi/extension/ko/mangashowme/MMCDNUrlHandler.kt
diff --git a/src/ko/mangashowme/src/eu/kanade/tachiyomi/extension/ko/mangashowme/MSMFilters.kt b/src/ko/mangashowme/src/eu/kanade/tachiyomi/extension/ko/mangashowme/MMFilters.kt
similarity index 54%
rename from src/ko/mangashowme/src/eu/kanade/tachiyomi/extension/ko/mangashowme/MSMFilters.kt
rename to src/ko/mangashowme/src/eu/kanade/tachiyomi/extension/ko/mangashowme/MMFilters.kt
index 49942106c..2cebe7cb9 100644
--- a/src/ko/mangashowme/src/eu/kanade/tachiyomi/extension/ko/mangashowme/MSMFilters.kt
+++ b/src/ko/mangashowme/src/eu/kanade/tachiyomi/extension/ko/mangashowme/MMFilters.kt
@@ -13,88 +13,100 @@ 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("Match", arrayOf("AND", "OR"))
+private class SearchType : Filter.Select("Type", arrayOf("Title", "Artist"))
private class SearchGenresList(genres: List) : Filter.Group("Genres", genres)
private class SearchNamingList : Filter.Select("Naming", searchNaming())
private class SearchStatusList : Filter.Select("Status", searchStatus())
+private class SearchOrderList : Filter.Select("Order", order())
+
// [`"Not Set"`, ...[...document.querySelectorAll(".categories ul[data-type='1'] li")].map((el, i) => `"${el.innerText.trim()}"`)].join(',\n')
private fun searchNaming() = arrayOf(
- "Not Set",
- "ㄱ",
- "ㄲ",
- "ㄴ",
- "ㄷ",
- "ㄸ",
- "ㄹ",
- "ㅁ",
- "ㅂ",
- "ㅃ",
- "ㅅ",
- "ㅆ",
- "ㅇ",
- "ㅈ",
- "ㅉ",
- "ㅊ",
- "ㅋ",
- "ㅌ",
- "ㅍ",
- "ㅎ",
- "A-Z",
- "0-9"
+ "Not Set",
+ "ㄱ",
+ "ㄲ",
+ "ㄴ",
+ "ㄷ",
+ "ㄸ",
+ "ㄹ",
+ "ㅁ",
+ "ㅂ",
+ "ㅃ",
+ "ㅅ",
+ "ㅆ",
+ "ㅇ",
+ "ㅈ",
+ "ㅉ",
+ "ㅊ",
+ "ㅋ",
+ "ㅌ",
+ "ㅍ",
+ "ㅎ",
+ "A-Z",
+ "0-9"
)
// [`"Not Set"`, ...[...document.querySelectorAll(".categories ul[data-type='2'] li")].map((el, i) => `"${el.innerText.trim()}"`)].join(',\n')
private fun searchStatus() = arrayOf(
- "Not Set",
- "주간",
- "격주",
- "월간",
- "격월/비정기",
- "단편",
- "단행본",
- "완결"
+ "Not Set",
+ "주간",
+ "격주",
+ "월간",
+ "격월/비정기",
+ "단편",
+ "단행본",
+ "완결"
+)
+
+// [...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"),
- SearchCheckBox("BL"),
- SearchCheckBox("SF"),
- SearchCheckBox("TS"),
- SearchCheckBox("개그"),
- SearchCheckBox("게임"),
- SearchCheckBox("공포"),
- SearchCheckBox("도박"),
- SearchCheckBox("드라마"),
- SearchCheckBox("라노벨"),
- SearchCheckBox("러브코미디"),
- SearchCheckBox("먹방"),
- SearchCheckBox("백합"),
- SearchCheckBox("붕탁"),
- SearchCheckBox("순정"),
- SearchCheckBox("스릴러"),
- SearchCheckBox("스포츠"),
- SearchCheckBox("시대"),
- SearchCheckBox("애니화"),
- SearchCheckBox("액션"),
- SearchCheckBox("음악"),
- SearchCheckBox("이세계"),
- SearchCheckBox("일상"),
- SearchCheckBox("전생"),
- SearchCheckBox("추리"),
- SearchCheckBox("판타지"),
- SearchCheckBox("학원"),
- SearchCheckBox("호러")
+ SearchCheckBox("17"),
+ SearchCheckBox("BL"),
+ SearchCheckBox("SF"),
+ SearchCheckBox("TS"),
+ SearchCheckBox("개그"),
+ SearchCheckBox("게임"),
+ SearchCheckBox("공포"),
+ SearchCheckBox("도박"),
+ SearchCheckBox("드라마"),
+ SearchCheckBox("라노벨"),
+ SearchCheckBox("러브코미디"),
+ SearchCheckBox("먹방"),
+ SearchCheckBox("백합"),
+ SearchCheckBox("붕탁"),
+ SearchCheckBox("순정"),
+ SearchCheckBox("스릴러"),
+ SearchCheckBox("스포츠"),
+ SearchCheckBox("시대"),
+ SearchCheckBox("애니화"),
+ SearchCheckBox("액션"),
+ SearchCheckBox("음악"),
+ SearchCheckBox("이세계"),
+ SearchCheckBox("일상"),
+ SearchCheckBox("전생"),
+ SearchCheckBox("추리"),
+ SearchCheckBox("판타지"),
+ SearchCheckBox("학원"),
+ SearchCheckBox("호러")
)
fun getFilters() = FilterList(
- SearchNamingList(),
- SearchStatusList(),
- SearchGenresList(searchGenres()),
- Filter.Separator(),
- SearchMatch(),
- Filter.Separator(),
- TextField("Author/Artist (Exact search)", "author")
+ SearchNamingList(),
+ SearchStatusList(),
+ SearchGenresList(searchGenres()),
+ Filter.Separator(),
+ SearchType(),
+ SearchMatch(),
+ 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()
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}")
}
diff --git a/src/ko/mangashowme/src/eu/kanade/tachiyomi/extension/ko/mangashowme/MSMImageDecoder.kt b/src/ko/mangashowme/src/eu/kanade/tachiyomi/extension/ko/mangashowme/MMImageDecoder.kt
similarity index 95%
rename from src/ko/mangashowme/src/eu/kanade/tachiyomi/extension/ko/mangashowme/MSMImageDecoder.kt
rename to src/ko/mangashowme/src/eu/kanade/tachiyomi/extension/ko/mangashowme/MMImageDecoder.kt
index e00d7cee6..007d428c2 100644
--- a/src/ko/mangashowme/src/eu/kanade/tachiyomi/extension/ko/mangashowme/MSMImageDecoder.kt
+++ b/src/ko/mangashowme/src/eu/kanade/tachiyomi/extension/ko/mangashowme/MMImageDecoder.kt
@@ -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")
diff --git a/src/ko/mangashowme/src/eu/kanade/tachiyomi/extension/ko/mangashowme/MSMImageUrlHandler.kt b/src/ko/mangashowme/src/eu/kanade/tachiyomi/extension/ko/mangashowme/MMmageUrlHandler.kt
similarity index 100%
rename from src/ko/mangashowme/src/eu/kanade/tachiyomi/extension/ko/mangashowme/MSMImageUrlHandler.kt
rename to src/ko/mangashowme/src/eu/kanade/tachiyomi/extension/ko/mangashowme/MMmageUrlHandler.kt
diff --git a/src/ko/mangashowme/src/eu/kanade/tachiyomi/extension/ko/mangashowme/MangaShowMe.kt b/src/ko/mangashowme/src/eu/kanade/tachiyomi/extension/ko/mangashowme/ManaMoa.kt
similarity index 78%
rename from src/ko/mangashowme/src/eu/kanade/tachiyomi/extension/ko/mangashowme/MangaShowMe.kt
rename to src/ko/mangashowme/src/eu/kanade/tachiyomi/extension/ko/mangashowme/ManaMoa.kt
index 0c241b57d..712743f60 100644
--- a/src/ko/mangashowme/src/eu/kanade/tachiyomi/extension/ko/mangashowme/MangaShowMe.kt
+++ b/src/ko/mangashowme/src/eu/kanade/tachiyomi/extension/ko/mangashowme/ManaMoa.kt
@@ -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,19 +46,21 @@ 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)
- .addInterceptor(ImageDecoderInterceptor())
- .addInterceptor(ImageUrlHandlerInterceptor())
- .build()!!
+ .connectTimeout(10, TimeUnit.SECONDS)
+ .readTimeout(30, TimeUnit.SECONDS)
+ .addInterceptor(ImageDecoderInterceptor())
+ .addInterceptor(ImageUrlHandlerInterceptor())
+ .build()!!
override fun popularMangaSelector() = "div.manga-list-gallery > div > div.post-row"
@@ -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 {
+ 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:"
}
}
diff --git a/src/ko/mangashowme/src/eu/kanade/tachiyomi/extension/ko/mangashowme/ManaMoaUrlActivity.kt b/src/ko/mangashowme/src/eu/kanade/tachiyomi/extension/ko/mangashowme/ManaMoaUrlActivity.kt
new file mode 100644
index 000000000..d1e3ef40c
--- /dev/null
+++ b/src/ko/mangashowme/src/eu/kanade/tachiyomi/extension/ko/mangashowme/ManaMoaUrlActivity.kt
@@ -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)
+ }
+
+}