Compare commits

..

No commits in common. "c5c6d77479d473b7acd5251d603d224de1d31132" and "1699cece9f9f17f1033819a005c68b403f0d703c" have entirely different histories.

286 changed files with 1009 additions and 5561 deletions

View File

@ -1,12 +0,0 @@
plugins {
`java-library`
kotlin("jvm")
}
repositories {
mavenCentral()
}
dependencies {
compileOnly(libs.kotlin.stdlib)
}

View File

@ -1,294 +0,0 @@
package eu.kanade.tachiyomi.lib.lzstring
typealias getCharFromIntFn = (it: Int) -> String
typealias getNextValueFn = (it: Int) -> Int
/**
* Reimplementation of [lz-string](https://github.com/pieroxy/lz-string) compression/decompression.
*/
object LZString {
private fun compress(
uncompressed: String,
bitsPerChar: Int,
getCharFromInt: getCharFromIntFn,
): String {
val context = CompressionContext(uncompressed.length, bitsPerChar, getCharFromInt)
for (ii in uncompressed.indices) {
context.c = uncompressed[ii].toString()
if (!context.dictionary.containsKey(context.c)) {
context.dictionary[context.c] = context.dictSize++
context.dictionaryToCreate[context.c] = true
}
context.wc = context.w + context.c
if (context.dictionary.containsKey(context.wc)) {
context.w = context.wc
continue
}
context.outputCodeForW()
context.decrementEnlargeIn()
context.dictionary[context.wc] = context.dictSize++
context.w = context.c
}
if (context.w.isNotEmpty()) {
context.outputCodeForW()
context.decrementEnlargeIn()
}
// Mark the end of the stream
context.value = 2
for (i in 0 until context.numBits) {
context.dataVal = (context.dataVal shl 1) or (context.value and 1)
context.appendDataOrAdvancePosition()
context.value = context.value shr 1
}
while (true) {
context.dataVal = context.dataVal shl 1
if (context.dataPosition == bitsPerChar - 1) {
context.data.append(getCharFromInt(context.dataVal))
break
}
context.dataPosition++
}
return context.data.toString()
}
private fun decompress(length: Int, resetValue: Int, getNextValue: getNextValueFn): String {
val dictionary = mutableListOf<String>()
val result = StringBuilder()
val data = DecompressionContext(resetValue, getNextValue)
var enlargeIn = 4
var numBits = 3
var entry: String
var c: Char? = null
for (i in 0 until 3) {
dictionary.add(i.toString())
}
data.loopUntilMaxPower()
when (data.bits) {
0 -> {
data.bits = 0
data.maxPower = 1 shl 8
data.power = 1
data.loopUntilMaxPower()
c = data.bits.toChar()
}
1 -> {
data.bits = 0
data.maxPower = 1 shl 16
data.power = 1
data.loopUntilMaxPower()
c = data.bits.toChar()
}
2 -> throw IllegalArgumentException("Invalid LZString")
}
if (c == null) {
throw Exception("No character found")
}
dictionary.add(c.toString())
var w = c.toString()
result.append(c.toString())
while (true) {
if (data.index > length) {
throw IllegalArgumentException("Invalid LZString")
}
data.bits = 0
data.maxPower = 1 shl numBits
data.power = 1
data.loopUntilMaxPower()
var cc = data.bits
when (data.bits) {
0 -> {
data.bits = 0
data.maxPower = 1 shl 8
data.power = 1
data.loopUntilMaxPower()
dictionary.add(data.bits.toChar().toString())
cc = dictionary.size - 1
enlargeIn--
}
1 -> {
data.bits = 0
data.maxPower = 1 shl 16
data.power = 1
data.loopUntilMaxPower()
dictionary.add(data.bits.toChar().toString())
cc = dictionary.size - 1
enlargeIn--
}
2 -> return result.toString()
}
if (enlargeIn == 0) {
enlargeIn = 1 shl numBits
numBits++
}
entry = if (cc < dictionary.size) {
dictionary[cc]
} else {
if (cc == dictionary.size) {
w + w[0]
} else {
throw Exception("Invalid LZString")
}
}
result.append(entry)
dictionary.add(w + entry[0])
enlargeIn--
w = entry
if (enlargeIn == 0) {
enlargeIn = 1 shl numBits
numBits++
}
}
}
private const val base64KeyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
fun compressToBase64(input: String): String =
compress(input, 6) { base64KeyStr[it].toString() }.let {
return when (it.length % 4) {
0 -> it
1 -> "$it==="
2 -> "$it=="
3 -> "$it="
else -> throw IllegalStateException("Modulo of 4 should not exceed 3.")
}
}
fun decompressFromBase64(input: String): String =
decompress(input.length, 32) {
base64KeyStr.indexOf(input[it])
}
}
private data class DecompressionContext(
val resetValue: Int,
val getNextValue: getNextValueFn,
var value: Int = getNextValue(0),
var position: Int = resetValue,
var index: Int = 1,
var bits: Int = 0,
var maxPower: Int = 1 shl 2,
var power: Int = 1,
) {
fun loopUntilMaxPower() {
while (power != maxPower) {
val resb = value and position
position = position shr 1
if (position == 0) {
position = resetValue
value = getNextValue(index++)
}
bits = bits or ((if (resb > 0) 1 else 0) * power)
power = power shl 1
}
}
}
private data class CompressionContext(
val uncompressedLength: Int,
val bitsPerChar: Int,
val getCharFromInt: getCharFromIntFn,
var value: Int = 0,
val dictionary: MutableMap<String, Int> = HashMap(),
val dictionaryToCreate: MutableMap<String, Boolean> = HashMap(),
var c: String = "",
var wc: String = "",
var w: String = "",
var enlargeIn: Int = 2, // Compensate for the first entry which should not count
var dictSize: Int = 3,
var numBits: Int = 2,
val data: StringBuilder = StringBuilder(uncompressedLength / 3),
var dataVal: Int = 0,
var dataPosition: Int = 0,
) {
fun appendDataOrAdvancePosition() {
if (dataPosition == bitsPerChar - 1) {
dataPosition = 0
data.append(getCharFromInt(dataVal))
dataVal = 0
} else {
dataPosition++
}
}
fun decrementEnlargeIn() {
enlargeIn--
if (enlargeIn == 0) {
enlargeIn = 1 shl numBits
numBits++
}
}
// Output the code for W.
fun outputCodeForW() {
if (dictionaryToCreate.containsKey(w)) {
if (w[0].code < 256) {
for (i in 0 until numBits) {
dataVal = dataVal shl 1
appendDataOrAdvancePosition()
}
value = w[0].code
for (i in 0 until 8) {
dataVal = (dataVal shl 1) or (value and 1)
appendDataOrAdvancePosition()
value = value shr 1
}
} else {
value = 1
for (i in 0 until numBits) {
dataVal = (dataVal shl 1) or value
appendDataOrAdvancePosition()
value = 0
}
value = w[0].code
for (i in 0 until 16) {
dataVal = (dataVal shl 1) or (value and 1)
appendDataOrAdvancePosition()
value = value shr 1
}
}
decrementEnlargeIn()
dictionaryToCreate.remove(w)
} else {
value = dictionary[w]!!
for (i in 0 until numBits) {
dataVal = (dataVal shl 1) or (value and 1)
appendDataOrAdvancePosition()
value = value shr 1
}
}
}
}

View File

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<activity
android:name="eu.kanade.tachiyomi.multisrc.colamanga.ColaMangaUrlActivity"
android:excludeFromRecents="true"
android:exported="true"
android:theme="@android:style/Theme.NoDisplay">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data
android:host="${SOURCEHOST}"
android:scheme="${SOURCESCHEME}"
android:pathPattern="/manga-..*/" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@ -1,3 +0,0 @@
dependencies {
implementation(project(":lib:synchrony"))
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

View File

@ -1,123 +0,0 @@
package eu.kanade.tachiyomi.extension.en.mangadig
import eu.kanade.tachiyomi.multisrc.colamanga.ColaManga
import eu.kanade.tachiyomi.multisrc.colamanga.UriPartFilter
import eu.kanade.tachiyomi.source.model.FilterList
class MangaDig : ColaManga("MangaDig", "https://mangadig.com", "en") {
override fun popularMangaNextPageSelector() = "a:contains(Next):not(.fed-btns-disad)"
override val statusTitle = "Status"
override val authorTitle = "Author"
override val genreTitle = "Category"
override val statusOngoing = "OnGoing"
override val statusCompleted = "Complete"
override fun getFilterList(): FilterList {
val filters = buildList {
addAll(super.getFilterList().list)
add(SortFilter())
add(CategoryFilter())
add(CharFilter())
add(StatusFilter())
}
return FilterList(filters)
}
private class StatusFilter : UriPartFilter(
"Status",
"status",
arrayOf(
Pair("All", ""),
Pair("Ongoing", "1"),
Pair("Complete", "2"),
),
)
private class SortFilter : UriPartFilter(
"Order by",
"orderBy",
arrayOf(
Pair("Last updated", "update"),
Pair("Recently added", "create"),
Pair("Most popular today", "dailyCount"),
Pair("Most popular this week", "weeklyCount"),
Pair("Most popular this month", "monthlyCount"),
),
2,
)
private class CategoryFilter : UriPartFilter(
"Genre",
"mainCategoryId",
arrayOf(
Pair("All", ""),
Pair("Romance", "10008"),
Pair("Drama", "10005"),
Pair("Comedy", "10004"),
Pair("Fantasy", "10006"),
Pair("Action", "10002"),
Pair("CEO", "10142"),
Pair("Webtoons", "10012"),
Pair("Historical", "10021"),
Pair("Adventure", "10003"),
Pair("Josei", "10059"),
Pair("Smut", "10047"),
Pair("Supernatural", "10018"),
Pair("School life", "10017"),
Pair("Completed", "10423"),
Pair("Possessive", "10284"),
Pair("Manhua", "10010"),
Pair("Sweet", "10282"),
Pair("Harem", "10007"),
Pair("Slice of life", "10026"),
Pair("Girl Power", "10144"),
Pair("Martial arts", "10013"),
Pair("Chinese Classic", "10243"),
Pair("BL", "10262"),
Pair("Manhwa", "10039"),
Pair("Adult", "10030"),
Pair("Shounen", "10009"),
Pair("TimeTravel", "10143"),
Pair("Shoujo", "10054"),
Pair("Ecchi", "10027"),
Pair("Revenge", "10556"),
),
)
private class CharFilter : UriPartFilter(
"Alphabet",
"charCategoryId",
arrayOf(
Pair("All", ""),
Pair("A", "10015"),
Pair("B", "10028"),
Pair("C", "10055"),
Pair("D", "10034"),
Pair("E", "10049"),
Pair("F", "10056"),
Pair("G", "10023"),
Pair("H", "10037"),
Pair("I", "10035"),
Pair("J", "10060"),
Pair("K", "10022"),
Pair("L", "10046"),
Pair("M", "10020"),
Pair("N", "10044"),
Pair("O", "10024"),
Pair("P", "10048"),
Pair("Q", "10051"),
Pair("R", "10025"),
Pair("S", "10011"),
Pair("T", "10001"),
Pair("U", "10058"),
Pair("V", "10016"),
Pair("W", "10052"),
Pair("X", "10061"),
Pair("Y", "10036"),
Pair("Z", "10101"),
),
)
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.6 KiB

View File

@ -1,120 +0,0 @@
package eu.kanade.tachiyomi.extension.zh.onemanhua
import eu.kanade.tachiyomi.multisrc.colamanga.ColaManga
import eu.kanade.tachiyomi.multisrc.colamanga.UriPartFilter
import eu.kanade.tachiyomi.source.model.FilterList
class Onemanhua : ColaManga("COLAMANGA", "https://www.colamanga.com", "zh") {
override val id = 8252565807829914103 // name used to be "One漫画"
override fun popularMangaNextPageSelector() = "a:contains(下页):not(.fed-btns-disad)"
override val statusTitle = "状态"
override val authorTitle = "作者"
override val genreTitle = "类别"
override val statusOngoing = "连载中"
override val statusCompleted = "已完结"
override fun getFilterList(): FilterList {
val filters = buildList {
addAll(super.getFilterList().list)
add(SortFilter())
add(CategoryFilter())
add(CharFilter())
add(StatusFilter())
}
return FilterList(filters)
}
private class StatusFilter : UriPartFilter(
"状态",
"status",
arrayOf(
Pair("全部", ""),
Pair("连载中", "1"),
Pair("已完结", "2"),
),
)
private class SortFilter : UriPartFilter(
"排序",
"orderBy",
arrayOf(
Pair("更新日", "update"),
Pair("日点击", "dailyCount"),
Pair("周点击", "weeklyCount"),
Pair("月点击", "monthlyCount"),
),
1,
)
private class CategoryFilter : UriPartFilter(
"类型",
"mainCategoryId",
arrayOf(
Pair("全部", ""),
Pair("热血", "10023"),
Pair("玄幻", "10024"),
Pair("恋爱", "10126"),
Pair("冒险", "10210"),
Pair("古风", "10143"),
Pair("都市", "10124"),
Pair("穿越", "10129"),
Pair("奇幻", "10242"),
Pair("其他", "10560"),
Pair("少男", "10641"),
Pair("搞笑", "10122"),
Pair("战斗", "10309"),
Pair("冒险热血", "11224"),
Pair("重生", "10461"),
Pair("爆笑", "10201"),
Pair("逆袭", "10943"),
Pair("后宫", "10138"),
Pair("少年", "10321"),
Pair("少女", "10301"),
Pair("熱血", "12044"),
Pair("系统", "10722"),
Pair("动作", "10125"),
Pair("校园", "10131"),
Pair("冒險", "12123"),
Pair("修真", "10133"),
Pair("修仙", "10453"),
Pair("剧情", "10480"),
Pair("霸总", "10127"),
Pair("大女主", "10706"),
Pair("生活", "10142"),
),
)
private class CharFilter : UriPartFilter(
"字母",
"charCategoryId",
arrayOf(
Pair("全部", ""),
Pair("A", "10182"),
Pair("B", "10081"),
Pair("C", "10134"),
Pair("D", "10001"),
Pair("E", "10238"),
Pair("F", "10161"),
Pair("G", "10225"),
Pair("H", "10137"),
Pair("I", "10284"),
Pair("J", "10141"),
Pair("K", "10283"),
Pair("L", "10132"),
Pair("M", "10136"),
Pair("N", "10130"),
Pair("O", "10282"),
Pair("P", "10262"),
Pair("Q", "10164"),
Pair("R", "10240"),
Pair("S", "10121"),
Pair("T", "10123"),
Pair("U", "11184"),
Pair("V", "11483"),
Pair("W", "10135"),
Pair("X", "10061"),
Pair("Y", "10082"),
Pair("Z", "10128"),
),
)
}

View File

@ -13,9 +13,6 @@ import rx.Observable
import java.util.Calendar
class Manga1000 : FMReader("Manga1000", "https://manga1000.top", "ja") {
override val infoElementSelector = "div.row div.row"
// source is picky about URL format
private fun mangaRequest(sortBy: String, page: Int): Request {
return GET("$baseUrl/manga-list.html?listType=pagination&page=$page&artist=&author=&group=&m_status=&name=&genre=&ungenre=&magazine=&sort=$sortBy&sort_type=DESC", headers)
@ -28,7 +25,7 @@ class Manga1000 : FMReader("Manga1000", "https://manga1000.top", "ja") {
override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> {
val slug = manga.url.substringAfter("manga-").substringBefore(".html")
return client.newCall(GET("$baseUrl/app/manga/controllers/cont.Listchapter.php?slug=$slug", headers))
return client.newCall(GET("$baseUrl/app/manga/controllers/cont.Listchapterapi.php?slug=$slug", headers))
.asObservableSuccess()
.map { res ->
res.asJsoup().select(".at-series a").map {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.6 KiB

View File

@ -1,96 +0,0 @@
package eu.kanade.tachiyomi.extension.ja.idolgravureprincessdate
import eu.kanade.tachiyomi.multisrc.gravureblogger.GravureBlogger
class IdolGravureprincessDate : GravureBlogger(
"Idol. gravureprincess .date",
"https://idol.gravureprincess.date",
"ja",
) {
override val labelFilters = buildMap {
put("Idol", getIdols())
put("Magazines", getMagazine())
}
private fun getIdols() = listOf(
"Nogizaka46",
"AKB48",
"NMB48",
"Keyakizaka46",
"HKT48",
"SKE48",
"NGT48",
"SUPER☆GiRLS",
"Morning Musume",
"Dempagumi.inc",
"Angerme",
"Juice=Juice",
"NijiCon-虹コン",
"Houkago Princess",
"Magical Punchline",
"Idoling!!!",
"Rev. from DVL",
"Link STAR`s",
"LADYBABY",
"℃-ute",
"Country Girls",
"Up Up Girls (Kakko Kari)",
"Yumemiru Adolescence",
"Shiritsu Ebisu Chugaku",
"Tenkoushoujo Kagekidan",
"Drop",
"Steam Girls",
"Kamen Joshi's",
"LinQ",
"Doll☆Element",
"TrySail",
"Akihabara Backstage Pass",
"Palet",
"Passport☆",
"Ange☆Reve",
"BiSH",
"Ciao Bella Cinquetti",
"Gekidanherbest",
"Haraeki Stage Ace",
"Ru:Run",
"SDN48",
)
private fun getMagazine() = listOf(
"FLASH",
"Weekly Playboy",
"FRIDAY Magazine",
"Young Jump",
"Young Magazine",
"BLT",
"ENTAME",
"EX-Taishu",
"SPA! Magazine",
"Young Gangan",
"UTB",
"Young Animal",
"Young Champion",
"Big Comic Spirtis",
"Shonen Magazine",
"BUBKA",
"BOMB",
"Shonen Champion",
"Manga Action",
"Weekly Shonen Sunday",
"Photobooks",
"BRODY",
"Hustle Press",
"ANAN Magazine",
"SMART Magazine",
"Young Sunday",
"Gravure The Television",
"CD&DL My Girl",
"Daily LoGiRL",
"Shukan Taishu",
"Girls! Magazine",
"Soccer Game King",
"Weekly Georgia",
"Sunday Magazine",
"Mery Magazine",
)
}

View File

@ -1,62 +0,0 @@
package eu.kanade.tachiyomi.extension.ja.micmicidol
import eu.kanade.tachiyomi.multisrc.gravureblogger.GravureBlogger
class MicMicIdol : GravureBlogger("MIC MIC IDOL", "https://www.micmicidol.club", "ja") {
override val labelFilters = buildMap {
put("Type", getTypes())
put("Japan Magazine", getJapanMagazines())
put("Japan Fashion", getJapanFashion())
}
private fun getJapanMagazines() = listOf(
"cyzo",
"EnTame",
"EX大衆",
"Friday",
"Flash",
"Shonen Magazine",
"Shonen Sunday",
"Weekly Shonen Champion",
"Weekly Big Comic Spirits",
"Weekly Jitsuwa",
"Weekly Playboy",
"Weekly SPA!",
"Young Animal",
"Young Champion",
"Young Gangan",
"Young Jump",
"Young Magazine",
)
private fun getJapanFashion() = listOf(
"andGIRL",
"aR",
"Baila",
"Biteki",
"CanCam",
"Classy",
"ELLE Japan",
"Ginger",
"JJ",
"Maquia",
"Mina",
"MORE",
"Non-no",
"Oggi",
"Ray",
"Scawaii",
"Steady",
"ViVi",
"VoCE",
"With",
)
private fun getTypes() = listOf(
"- Cover",
"- Japan Magazine",
"- Japan Fashion Magazine",
"- Japan Idol Photobook",
"- Asia Idol",
)
}

View File

@ -0,0 +1,62 @@
package eu.kanade.tachiyomi.extension.es.atlantisscan
import eu.kanade.tachiyomi.multisrc.madara.Madara
import eu.kanade.tachiyomi.network.POST
import eu.kanade.tachiyomi.network.interceptor.rateLimit
import okhttp3.FormBody
import okhttp3.OkHttpClient
import okhttp3.Request
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.concurrent.TimeUnit
class AtlantisScan : Madara(
"Atlantis Scan",
"https://scansatlanticos.com",
"es",
dateFormat = SimpleDateFormat("dd/MM/yyyy", Locale.US),
) {
override val id: Long = 2237642340381856331
override val client: OkHttpClient = super.client.newBuilder()
.rateLimit(2, 1, TimeUnit.SECONDS)
.build()
override val useNewChapterEndpoint = true
override fun popularMangaNextPageSelector() = "body:not(:has(.no-posts))"
private fun loadMoreRequest(page: Int, metaKey: String): Request {
val formBody = FormBody.Builder().apply {
add("action", "madara_load_more")
add("page", page.toString())
add("template", "madara-core/content/content-archive")
add("vars[paged]", "1")
add("vars[orderby]", "meta_value_num")
add("vars[template]", "archive")
add("vars[sidebar]", "full")
add("vars[post_type]", "wp-manga")
add("vars[post_status]", "publish")
add("vars[meta_key]", metaKey)
add("vars[order]", "desc")
add("vars[meta_query][relation]", "AND")
add("vars[manga_archives_item_layout]", "big_thumbnail")
}.build()
val xhrHeaders = headersBuilder()
.add("Content-Length", formBody.contentLength().toString())
.add("Content-Type", formBody.contentType().toString())
.add("X-Requested-With", "XMLHttpRequest")
.build()
return POST("$baseUrl/wp-admin/admin-ajax.php", xhrHeaders, formBody)
}
override fun popularMangaRequest(page: Int): Request {
return loadMoreRequest(page - 1, "_wp_manga_views")
}
override fun latestUpdatesRequest(page: Int): Request {
return loadMoreRequest(page - 1, "_latest_update")
}
}

View File

@ -8,7 +8,7 @@ import java.util.concurrent.TimeUnit
class Jiangzaitoon : Madara(
"Jiangzaitoon",
"https://jiangzaitoon.info",
"https://jiangzaitoon.cc",
"tr",
SimpleDateFormat("d MMM yyy", Locale("tr")),
) {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

View File

@ -1,30 +0,0 @@
package eu.kanade.tachiyomi.extension.tr.mangagezgini
import eu.kanade.tachiyomi.multisrc.madara.Madara
import eu.kanade.tachiyomi.source.model.SChapter
import org.jsoup.nodes.Element
import java.text.SimpleDateFormat
import java.util.Locale
class MangaGezgini : Madara(
"MangaGezgini",
"https://mangagezgini.com",
"tr",
SimpleDateFormat("dd/MM/yyy", Locale("tr")),
) {
override fun chapterFromElement(element: Element): SChapter {
val chapter = SChapter.create()
with(element) {
select(chapterUrlSelector).first()?.let { urlElement ->
chapter.url = urlElement.attr("abs:href").let {
it.substringBefore("?style=paged") + if (!it.endsWith(chapterUrlSuffix)) chapterUrlSuffix else ""
}
chapter.name = element.select("li.wp-manga-chapter.has-thumb a").text()
}
chapter.date_upload = select("img:not(.thumb)").firstOrNull()?.attr("alt")?.let { parseRelativeDate(it) }
?: select("span a").firstOrNull()?.attr("title")?.let { parseRelativeDate(it) }
?: parseChapterDate(select(chapterDateSelector()).firstOrNull()?.text())
}
return chapter
}
}

View File

@ -11,11 +11,11 @@ import uy.kohesive.injekt.api.get
import java.text.SimpleDateFormat
import java.util.Locale
class Mangalink : Madara("مانجا لينك", "https://manga-link.com", "ar", SimpleDateFormat("MMMM dd, yyyy", Locale("ar"))) {
class Mangalink : Madara("مانجا لينك", "https://manga-link.net", "ar", SimpleDateFormat("MMMM dd, yyyy", Locale("ar"))) {
override val chapterUrlSuffix = ""
private val defaultBaseUrl = "https://manga-link.com"
private val defaultBaseUrl = "https://manga-link.net"
override val baseUrl by lazy { getPrefBaseUrl() }
private val preferences: SharedPreferences by lazy {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

View File

@ -1,12 +0,0 @@
package eu.kanade.tachiyomi.extension.tr.mangawow
import eu.kanade.tachiyomi.multisrc.madara.Madara
import java.text.SimpleDateFormat
import java.util.Locale
class MangaWOW : Madara(
"MangaWOW",
"https://mangawow.org",
"tr",
SimpleDateFormat("MMMM dd, yyyy", Locale("tr")),
)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

View File

@ -1,21 +0,0 @@
package eu.kanade.tachiyomi.extension.pt.ninjascan
import eu.kanade.tachiyomi.multisrc.madara.Madara
import eu.kanade.tachiyomi.network.interceptor.rateLimit
import java.text.SimpleDateFormat
import java.util.Locale
class NinjaScan : Madara(
"Ninja Scan",
"https://ninjascan.site",
"pt-BR",
SimpleDateFormat("dd 'de' MMMMM 'de' yyyy", Locale("pt", "BR")),
) {
override val client = super.client.newBuilder()
.rateLimit(2)
.build()
override val useNewChapterEndpoint = true
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
}

View File

@ -6,12 +6,10 @@ import java.util.Locale
class SamuraiScan : Madara(
"SamuraiScan",
"https://samuraiscan.org",
"https://samuraiscan.com",
"es",
SimpleDateFormat("d MMMM, yyyy", Locale("es")),
SimpleDateFormat("MMMM d, yyyy", Locale("es")),
) {
override val mangaSubString = "l"
override val useNewChapterEndpoint = true
override val mangaDetailsSelectorDescription = "div.summary_content div.manga-summary"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

View File

@ -1,15 +0,0 @@
package eu.kanade.tachiyomi.extension.en.stonescape
import eu.kanade.tachiyomi.multisrc.madara.Madara
import java.text.SimpleDateFormat
import java.util.Locale
class StoneScape : Madara(
"StoneScape",
"https://stonescape.xyz",
"en",
SimpleDateFormat("MMMM dd, yyyy", Locale("en")),
) {
override val mangaSubString = "series"
override val chapterUrlSelector = "div + a"
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

View File

@ -1,21 +0,0 @@
package eu.kanade.tachiyomi.extension.pt.sussyscan
import eu.kanade.tachiyomi.multisrc.madara.Madara
import eu.kanade.tachiyomi.network.interceptor.rateLimit
import java.text.SimpleDateFormat
import java.util.Locale
class SussyScan : Madara(
"Sussy Scan",
"https://sussyscan.com",
"pt-BR",
SimpleDateFormat("MMMMM dd, yyyy", Locale("pt", "BR")),
) {
override val client = super.client.newBuilder()
.rateLimit(2)
.build()
override val useNewChapterEndpoint = true
override val mangaSubString = "sus"
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

View File

@ -1,8 +0,0 @@
package eu.kanade.tachiyomi.extension.zh.hanman18
import eu.kanade.tachiyomi.multisrc.manga18.Manga18
class HANMAN18 : Manga18("HANMAN18", "https://hanman18.com", "zh") {
// tag filter doesn't work on site
override val getAvailableTags = false
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

View File

@ -1,16 +0,0 @@
package eu.kanade.tachiyomi.extension.en.hentai3zcc
import eu.kanade.tachiyomi.multisrc.manga18.Manga18
import eu.kanade.tachiyomi.source.model.SManga
import org.jsoup.nodes.Element
class Hentai3zCC : Manga18("Hentai3z.CC", "https://hentai3z.cc", "en") {
override fun popularMangaFromElement(element: Element) = SManga.create().apply {
setUrlWithoutDomain(element.selectFirst("a")!!.absUrl("href"))
title = element.selectFirst("div.mg_info > div.mg_name a")!!.text()
thumbnail_url = element.selectFirst("img")?.absUrl("src")
?.replace("cover_thumb_2.webp", "cover_250x350.jpg")
?.replace("admin.manga18.us", "bk.18porncomic.com")
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

View File

@ -1,251 +0,0 @@
package eu.kanade.tachiyomi.extension.ja.rawotaku
import eu.kanade.tachiyomi.multisrc.mangareader.MangaReader
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.asObservableSuccess
import eu.kanade.tachiyomi.network.interceptor.rateLimit
import eu.kanade.tachiyomi.source.model.Filter
import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.util.asJsoup
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.Request
import okhttp3.Response
import org.jsoup.Jsoup
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import org.jsoup.nodes.TextNode
import org.jsoup.select.Evaluator
import rx.Observable
import java.net.URLEncoder
class RawOtaku : MangaReader() {
override val name = "Raw Otaku"
override val lang = "ja"
override val baseUrl = "https://rawotaku.com"
override val client = network.cloudflareClient.newBuilder()
.rateLimit(2)
.build()
override fun headersBuilder() = super.headersBuilder()
.add("Referer", "$baseUrl/")
// ============================== Popular ===============================
override fun popularMangaRequest(page: Int) =
GET("$baseUrl/filter/?type=all&status=all&language=all&sort=most-viewed&p=$page", headers)
// =============================== Latest ===============================
override fun latestUpdatesRequest(page: Int) =
GET("$baseUrl/filter/?type=all&status=all&language=all&sort=latest-updated&p=$page", headers)
// =============================== Search ===============================
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
val url = baseUrl.toHttpUrl().newBuilder().apply {
if (query.isNotBlank()) {
addQueryParameter("q", query)
} else {
addPathSegment("filter")
addPathSegment("")
filters.ifEmpty(::getFilterList).forEach { filter ->
when (filter) {
is TypeFilter -> {
addQueryParameter(filter.param, filter.selection)
}
is StatusFilter -> {
addQueryParameter(filter.param, filter.selection)
}
is LanguageFilter -> {
addQueryParameter(filter.param, filter.selection)
}
is SortFilter -> {
addQueryParameter(filter.param, filter.selection)
}
is GenresFilter -> {
filter.state.forEach {
if (it.state) {
addQueryParameter(filter.param, it.id)
}
}
}
else -> { }
}
}
}
addQueryParameter("p", page.toString())
}.build()
return GET(url, headers)
}
override fun searchMangaSelector() = ".manga_list-sbs .manga-poster"
override fun searchMangaFromElement(element: Element) =
SManga.create().apply {
setUrlWithoutDomain(element.attr("href"))
element.selectFirst(Evaluator.Tag("img"))!!.let {
title = it.attr("alt")
thumbnail_url = it.imgAttr()
}
}
override fun searchMangaNextPageSelector() = "ul.pagination > li.active + li"
// =============================== Filters ==============================
override fun getFilterList() =
FilterList(
Note,
Filter.Separator(),
TypeFilter(),
StatusFilter(),
LanguageFilter(),
SortFilter(),
GenresFilter(),
)
// =========================== Manga Details ============================
override fun mangaDetailsParse(document: Document) = SManga.create().apply {
val root = document.selectFirst(Evaluator.Id("ani_detail"))!!
val mangaTitle = root.selectFirst(Evaluator.Class("manga-name"))!!.ownText()
title = mangaTitle
description = buildString {
root.selectFirst(".description")?.ownText()?.let { append(it) }
append("\n\n")
root.selectFirst(".manga-name-or")?.ownText()?.let {
if (it.isNotEmpty() && it != mangaTitle) {
append("Alternative Title: ")
append(it)
}
}
}.trim()
thumbnail_url = root.selectFirst(Evaluator.Tag("img"))!!.imgAttr()
genre = root.selectFirst(Evaluator.Class("genres"))!!.children().joinToString { it.ownText() }
for (item in root.selectFirst(Evaluator.Class("anisc-info"))!!.children()) {
if (item.hasClass("item").not()) continue
when (item.selectFirst(Evaluator.Class("item-head"))!!.ownText()) {
"著者:" -> item.parseAuthorsTo(this)
"地位:" -> status = when (item.selectFirst(Evaluator.Class("name"))!!.ownText().lowercase()) {
"ongoing" -> SManga.ONGOING
"completed" -> SManga.COMPLETED
"on-hold" -> SManga.ON_HIATUS
"canceled" -> SManga.CANCELLED
else -> SManga.UNKNOWN
}
}
}
}
private fun Element.parseAuthorsTo(manga: SManga) {
val authors = select(Evaluator.Tag("a"))
val text = authors.map { it.ownText().replace(",", "") }
val count = authors.size
when (count) {
0 -> return
1 -> {
manga.author = text[0]
return
}
}
val authorList = ArrayList<String>(count)
val artistList = ArrayList<String>(count)
for ((index, author) in authors.withIndex()) {
val textNode = author.nextSibling() as? TextNode
val list = if (textNode != null && "(Art)" in textNode.wholeText) artistList else authorList
list.add(text[index])
}
if (authorList.isEmpty().not()) manga.author = authorList.joinToString()
if (artistList.isEmpty().not()) manga.artist = artistList.joinToString()
}
// ============================== Chapters ==============================
override fun chapterListRequest(mangaUrl: String, type: String): Request =
GET(baseUrl + mangaUrl, headers)
override fun parseChapterElements(response: Response, isVolume: Boolean): List<Element> {
TODO("Not yet implemented")
}
override val chapterType = ""
override val volumeType = ""
override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> {
return client.newCall(chapterListRequest(manga))
.asObservableSuccess()
.map(::parseChapterList)
}
private fun parseChapterList(response: Response): List<SChapter> {
val document = response.use { it.asJsoup() }
return document.select(chapterListSelector())
.map(::chapterFromElement)
}
private fun chapterListSelector(): String = "#ja-chaps > .chapter-item"
private fun chapterFromElement(element: Element): SChapter = SChapter.create().apply {
val id = element.attr("data-id")
element.selectFirst("a")!!.run {
setUrlWithoutDomain(attr("href") + "#$id")
name = selectFirst(".name")?.text() ?: text()
}
}
// =============================== Pages ================================
override fun fetchPageList(chapter: SChapter): Observable<List<Page>> = Observable.fromCallable {
val id = chapter.url.substringAfterLast("#")
val ajaxHeaders = super.headersBuilder().apply {
add("Accept", "application/json, text/javascript, */*; q=0.01")
add("Referer", URLEncoder.encode(baseUrl + chapter.url.substringBeforeLast("#"), "utf-8"))
add("X-Requested-With", "XMLHttpRequest")
}.build()
val ajaxUrl = "$baseUrl/json/chapter?mode=vertical&id=$id"
client.newCall(GET(ajaxUrl, ajaxHeaders)).execute().let(::pageListParse)
}
override fun pageListParse(response: Response): List<Page> {
val document = response.use { it.parseHtmlProperty() }
val pageList = document.select(".container-reader-chapter > div > img").map {
val index = it.attr("alt").toInt()
val imgUrl = it.imgAttr()
Page(index, imageUrl = imgUrl)
}
return pageList
}
// ============================= Utilities ==============================
private fun Element.imgAttr(): String = when {
hasAttr("data-lazy-src") -> attr("abs:data-lazy-src")
hasAttr("data-src") -> attr("abs:data-src")
else -> attr("abs:src")
}
private fun Response.parseHtmlProperty(): Document {
val html = Json.parseToJsonElement(body.string()).jsonObject["html"]!!.jsonPrimitive.content
return Jsoup.parseBodyFragment(html)
}
}

View File

@ -1,110 +0,0 @@
package eu.kanade.tachiyomi.extension.ja.rawotaku
import eu.kanade.tachiyomi.source.model.Filter
object Note : Filter.Header("NOTE: Ignored if using text search!")
sealed class Select(
name: String,
val param: String,
values: Array<String>,
) : Filter.Select<String>(name, values) {
open val selection: String
get() = if (state == 0) "" else state.toString()
}
class TypeFilter(
values: Array<String> = types.keys.toTypedArray(),
) : Select("タイプ", "type", values) {
override val selection: String
get() = types[values[state]]!!
companion object {
private val types = mapOf(
"全て" to "all",
"Raw Manga" to "Raw Manga",
"BLコミック" to "BLコミック",
"TLコミック" to "TLコミック",
"オトナコミック" to "オトナコミック",
"女性マンガ" to "女性マンガ",
"少女マンガ" to "少女マンガ",
"少年マンガ" to "少年マンガ",
"青年マンガ" to "青年マンガ",
)
}
}
class StatusFilter(
values: Array<String> = statuses.keys.toTypedArray(),
) : Select("地位", "status", values) {
override val selection: String
get() = statuses[values[state]]!!
companion object {
private val statuses = mapOf(
"全て" to "all",
"Publishing" to "Publishing",
"Finished" to "Finished",
)
}
}
class LanguageFilter(
values: Array<String> = languages.keys.toTypedArray(),
) : Select("言語", "language", values) {
override val selection: String
get() = languages[values[state]]!!
companion object {
private val languages = mapOf(
"全て" to "all",
"Japanese" to "ja",
"English" to "en",
)
}
}
class SortFilter(
values: Array<String> = sort.keys.toTypedArray(),
) : Select("選別", "sort", values) {
override val selection: String
get() = sort[values[state]]!!
companion object {
private val sort = mapOf(
"デフォルト" to "default",
"最新の更新" to "latest-updated",
"最も見られました" to "most-viewed",
"Title [A-Z]" to "title-az",
"Title [Z-A]" to "title-za",
)
}
}
class Genre(name: String, val id: String) : Filter.CheckBox(name)
class GenresFilter(
values: List<Genre> = genres,
) : Filter.Group<Genre>("ジャンル", values) {
val param = "genre[]"
companion object {
private val genres: List<Genre>
get() = listOf(
Genre("アクション", "55"),
Genre("エッチ", "15706"),
Genre("コメディ", "91"),
Genre("ドラマ", "56"),
Genre("ハーレム", "20"),
Genre("ファンタジー", "1"),
Genre("冒険", "54"),
Genre("悪魔", "6820"),
Genre("武道", "1064"),
Genre("歴史的", "9600"),
Genre("警察・特殊部隊", "6089"),
Genre("車・バイク", "4329"),
Genre("音楽", "473"),
Genre("魔法", "1416"),
)
}
}

View File

@ -1,22 +0,0 @@
package eu.kanade.tachiyomi.extension.es.atlantisscan
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
import eu.kanade.tachiyomi.network.interceptor.rateLimit
import okhttp3.OkHttpClient
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.concurrent.TimeUnit
class AtlantisScan : MangaThemesia(
"Atlantis Scan",
"https://scansatlanticos.com",
"es",
dateFormat = SimpleDateFormat("MMMM dd, yyyy", Locale.US),
) {
// Site moved from Madara to MangaThemesia
override val versionId = 2
override val client: OkHttpClient = super.client.newBuilder()
.rateLimit(2, 1, TimeUnit.SECONDS)
.build()
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

View File

@ -1,12 +0,0 @@
package eu.kanade.tachiyomi.extension.id.comicaso
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
import java.text.SimpleDateFormat
import java.util.Locale
class Comicaso : MangaThemesia(
"Comicaso",
"https://comicaso.com",
"id",
dateFormat = SimpleDateFormat("MMMM d, yyyy", Locale("id")),
)

View File

@ -1,27 +0,0 @@
package eu.kanade.tachiyomi.extension.id.comicsekai
import android.util.Base64
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
import eu.kanade.tachiyomi.source.model.Page
import kotlinx.serialization.json.jsonArray
import kotlinx.serialization.json.jsonPrimitive
import org.jsoup.nodes.Document
class Comicsekai : MangaThemesia("Comicsekai", "http://www.comicsekai.com", "id") {
override fun pageListParse(document: Document): List<Page> {
// "ts_reader.run({" in base64
val script = document.selectFirst("script[src^=data:text/javascript;base64,dHNfcmVhZGVyLnJ1bih7]")
?: return super.pageListParse(document)
val data = Base64.decode(script.attr("src").substringAfter("base64,"), Base64.DEFAULT).toString(Charsets.UTF_8)
val imageListJson = JSON_IMAGE_LIST_REGEX.find(data)?.destructured?.toList()?.get(0).orEmpty()
val imageList = try {
json.parseToJsonElement(imageListJson).jsonArray
} catch (_: IllegalArgumentException) {
emptyList()
}
return imageList.mapIndexed { i, jsonEl ->
Page(i, imageUrl = jsonEl.jsonPrimitive.content)
}
}
}

View File

@ -1,12 +0,0 @@
package eu.kanade.tachiyomi.extension.th.dragonmanga
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
import java.text.SimpleDateFormat
import java.util.Locale
class DragonManga : MangaThemesia(
"DragonManga",
"https://www.dragon-manga.com",
"th",
dateFormat = SimpleDateFormat("MMMM d, yyyy", Locale("th")),
)

View File

@ -8,7 +8,7 @@ import java.util.Locale
class InariManga : MangaThemesia(
"InariManga",
"https://inarimanga.net",
"https://inarimanga.com",
"es",
dateFormat = SimpleDateFormat("MMMM dd, yyyy", Locale("en")),
) {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 978 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

View File

@ -1,12 +0,0 @@
package eu.kanade.tachiyomi.extension.pt.irisscanlator
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
import java.text.SimpleDateFormat
import java.util.Locale
class IrisScanlator : MangaThemesia(
"Iris Scanlator",
"https://irisscanlator.com.br",
"pt-BR",
dateFormat = SimpleDateFormat("MMMM d, yyyy", Locale("pt", "BR")),
)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Some files were not shown because too many files have changed in this diff Show More