Finish some more advanced mangadex delegation features, more to come later

This commit is contained in:
Jobobby04
2020-08-20 20:50:37 -04:00
parent 294ade035e
commit 0deb6f6b8d
31 changed files with 2274 additions and 4 deletions
@@ -0,0 +1,15 @@
package exh.md.utils
enum class FollowStatus(val int: Int) {
UNFOLLOWED(0),
READING(1),
COMPLETED(2),
ON_HOLD(3),
PLAN_TO_READ(4),
DROPPED(5),
RE_READING(6);
companion object {
fun fromInt(value: Int): FollowStatus? = values().find { it.int == value }
}
}
+45
View File
@@ -0,0 +1,45 @@
package exh.md.utils
enum class MdLang(val lang: String, val dexLang: String, val langId: Int) {
English("en", "gb", 1),
Japanese("ja", "jp", 2),
Polish("pl", "pl", 3),
SerboCroatian("sh", "rs", 4),
Dutch("nl", "nl", 5),
Italian("it", "it", 6),
Russian("ru", "ru", 7),
German("de", "de", 8),
Hungarian("hu", "hu", 9),
French("fr", "fr", 10),
Finnish("fi", "fi", 11),
Vietnamese("vi", "vn", 12),
Greek("el", "gr", 13),
Bulgarian("bg", "bg", 14),
Spanish("es", "es", 15),
PortugeseBrazilian("pt-BR", "br", 16),
Portuguese("pt", "pt", 17),
Swedish("sv", "se", 18),
Arabic("ar", "sa", 19),
Danish("da", "dk", 20),
ChineseSimplifed("zh-Hans", "cn", 21),
Bengali("bn", "bd", 22),
Romanian("ro", "ro", 23),
Czech("cs", "cz", 24),
Mongolian("mn", "mn", 25),
Turkish("tr", "tr", 26),
Indonesian("id", "id", 27),
Korean("ko", "kr", 28),
SpanishLTAM("es-419", "mx", 29),
Persian("fa", "ir", 30),
Malay("ms", "my", 31),
Thai("th", "th", 32),
Catalan("ca", "ct", 33),
Filipino("fil", "ph", 34),
ChineseTraditional("zh-Hant", "hk", 35),
Ukrainian("uk", "ua", 36),
Burmese("my", "mm", 37),
Lithuanian("lt", "il", 38),
Hebrew("he", "il", 39),
Hindi("hi", "in", 40),
Norwegian("no", "no", 42)
}
+248
View File
@@ -0,0 +1,248 @@
package exh.md.utils
import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga
import java.net.URI
import java.net.URISyntaxException
import kotlin.math.floor
import kotlinx.serialization.json.Json
import org.jsoup.parser.Parser
class MdUtil {
companion object {
const val cdnUrl = "https://mangadex.org" // "https://s0.mangadex.org"
const val baseUrl = "https://mangadex.org"
const val randMangaPage = "/manga/"
const val apiManga = "/api/manga/"
const val apiChapter = "/api/chapter/"
const val apiChapterSuffix = "?mark_read=0"
const val groupSearchUrl = "$baseUrl/groups/0/1/"
const val followsAllApi = "/api/?type=manga_follows"
const val followsMangaApi = "/api/?type=manga_follows&manga_id="
const val coversApi = "/api/index.php?type=covers&id="
const val reportUrl = "https://api.mangadex.network/report"
const val imageUrl = "$baseUrl/data"
val jsonParser = Json {
isLenient = true
ignoreUnknownKeys = true
allowSpecialFloatingPointValues = true
useArrayPolymorphism = true
prettyPrint = true
}
private const
val scanlatorSeparator = " & "
val validOneShotFinalChapters = listOf("0", "1")
val englishDescriptionTags = listOf(
"[b][u]English:",
"[b][u]English",
"[English]:",
"[B][ENG][/B]"
)
val descriptionLanguages = listOf(
"Russian / Русский",
"[u]Russian",
"[b][u]Russian",
"[RUS]",
"Russian / Русский",
"Russian/Русский:",
"Russia/Русское",
"Русский",
"RUS:",
"[b][u]German / Deutsch",
"German/Deutsch:",
"Español / Spanish",
"Spanish / Español",
"Spanish / Espa & ntilde; ol",
"Spanish / Español",
"[b][u]Spanish",
"[Español]:",
"[b] Spanish: [/ b]",
"Spanish/Español",
"Español / Spanish",
"Italian / Italiano",
"Pasta-Pizza-Mandolino/Italiano",
"Polish / polski",
"Polish / Polski",
"Polish Summary / Polski Opis",
"Polski",
"Portuguese (BR) / Português",
"Portuguese / Português",
"Português / Portuguese",
"Portuguese / Portugu",
"Portuguese / Português",
"Português",
"Portuguese (BR) / Portugu & ecirc;",
"Portuguese (BR) / Portuguê",
"[PTBR]",
"Résume Français",
"Résumé Français",
"[b][u]French",
"French / Français",
"Français",
"[hr]Fr:",
"French - Français:",
"Turkish / Türkçe",
"Turkish/Türkçe",
"[b][u]Chinese",
"Arabic / العربية",
"العربية",
"[hr]TH",
"[b][u]Vietnamese",
"[b]Links:",
"[b]Link[/b]",
"Links:",
"[b]External Links"
)
// guess the thumbnail url is .jpg this has a ~80% success rate
fun formThumbUrl(mangaUrl: String, lowQuality: Boolean): String {
var ext = ".jpg"
if (lowQuality) {
ext = ".thumb$ext"
}
return cdnUrl + "/images/manga/" + getMangaId(mangaUrl) + ext
}
// Get the ID from the manga url
fun getMangaId(url: String): String {
val lastSection = url.trimEnd('/').substringAfterLast("/")
return if (lastSection.toIntOrNull() != null) {
lastSection
} else {
// this occurs if person has manga from before that had the id/name/
url.trimEnd('/').substringBeforeLast("/").substringAfterLast("/")
}
}
fun getChapterId(url: String) = url.substringBeforeLast(apiChapterSuffix).substringAfterLast("/")
// creates the manga url from the browse for the api
fun modifyMangaUrl(url: String): String =
url.replace("/title/", "/manga/").substringBeforeLast("/") + "/"
// Removes the ?timestamp from image urls
fun removeTimeParamUrl(url: String): String = url.substringBeforeLast("?")
fun cleanString(string: String): String {
val bbRegex =
"""\[(\w+)[^]]*](.*?)\[/\1]""".toRegex()
var intermediate = string
.replace("[list]", "", true)
.replace("[/list]", "", true)
.replace("[*]", "")
.replace("[hr]", "", true)
.replace("[u]", "", true)
.replace("[/u]", "", true)
.replace("[b]", "", true)
.replace("[/b]", "", true)
// Recursively remove nested bbcode
while (bbRegex.containsMatchIn(intermediate)) {
intermediate = intermediate.replace(bbRegex, "$2")
}
return Parser.unescapeEntities(intermediate, false)
}
fun cleanDescription(string: String): String {
var newDescription = string
descriptionLanguages.forEach {
newDescription = newDescription.substringBefore(it)
}
englishDescriptionTags.forEach {
newDescription = newDescription.replace(it, "")
}
return cleanString(newDescription)
}
fun getImageUrl(attr: String): String {
// Some images are hosted elsewhere
if (attr.startsWith("http")) {
return attr
}
return baseUrl + attr
}
fun getScanlators(scanlators: String): List<String> {
if (scanlators.isBlank()) return emptyList()
return scanlators.split(scanlatorSeparator).distinct()
}
fun getScanlatorString(scanlators: Set<String>): String {
return scanlators.toList().sorted().joinToString(scanlatorSeparator)
}
fun getMissingChapterCount(chapters: List<SChapter>, mangaStatus: Int): String? {
if (mangaStatus == SManga.COMPLETED) return null
// TODO
val remove0ChaptersFromCount = chapters.distinctBy {
/*if (it.chapter_txt.isNotEmpty()) {
it.vol + it.chapter_txt
} else {*/
it.name
/*}*/
}.sortedByDescending { it.chapter_number }
remove0ChaptersFromCount.firstOrNull()?.let {
val chpNumber = floor(it.chapter_number).toInt()
val allChapters = (1..chpNumber).toMutableSet()
remove0ChaptersFromCount.forEach {
allChapters.remove(floor(it.chapter_number).toInt())
}
if (allChapters.size <= 0) return null
return allChapters.size.toString()
}
return null
}
}
}
/**
* Assigns the url of the chapter without the scheme and domain. It saves some redundancy from
* database and the urls could still work after a domain change.
*
* @param url the full url to the chapter.
*/
fun SChapter.setMDUrlWithoutDomain(url: String) {
this.url = getMDUrlWithoutDomain(url)
}
/**
* Assigns the url of the manga without the scheme and domain. It saves some redundancy from
* database and the urls could still work after a domain change.
*
* @param url the full url to the manga.
*/
fun SManga.setMDUrlWithoutDomain(url: String) {
this.url = getMDUrlWithoutDomain(url)
}
/**
* Returns the url of the given string without the scheme and domain.
*
* @param orig the full url.
*/
private fun getMDUrlWithoutDomain(orig: String): String {
return try {
val uri = URI(orig)
var out = uri.path
if (uri.query != null) {
out += "?" + uri.query
}
if (uri.fragment != null) {
out += "#" + uri.fragment
}
out
} catch (e: URISyntaxException) {
orig
}
}