Update MSM Extension. (#1061)

* Improve Preference-stub

* Re-arrange some stubs to correct class.
* Add `EditTextPreference`.

* Update MSM extension.

* Update filter.
* Fix image fetch due to site changes (v4 -> v11)
* Add BaseUrl Override for site domain changes.
  - Korean sources are change domain every 1-2 weeks due to internet censorship.

* Add missing file `EditTextPreference.java`

* Fix tags.
This commit is contained in:
DitFranXX 2019-04-27 23:40:07 +09:00 committed by Eugene
parent 47e9e9389d
commit 9105f9aef8
7 changed files with 186 additions and 74 deletions

View File

@ -4,4 +4,20 @@ package android.support.v7.preference;
* Created by Carlos on 5/9/2018. * Created by Carlos on 5/9/2018.
*/ */
public abstract class DialogPreference extends Preference {} public abstract class DialogPreference extends Preference {
public CharSequence getDialogTitle() {
throw new RuntimeException("Stub!");
}
public void setDialogTitle(CharSequence dialogTitle) {
throw new RuntimeException("Stub!");
}
public CharSequence getDialogMessage() {
throw new RuntimeException("Stub!");
}
public void setDialogMessage(CharSequence dialogMessage) {
throw new RuntimeException("Stub!");
}
}

View File

@ -0,0 +1,17 @@
package android.support.v7.preference;
import android.content.Context;
public class EditTextPreference extends DialogPreference {
public EditTextPreference(Context context) {
throw new RuntimeException("Stub!");
}
public String getText() {
throw new RuntimeException("Stub!");
}
public void setText(String text) {
throw new RuntimeException("Stub!");
}
}

View File

@ -12,27 +12,12 @@ public class ListPreference extends Preference {
throw new RuntimeException("Stub!"); throw new RuntimeException("Stub!");
} }
public CharSequence getTitle() {
throw new RuntimeException("Stub!");
}
public void setTitle(CharSequence title) {
throw new RuntimeException("Stub!");
}
public void setEntries(CharSequence[] entries) { public void setEntries(CharSequence[] entries) {
throw new RuntimeException("Stub!"); throw new RuntimeException("Stub!");
} }
public CharSequence[] getEntries() { public CharSequence[] getEntries() {
throw new RuntimeException("Stub!"); throw new RuntimeException("Stub!");
}
public void setOnPreferenceChangeListener(OnPreferenceChangeListener onPreferenceChangeListener) {
throw new RuntimeException("Stub!");
} }
public int findIndexOfValue(String value) { public int findIndexOfValue(String value) {
@ -58,12 +43,4 @@ public class ListPreference extends Preference {
public void setValue(String value) { public void setValue(String value) {
throw new RuntimeException("Stub!"); throw new RuntimeException("Stub!");
} }
public void setSummary(CharSequence summary) {
throw new RuntimeException("Stub!");
}
public CharSequence getSummary() {
throw new RuntimeException("Stub!");
}
} }

View File

@ -9,6 +9,26 @@ public class Preference {
boolean onPreferenceChange(Preference preference, Object newValue); boolean onPreferenceChange(Preference preference, Object newValue);
} }
public void setOnPreferenceChangeListener(OnPreferenceChangeListener onPreferenceChangeListener) {
throw new RuntimeException("Stub!");
}
public void setOnPreferenceClickListener(OnPreferenceClickListener onPreferenceClickListener) {
throw new RuntimeException("Stub!");
}
public CharSequence getTitle() {
throw new RuntimeException("Stub!");
}
public void setTitle(CharSequence title) {
throw new RuntimeException("Stub!");
}
public CharSequence getSummary() {
throw new RuntimeException("Stub!");
}
public void setKey(String key) { public void setKey(String key) {
throw new RuntimeException("Stub!"); throw new RuntimeException("Stub!");
} }
@ -16,4 +36,16 @@ public class Preference {
public String getKey() { public String getKey() {
throw new RuntimeException("Stub!"); throw new RuntimeException("Stub!");
} }
public void setSummary(CharSequence summary) {
throw new RuntimeException("Stub!");
}
public void setDefaultValue(Object defaultValue) {
throw new RuntimeException("Stub!");
}
public interface OnPreferenceClickListener {
boolean onPreferenceClick(Preference preference);
}
} }

View File

@ -5,8 +5,13 @@ ext {
appName = 'Tachiyomi: MangaShow.Me (ManaMoa)' appName = 'Tachiyomi: MangaShow.Me (ManaMoa)'
pkgNameSuffix = 'ko.mangashowme' pkgNameSuffix = 'ko.mangashowme'
extClass = '.MangaShowMe' extClass = '.MangaShowMe'
extVersionCode = 10 extVersionCode = 11
libVersion = '1.2' libVersion = '1.2'
} }
dependencies {
compileOnly project(':preference-stub')
compileOnly 'com.github.inorichi.injekt:injekt-core:65b0440'
}
apply from: "$rootDir/common.gradle" apply from: "$rootDir/common.gradle"

View File

@ -9,13 +9,15 @@ import okhttp3.Request
// TODO: Completely Implement/Update Filters(Genre/Artist). // TODO: Completely Implement/Update Filters(Genre/Artist).
private class TextField(name: String, val key: String) : Filter.Text(name) private class TextField(name: String, val key: String) : Filter.Text(name)
private class SearchCheckBox(val id: Int, name: String) : Filter.CheckBox(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 SearchMatch : Filter.Select<String>("Match", arrayOf("AND", "OR"))
private class SearchGenresList(genres: List<SearchCheckBox>) : Filter.Group<SearchCheckBox>("Genres", genres) private class SearchGenresList(genres: List<SearchCheckBox>) : Filter.Group<SearchCheckBox>("Genres", genres)
private class SearchNamingList : Filter.Select<String>("Naming", searchNaming()) private class SearchNamingList : Filter.Select<String>("Naming", searchNaming())
private class SearchStatusList : Filter.Select<String>("Status", searchStatus()) private class SearchStatusList : Filter.Select<String>("Status", searchStatus())
// [`"Not Set"`, ...[...document.querySelectorAll(".categories ul[data-type='1'] li")].map((el, i) => `"${el.innerText.trim()}"`)].join(',\n')
private fun searchNaming() = arrayOf( private fun searchNaming() = arrayOf(
"Not Set", "Not Set",
"", "",
@ -41,6 +43,7 @@ private fun searchNaming() = arrayOf(
"0-9" "0-9"
) )
// [`"Not Set"`, ...[...document.querySelectorAll(".categories ul[data-type='2'] li")].map((el, i) => `"${el.innerText.trim()}"`)].join(',\n')
private fun searchStatus() = arrayOf( private fun searchStatus() = arrayOf(
"Not Set", "Not Set",
"주간", "주간",
@ -52,36 +55,36 @@ private fun searchStatus() = arrayOf(
"완결" "완결"
) )
// [...document.querySelectorAll(".categories ul[data-type='3'] li")].map((el, i) => `SearchCheckBox("${el.innerText.trim()}")`).join(',\n')
private fun searchGenres() = listOf( private fun searchGenres() = listOf(
SearchCheckBox(0, "17"), SearchCheckBox("17"),
SearchCheckBox(0, "BL"), SearchCheckBox("BL"),
SearchCheckBox(0, "SF"), SearchCheckBox("SF"),
SearchCheckBox(0, "TS"), SearchCheckBox("TS"),
SearchCheckBox(0, "개그"), SearchCheckBox("개그"),
SearchCheckBox(0, "게임"), SearchCheckBox("게임"),
SearchCheckBox(0, "공포"), SearchCheckBox("공포"),
SearchCheckBox(0, "도박"), SearchCheckBox("도박"),
SearchCheckBox(0, "드라마"), SearchCheckBox("드라마"),
SearchCheckBox(0, "라노벨"), SearchCheckBox("라노벨"),
SearchCheckBox(0, "러브코미디"), SearchCheckBox("러브코미디"),
SearchCheckBox(0, "먹방"), SearchCheckBox("먹방"),
SearchCheckBox(0, "백합"), SearchCheckBox("백합"),
SearchCheckBox(0, "붕탁"), SearchCheckBox("붕탁"),
SearchCheckBox(0, "순정"), SearchCheckBox("순정"),
SearchCheckBox(0, "스릴러"), SearchCheckBox("스릴러"),
SearchCheckBox(0, "스포츠"), SearchCheckBox("스포츠"),
SearchCheckBox(0, "시대"), SearchCheckBox("시대"),
SearchCheckBox(0, "애니화"), SearchCheckBox("애니화"),
SearchCheckBox(0, "액션"), SearchCheckBox("액션"),
SearchCheckBox(0, "역사"), SearchCheckBox("음악"),
SearchCheckBox(0, "음악"), SearchCheckBox("이세계"),
SearchCheckBox(0, "이세계"), SearchCheckBox("일상"),
SearchCheckBox(0, "일상"), SearchCheckBox("전생"),
SearchCheckBox(0, "전생"), SearchCheckBox("추리"),
SearchCheckBox(0, "추리"), SearchCheckBox("판타지"),
SearchCheckBox(0, "판타지"), SearchCheckBox("학원"),
SearchCheckBox(0, "학원"), SearchCheckBox("호러")
SearchCheckBox(0, "호러")
) )
fun getFilters() = FilterList( fun getFilters() = FilterList(
@ -136,7 +139,7 @@ fun searchComplexFilterMangaRequestBuilder(baseUrl: String, page: Int, query: St
is SearchGenresList -> { is SearchGenresList -> {
filter.state.forEach { filter.state.forEach {
if (it.state) { if (it.state) {
genresFilter.add(it.name) genresFilter.add(it.id)
} }
} }
} }

View File

@ -1,7 +1,14 @@
package eu.kanade.tachiyomi.extension.ko.mangashowme package eu.kanade.tachiyomi.extension.ko.mangashowme
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.Application
import android.content.SharedPreferences
import android.support.v7.preference.EditTextPreference
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.GET
import eu.kanade.tachiyomi.source.ConfigurableSource
import eu.kanade.tachiyomi.source.model.* import eu.kanade.tachiyomi.source.model.*
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
@ -12,6 +19,8 @@ import org.json.JSONArray
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import org.jsoup.select.Elements import org.jsoup.select.Elements
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
@ -22,9 +31,10 @@ import java.util.concurrent.TimeUnit
* PS. There's no Popular section. It's just a list of manga. Also not latest updates. * PS. There's no Popular section. It's just a list of manga. Also not latest updates.
* `manga_list` returns latest 'added' manga. not a chapter updates. * `manga_list` returns latest 'added' manga. not a chapter updates.
**/ **/
class MangaShowMe : ParsedHttpSource() { class MangaShowMe : ConfigurableSource, ParsedHttpSource() {
override val name = "MangaShow.Me" override val name = "MangaShow.Me"
override val baseUrl = "https://manamoa2.net" private val defaultBaseUrl = "https://manamoa3.net"
override val baseUrl by lazy { getPrefBaseUrl() }
override val lang: String = "ko" override val lang: String = "ko"
// Latest updates currently returns duplicate manga as it separates manga into chapters // Latest updates currently returns duplicate manga as it separates manga into chapters
@ -37,15 +47,23 @@ class MangaShowMe : ParsedHttpSource() {
val req = chain.request() val req = chain.request()
// only for image Request // only for image Request
if (!req.url().host().contains("filecdn.xyz")) return@addInterceptor chain.proceed(req) val isFileCdn = !req.url().host().contains(".filecdn.xyz")
if (!req.url().toString().endsWith("?quick")) return@addInterceptor chain.proceed(req)
val secondUrl = req.header("SecondUrlToRequest") val secondUrl = req.header("SecondUrlToRequest")
fun get(flag: Int = 0): Request { fun get(flag: Int = 0): Request {
val url = when (flag) { val url = if (isFileCdn) {
1 -> req.url().toString().replace("img.", "s3.") when (flag) {
2 -> secondUrl!! 1 -> req.url().toString().replace("img.", "s3.")
else -> req.url().toString() else -> req.url().toString()
}
} else {
when (flag) {
1 -> secondUrl!!
2 -> secondUrl!!.replace("img.", "s3.")
else -> req.url().toString().substringBefore("?quick")
}
} }
return req.newBuilder()!!.url(url) return req.newBuilder()!!.url(url)
@ -55,13 +73,21 @@ class MangaShowMe : ParsedHttpSource() {
} }
val res = chain.proceed(get()) val res = chain.proceed(get())
val length = res.header("content-length")
if (length == null || length.toInt() < 50000) { if (isFileCdn) {
val s3res = chain.proceed(get(1)) // s3 val length = res.header("content-length")
if (!s3res.isSuccessful && secondUrl != null) { if (length == null || length.toInt() < 50000) {
chain.proceed(get(2)) // secondUrl chain.proceed(get(1)) // s3
} else s3res } else res
} else res } else {
if (!res.isSuccessful && secondUrl != null) {
val fallbackRes = chain.proceed(get(1)) // img filecdn
val fallbackLength = fallbackRes.header("content-length")
if (fallbackLength == null || fallbackLength.toInt() < 50000) {
chain.proceed(get(2)) // s3
} else fallbackRes
} else res
}
} }
.build()!! .build()!!
@ -116,7 +142,7 @@ class MangaShowMe : ParsedHttpSource() {
val mangaChaptersLike = mangaElementsSum(document.select(".title i.fa.fa-thumbs-up > span")) val mangaChaptersLike = mangaElementsSum(document.select(".title i.fa.fa-thumbs-up > span"))
val mangaComments = mangaElementsSum(document.select(".title i.fa.fa-comment > span")) val mangaComments = mangaElementsSum(document.select(".title i.fa.fa-comment > span"))
val genres = mutableListOf<String>() val genres = mutableListOf<String>()
document.select("div.left-info > .manga-tags > a.tag").forEach { document.select("div.left-info div.information > .manga-tags > a.tag").forEach {
genres.add(it.text()) genres.add(it.text())
} }
@ -223,10 +249,10 @@ class MangaShowMe : ParsedHttpSource() {
.map { imageUrls.getString(it) } .map { imageUrls.getString(it) }
.forEach { pages.add(Page(pages.size, decoder.request(it), "${it.substringBefore("!!")}?quick")) } .forEach { pages.add(Page(pages.size, decoder.request(it), "${it.substringBefore("!!")}?quick")) }
} else { } else {
(0 until imageUrls.length()) (0 until imageUrls1.length())
.map { .map {
imageUrls.getString(it) + try { imageUrls1.getString(it) + try {
"!!${imageUrls1.getString(it)}" "!!${imageUrls.getString(it)}?quick"
} catch (_: Exception) { } catch (_: Exception) {
"" ""
} }
@ -287,9 +313,45 @@ class MangaShowMe : ParsedHttpSource() {
url[1].replace("&", "%26").replace("#", "%23") url[1].replace("&", "%26").replace("#", "%23")
} }
private val preferences: SharedPreferences by lazy {
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
}
override fun setupPreferenceScreen(screen: PreferenceScreen) {
val baseUrlPref = EditTextPreference(screen.context).apply {
key = BASE_URL_PREF_TITLE
title = BASE_URL_PREF_TITLE
summary = BASE_URL_PREF_SUMMARY
this.setDefaultValue(defaultBaseUrl)
dialogTitle = BASE_URL_PREF_TITLE
dialogMessage = "Default: $defaultBaseUrl"
setOnPreferenceChangeListener { _, newValue ->
try {
val res = preferences.edit().putString(BASE_URL_PREF, newValue as String).commit()
Toast.makeText(screen.context, RESTART_TACHIYOMI, Toast.LENGTH_LONG).show()
res
} catch (e: Exception) {
e.printStackTrace()
false
}
}
}
screen.addPreference(baseUrlPref)
}
private fun getPrefBaseUrl(): String = preferences.getString(BASE_URL_PREF, defaultBaseUrl)
override fun getFilterList() = getFilters() override fun getFilterList() = getFilters()
companion object { companion object {
private const val BASE_URL_PREF_TITLE = "Override BaseUrl"
private const val BASE_URL_PREF = "overrideBaseUrl_v${BuildConfig.VERSION_NAME}"
private const val BASE_URL_PREF_SUMMARY = "For temporary uses. Update extension will erase this setting."
private const val RESTART_TACHIYOMI = "Restart Tachiyomi to apply new setting."
internal const val V1_CX = 5 internal const val V1_CX = 5
internal const val V1_CY = 5 internal const val V1_CY = 5
} }