Added support for OriginLanguage filtering in latest and browse, fixed porn chapters too (#8993)
* Added originalLanguage filters * add content preference in chapter list * Remove zero width space * change default originLanguagepref to false * made originLang work in browse too * actually fixed nsfw chapter list maybe * added new MangaDex icons * filter all chapters with external links * change browse sort to followCount * add origin language filtering to browse and properly set default filter values * add all contentRating queries to the actual chapterlist request no matter what
|
@ -6,7 +6,7 @@ ext {
|
||||||
extName = 'MangaDex'
|
extName = 'MangaDex'
|
||||||
pkgNameSuffix = 'all.mangadex'
|
pkgNameSuffix = 'all.mangadex'
|
||||||
extClass = '.MangaDexFactory'
|
extClass = '.MangaDexFactory'
|
||||||
extVersionCode = 130
|
extVersionCode = 131
|
||||||
libVersion = '1.2'
|
libVersion = '1.2'
|
||||||
containsNsfw = true
|
containsNsfw = true
|
||||||
}
|
}
|
||||||
|
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.7 KiB |
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 8.6 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 24 KiB |
|
@ -80,4 +80,22 @@ object MDConstants {
|
||||||
fun getContentRatingPornographicPrefKey(dexLang: String): String {
|
fun getContentRatingPornographicPrefKey(dexLang: String): String {
|
||||||
return "${contentRatingPornographicPref}_$dexLang"
|
return "${contentRatingPornographicPref}_$dexLang"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private const val originalLanguageJapanesePref = "originalLanguageJapanese"
|
||||||
|
|
||||||
|
fun getOriginalLanguageJapanesePref(dexLang: String): String {
|
||||||
|
return "${originalLanguageJapanesePref}_$dexLang"
|
||||||
|
}
|
||||||
|
|
||||||
|
private const val originalLanguageChinesePref = "originalLanguageChinese"
|
||||||
|
|
||||||
|
fun getOriginalLanguageChinesePref(dexLang: String): String {
|
||||||
|
return "${originalLanguageChinesePref}_$dexLang"
|
||||||
|
}
|
||||||
|
|
||||||
|
private const val originalLanguageKoreanPref = "originalLanguageKorean"
|
||||||
|
|
||||||
|
fun getOriginalLanguageKoreanPref(dexLang: String): String {
|
||||||
|
return "${originalLanguageKoreanPref}_$dexLang"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,7 +61,7 @@ abstract class MangaDex(override val lang: String, val dexLang: String) :
|
||||||
|
|
||||||
override fun popularMangaRequest(page: Int): Request {
|
override fun popularMangaRequest(page: Int): Request {
|
||||||
val url = MDConstants.apiMangaUrl.toHttpUrl().newBuilder().apply {
|
val url = MDConstants.apiMangaUrl.toHttpUrl().newBuilder().apply {
|
||||||
addQueryParameter("order[updatedAt]", "desc")
|
addQueryParameter("order[followedCount]", "desc")
|
||||||
addQueryParameter("limit", MDConstants.mangaLimit.toString())
|
addQueryParameter("limit", MDConstants.mangaLimit.toString())
|
||||||
addQueryParameter("offset", helper.getMangaListOffset(page))
|
addQueryParameter("offset", helper.getMangaListOffset(page))
|
||||||
addQueryParameter("includes[]", MDConstants.coverArt)
|
addQueryParameter("includes[]", MDConstants.coverArt)
|
||||||
|
@ -89,6 +89,29 @@ abstract class MangaDex(override val lang: String, val dexLang: String) :
|
||||||
) {
|
) {
|
||||||
addQueryParameter("contentRating[]", "pornographic")
|
addQueryParameter("contentRating[]", "pornographic")
|
||||||
}
|
}
|
||||||
|
if (preferences.getBoolean(
|
||||||
|
MDConstants.getOriginalLanguageJapanesePref(dexLang),
|
||||||
|
false
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
addQueryParameter("originalLanguage[]", "ja")
|
||||||
|
}
|
||||||
|
// dex has zh and zh-hk for chinese manhua
|
||||||
|
if (preferences.getBoolean(
|
||||||
|
MDConstants.getOriginalLanguageChinesePref(dexLang),
|
||||||
|
false
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
addQueryParameter("originalLanguage[]", "zh")
|
||||||
|
addQueryParameter("originalLanguage[]", "zh-hk")
|
||||||
|
}
|
||||||
|
if (preferences.getBoolean(
|
||||||
|
MDConstants.getOriginalLanguageKoreanPref(dexLang),
|
||||||
|
false
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
addQueryParameter("originalLanguage[]", "ko")
|
||||||
|
}
|
||||||
}.build().toUrl().toString()
|
}.build().toUrl().toString()
|
||||||
return GET(
|
return GET(
|
||||||
url = url,
|
url = url,
|
||||||
|
@ -144,6 +167,17 @@ abstract class MangaDex(override val lang: String, val dexLang: String) :
|
||||||
if (preferences.getBoolean(MDConstants.getContentRatingPornographicPrefKey(dexLang), false)) {
|
if (preferences.getBoolean(MDConstants.getContentRatingPornographicPrefKey(dexLang), false)) {
|
||||||
addQueryParameter("contentRating[]", "pornographic")
|
addQueryParameter("contentRating[]", "pornographic")
|
||||||
}
|
}
|
||||||
|
if (preferences.getBoolean(MDConstants.getOriginalLanguageJapanesePref(dexLang), false)) {
|
||||||
|
addQueryParameter("originalLanguage[]", "ja")
|
||||||
|
}
|
||||||
|
// dex has zh and zh-hk for chinese manhua
|
||||||
|
if (preferences.getBoolean(MDConstants.getOriginalLanguageChinesePref(dexLang), false)) {
|
||||||
|
addQueryParameter("originalLanguage[]", "zh")
|
||||||
|
addQueryParameter("originalLanguage[]", "zh-hk")
|
||||||
|
}
|
||||||
|
if (preferences.getBoolean(MDConstants.getOriginalLanguageKoreanPref(dexLang), false)) {
|
||||||
|
addQueryParameter("originalLanguage[]", "ko")
|
||||||
|
}
|
||||||
|
|
||||||
mangaIds.forEach { id ->
|
mangaIds.forEach { id ->
|
||||||
addQueryParameter("ids[]", id)
|
addQueryParameter("ids[]", id)
|
||||||
|
@ -308,15 +342,16 @@ abstract class MangaDex(override val lang: String, val dexLang: String) :
|
||||||
/**
|
/**
|
||||||
* Required because api is paged
|
* Required because api is paged
|
||||||
*/
|
*/
|
||||||
private fun actualChapterListRequest(mangaId: String, offset: Int) =
|
private fun actualChapterListRequest(mangaId: String, offset: Int): Request {
|
||||||
GET(
|
val url = helper.getChapterEndpoint(mangaId, offset, dexLang).toHttpUrlOrNull()!!.newBuilder().apply {
|
||||||
url = helper.getChapterEndpoint(mangaId, offset, dexLang),
|
addQueryParameter("contentRating[]", "safe")
|
||||||
headers = headers,
|
addQueryParameter("contentRating[]", "suggestive")
|
||||||
cache = CacheControl.FORCE_NETWORK
|
addQueryParameter("contentRating[]", "erotica")
|
||||||
)
|
addQueryParameter("contentRating[]", "pornographic")
|
||||||
|
}.build().toString()
|
||||||
|
return GET(url, headers = headers, cache = CacheControl.FORCE_NETWORK)
|
||||||
|
}
|
||||||
override fun chapterListParse(response: Response): List<SChapter> {
|
override fun chapterListParse(response: Response): List<SChapter> {
|
||||||
|
|
||||||
if (response.isSuccessful.not()) {
|
if (response.isSuccessful.not()) {
|
||||||
throw Exception("HTTP ${response.code}")
|
throw Exception("HTTP ${response.code}")
|
||||||
}
|
}
|
||||||
|
@ -350,15 +385,15 @@ abstract class MangaDex(override val lang: String, val dexLang: String) :
|
||||||
|
|
||||||
val now = Date().time
|
val now = Date().time
|
||||||
|
|
||||||
return chapterListResults.map { helper.createChapter(it) }
|
return chapterListResults.mapNotNull { helper.createChapter(it) }
|
||||||
.filter { it.date_upload <= now && "MangaPlus" != it.scanlator
|
.filter {
|
||||||
&& "Comikey" != it.scanlator}
|
it.date_upload <= now
|
||||||
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e("MangaDex", "error parsing chapter list", e)
|
Log.e("MangaDex", "error parsing chapter list", e)
|
||||||
throw(e)
|
throw(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun pageListRequest(chapter: SChapter): Request {
|
override fun pageListRequest(chapter: SChapter): Request {
|
||||||
if (!helper.containsUuid(chapter.url)) {
|
if (!helper.containsUuid(chapter.url)) {
|
||||||
throw Exception("Migrate this manga from MangaDex to MangaDex to update it")
|
throw Exception("Migrate this manga from MangaDex to MangaDex to update it")
|
||||||
|
@ -515,6 +550,48 @@ abstract class MangaDex(override val lang: String, val dexLang: String) :
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val originalLanguageJapanesePref = SwitchPreferenceCompat(screen.context).apply {
|
||||||
|
key = MDConstants.getOriginalLanguageJapanesePref(dexLang)
|
||||||
|
title = "Japanese"
|
||||||
|
summary = "If enabled, only shows content that was originally published in Japanese in both latest and browse"
|
||||||
|
setDefaultValue(false)
|
||||||
|
|
||||||
|
setOnPreferenceChangeListener { _, newValue ->
|
||||||
|
val checkValue = newValue as Boolean
|
||||||
|
preferences.edit()
|
||||||
|
.putBoolean(MDConstants.getOriginalLanguageJapanesePref(dexLang), checkValue)
|
||||||
|
.commit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val originalLanguageChinesePref = SwitchPreferenceCompat(screen.context).apply {
|
||||||
|
key = MDConstants.getOriginalLanguageChinesePref(dexLang)
|
||||||
|
title = "Chinese"
|
||||||
|
summary = "If enabled, only shows content that was originally published in Chinese in both latest and browse"
|
||||||
|
setDefaultValue(false)
|
||||||
|
|
||||||
|
setOnPreferenceChangeListener { _, newValue ->
|
||||||
|
val checkValue = newValue as Boolean
|
||||||
|
preferences.edit()
|
||||||
|
.putBoolean(MDConstants.getOriginalLanguageChinesePref(dexLang), checkValue)
|
||||||
|
.commit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val originalLanguageKoreanPref = SwitchPreferenceCompat(screen.context).apply {
|
||||||
|
key = MDConstants.getOriginalLanguageKoreanPref(dexLang)
|
||||||
|
title = "Korean"
|
||||||
|
summary = "If enabled, only shows content that was originally published in Korean in both latest and browse"
|
||||||
|
setDefaultValue(false)
|
||||||
|
|
||||||
|
setOnPreferenceChangeListener { _, newValue ->
|
||||||
|
val checkValue = newValue as Boolean
|
||||||
|
preferences.edit()
|
||||||
|
.putBoolean(MDConstants.getOriginalLanguageKoreanPref(dexLang), checkValue)
|
||||||
|
.commit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
screen.addPreference(coverQualityPref)
|
screen.addPreference(coverQualityPref)
|
||||||
screen.addPreference(dataSaverPref)
|
screen.addPreference(dataSaverPref)
|
||||||
screen.addPreference(standardHttpsPortPref)
|
screen.addPreference(standardHttpsPortPref)
|
||||||
|
@ -522,6 +599,9 @@ abstract class MangaDex(override val lang: String, val dexLang: String) :
|
||||||
screen.addPreference(contentRatingSuggestivePref)
|
screen.addPreference(contentRatingSuggestivePref)
|
||||||
screen.addPreference(contentRatingEroticaPref)
|
screen.addPreference(contentRatingEroticaPref)
|
||||||
screen.addPreference(contentRatingPornographicPref)
|
screen.addPreference(contentRatingPornographicPref)
|
||||||
|
screen.addPreference(originalLanguageJapanesePref)
|
||||||
|
screen.addPreference(originalLanguageChinesePref)
|
||||||
|
screen.addPreference(originalLanguageKoreanPref)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getFilterList(): FilterList =
|
override fun getFilterList(): FilterList =
|
||||||
|
|
|
@ -11,7 +11,7 @@ class MangaDexFilters {
|
||||||
internal fun getMDFilterList(preferences: SharedPreferences, dexLang: String): FilterList {
|
internal fun getMDFilterList(preferences: SharedPreferences, dexLang: String): FilterList {
|
||||||
|
|
||||||
return FilterList(
|
return FilterList(
|
||||||
OriginalLanguageList(getOriginalLanguage()),
|
OriginalLanguageList(getOriginalLanguage(preferences, dexLang)),
|
||||||
ContentRatingList(getContentRating(preferences, dexLang)),
|
ContentRatingList(getContentRating(preferences, dexLang)),
|
||||||
DemographicList(getDemographics()),
|
DemographicList(getDemographics()),
|
||||||
StatusList(getStatus()),
|
StatusList(getStatus()),
|
||||||
|
@ -24,8 +24,10 @@ class MangaDexFilters {
|
||||||
|
|
||||||
private fun getContentRating(preferences: SharedPreferences, dexLang: String) = listOf(
|
private fun getContentRating(preferences: SharedPreferences, dexLang: String) = listOf(
|
||||||
ContentRating("Safe").apply {
|
ContentRating("Safe").apply {
|
||||||
state =
|
state = preferences.getBoolean(
|
||||||
preferences.getBoolean(MDConstants.getContentRatingSafePrefKey(dexLang), true)
|
MDConstants.getContentRatingSafePrefKey(dexLang),
|
||||||
|
true
|
||||||
|
)
|
||||||
},
|
},
|
||||||
ContentRating("Suggestive").apply {
|
ContentRating("Suggestive").apply {
|
||||||
state = preferences.getBoolean(
|
state = preferences.getBoolean(
|
||||||
|
@ -78,10 +80,25 @@ class MangaDexFilters {
|
||||||
private class OriginalLanguageList(originalLanguage: List<OriginalLanguage>) :
|
private class OriginalLanguageList(originalLanguage: List<OriginalLanguage>) :
|
||||||
Filter.Group<OriginalLanguage>("Original language", originalLanguage)
|
Filter.Group<OriginalLanguage>("Original language", originalLanguage)
|
||||||
|
|
||||||
private fun getOriginalLanguage() = listOf(
|
private fun getOriginalLanguage(preferences: SharedPreferences, dexLang: String) = listOf(
|
||||||
OriginalLanguage("Japanese (Manga)", "ja"),
|
OriginalLanguage("Japanese (Manga)", "ja").apply {
|
||||||
OriginalLanguage("Chinese (Manhua)", "zh"),
|
state = preferences.getBoolean(
|
||||||
OriginalLanguage("Korean (Manhwa)", "ko"),
|
MDConstants.getOriginalLanguageJapanesePref(dexLang),
|
||||||
|
false
|
||||||
|
)
|
||||||
|
},
|
||||||
|
OriginalLanguage("Chinese (Manhua)", "zh").apply {
|
||||||
|
state = preferences.getBoolean(
|
||||||
|
MDConstants.getOriginalLanguageChinesePref(dexLang),
|
||||||
|
false
|
||||||
|
)
|
||||||
|
},
|
||||||
|
OriginalLanguage("Korean (Manhwa)", "ko").apply {
|
||||||
|
state = preferences.getBoolean(
|
||||||
|
MDConstants.getOriginalLanguageKoreanPref(dexLang),
|
||||||
|
false
|
||||||
|
)
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
internal class Tag(val id: String, name: String) : Filter.TriState(name)
|
internal class Tag(val id: String, name: String) : Filter.TriState(name)
|
||||||
|
|
|
@ -172,7 +172,7 @@ class MangaDexHelper() {
|
||||||
title = cleanString(mangaDto.data.attributes.title.asMdMap()["en"] ?: "")
|
title = cleanString(mangaDto.data.attributes.title.asMdMap()["en"] ?: "")
|
||||||
|
|
||||||
coverFileName?.let {
|
coverFileName?.let {
|
||||||
thumbnail_url = when(coverSuffix != null && coverSuffix != "") {
|
thumbnail_url = when (coverSuffix != null && coverSuffix != "") {
|
||||||
true -> "${MDConstants.cdnUrl}/covers/${mangaDto.data.id}/$coverFileName$coverSuffix"
|
true -> "${MDConstants.cdnUrl}/covers/${mangaDto.data.id}/$coverFileName$coverSuffix"
|
||||||
else -> "${MDConstants.cdnUrl}/covers/${mangaDto.data.id}/$coverFileName"
|
else -> "${MDConstants.cdnUrl}/covers/${mangaDto.data.id}/$coverFileName"
|
||||||
}
|
}
|
||||||
|
@ -248,7 +248,7 @@ class MangaDexHelper() {
|
||||||
/**
|
/**
|
||||||
* create the SChapter from json
|
* create the SChapter from json
|
||||||
*/
|
*/
|
||||||
fun createChapter(chapterDto: ChapterDto): SChapter {
|
fun createChapter(chapterDto: ChapterDto): SChapter? {
|
||||||
try {
|
try {
|
||||||
val data = chapterDto.data
|
val data = chapterDto.data
|
||||||
val attr = data.attributes
|
val attr = data.attributes
|
||||||
|
@ -287,6 +287,10 @@ class MangaDexHelper() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (attr.externalUrl != null && attr.data.isEmpty()) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
// if volume, chapter and title is empty its a oneshot
|
// if volume, chapter and title is empty its a oneshot
|
||||||
if (chapterName.isEmpty()) {
|
if (chapterName.isEmpty()) {
|
||||||
chapterName.add("Oneshot")
|
chapterName.add("Oneshot")
|
||||||
|
|
|
@ -33,4 +33,5 @@ data class ChapterAttributesDto(
|
||||||
val data: List<String>,
|
val data: List<String>,
|
||||||
val dataSaver: List<String>,
|
val dataSaver: List<String>,
|
||||||
val hash: String,
|
val hash: String,
|
||||||
|
val externalUrl: String?,
|
||||||
)
|
)
|
||||||
|
|