diff --git a/src/en/holymanga/build.gradle b/src/all/zbulu/build.gradle similarity index 50% rename from src/en/holymanga/build.gradle rename to src/all/zbulu/build.gradle index 5f1256329..36463a576 100644 --- a/src/en/holymanga/build.gradle +++ b/src/all/zbulu/build.gradle @@ -2,10 +2,10 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' ext { - appName = 'Tachiyomi: HolyManga & HeavenManga' - pkgNameSuffix = 'en.holymanga' - extClass = '.HMangaFactory' - extVersionCode = 3 + appName = 'Tachiyomi: zBulu' + pkgNameSuffix = 'all.zbulu' + extClass = '.ZbuluFactory' + extVersionCode = 1 libVersion = '1.2' } diff --git a/src/all/zbulu/res/mipmap-hdpi/ic_launcher.png b/src/all/zbulu/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 000000000..6fc1607d3 Binary files /dev/null and b/src/all/zbulu/res/mipmap-hdpi/ic_launcher.png differ diff --git a/src/all/zbulu/res/mipmap-mdpi/ic_launcher.png b/src/all/zbulu/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 000000000..abd1b9061 Binary files /dev/null and b/src/all/zbulu/res/mipmap-mdpi/ic_launcher.png differ diff --git a/src/all/zbulu/res/mipmap-xhdpi/ic_launcher.png b/src/all/zbulu/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 000000000..74a24c316 Binary files /dev/null and b/src/all/zbulu/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/src/all/zbulu/res/mipmap-xxhdpi/ic_launcher.png b/src/all/zbulu/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..137f81d7d Binary files /dev/null and b/src/all/zbulu/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/src/all/zbulu/res/mipmap-xxxhdpi/ic_launcher.png b/src/all/zbulu/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 000000000..e1f0e22be Binary files /dev/null and b/src/all/zbulu/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/src/all/zbulu/res/web_hi_res_512.png b/src/all/zbulu/res/web_hi_res_512.png new file mode 100644 index 000000000..83a4dd0be Binary files /dev/null and b/src/all/zbulu/res/web_hi_res_512.png differ diff --git a/src/en/holymanga/src/eu/kanade/tachiyomi/extension/en/holymanga/HManga.kt b/src/all/zbulu/src/eu/kanade/tachiyomi/extension/all/zbulu/Zbulu.kt similarity index 70% rename from src/en/holymanga/src/eu/kanade/tachiyomi/extension/en/holymanga/HManga.kt rename to src/all/zbulu/src/eu/kanade/tachiyomi/extension/all/zbulu/Zbulu.kt index 1f9bec638..5a6968240 100644 --- a/src/en/holymanga/src/eu/kanade/tachiyomi/extension/en/holymanga/HManga.kt +++ b/src/all/zbulu/src/eu/kanade/tachiyomi/extension/all/zbulu/Zbulu.kt @@ -1,4 +1,4 @@ -package eu.kanade.tachiyomi.extension.en.holymanga +package eu.kanade.tachiyomi.extension.all.zbulu import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.source.model.Filter @@ -10,43 +10,54 @@ import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.util.asJsoup import java.text.SimpleDateFormat import java.util.Locale +import java.util.concurrent.TimeUnit +import okhttp3.Headers import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.Response import org.jsoup.nodes.Document import org.jsoup.nodes.Element -abstract class HManga( +abstract class Zbulu( override val name: String, - override val baseUrl: String + override val baseUrl: String, + override val lang: String = "en" ) : ParsedHttpSource() { - override val lang = "en" - override val supportsLatest = true - override val client: OkHttpClient = network.cloudflareClient + override val client: OkHttpClient = network.cloudflareClient.newBuilder() + .connectTimeout(1, TimeUnit.MINUTES) + .readTimeout(1, TimeUnit.MINUTES) + .writeTimeout(1, TimeUnit.MINUTES) + .build() + + override fun headersBuilder(): Headers.Builder = Headers.Builder() + .add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:75.0) Gecko/20100101 Firefox/75.0") + .add("Content-Encoding", "identity") + + // Decreases calls, helps with Cloudflare + private fun String.addTrailingSlash() = if (!this.endsWith("/")) "$this/" else this // Popular - // This returns 12 manga or so, main browsing for this source should be through latest override fun popularMangaRequest(page: Int): Request { - return GET(baseUrl, headers) + return GET("$baseUrl/manga-list/page-$page/", headers) } - override fun popularMangaSelector() = "section#popular div.entry.vertical" + override fun popularMangaSelector() = "div.comics-grid > div.entry" override fun popularMangaFromElement(element: Element): SManga { - val manga = SManga.create() - element.select("h2 a").let { - manga.setUrlWithoutDomain(it.attr("href")) - manga.title = it.text() + return SManga.create().apply { + element.select("h3 a").let { + setUrlWithoutDomain(it.attr("href").addTrailingSlash()) + title = it.text() + } + thumbnail_url = element.select("img").first().attr("abs:src") } - manga.thumbnail_url = element.select("img").first().attr("src") - return manga } - override fun popularMangaNextPageSelector() = "Not needed" + override fun popularMangaNextPageSelector() = "a.next:has(i.fa-angle-right)" // Latest @@ -54,19 +65,11 @@ abstract class HManga( return GET("$baseUrl/latest-update/page-$page/", headers) } - override fun latestUpdatesSelector() = "div.comics-grid > div.entry" + override fun latestUpdatesSelector() = popularMangaSelector() - override fun latestUpdatesFromElement(element: Element): SManga { - val manga = SManga.create() - element.select("h3 a").let { - manga.setUrlWithoutDomain(it.attr("href")) - manga.title = it.text() - } - manga.thumbnail_url = element.select("img").first().attr("src") - return manga - } + override fun latestUpdatesFromElement(element: Element): SManga = popularMangaFromElement(element) - override fun latestUpdatesNextPageSelector() = "a.next:has(i.fa-angle-right)" + override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector() // Search @@ -78,7 +81,7 @@ abstract class HManga( lateinit var genre: String filters.forEach { filter -> when (filter) { - is TextField -> { + is AuthorField -> { if (filter.state.isNotBlank()) { ret = "$baseUrl/author/${filter.state.replace(" ", "-")}/page-$page" } @@ -107,15 +110,14 @@ abstract class HManga( override fun mangaDetailsParse(document: Document): SManga { val infoElement = document.select("div.single-comic").first() - val manga = SManga.create() - manga.title = infoElement.select("h1").first().text() - manga.author = infoElement.select("div.author a").text() - val status = infoElement.select("div.update span[style]").text() - manga.status = parseStatus(status) - manga.genre = infoElement.select("div.genre").text().substringAfter("Genre(s): ") - manga.description = infoElement.select("div.comic-description p").text() - manga.thumbnail_url = infoElement.select("img").attr("src") - return manga + return SManga.create().apply { + title = infoElement.select("h1").first().text() + author = infoElement.select("div.author a").text() + status = parseStatus(infoElement.select("div.update span[style]").text()) + genre = infoElement.select("div.genre a").joinToString { it.text() } + description = infoElement.select("div.comic-description p").text() + thumbnail_url = infoElement.select("img").attr("abs:src") + } } private fun parseStatus(status: String?) = when { @@ -131,34 +133,26 @@ abstract class HManga( override fun chapterListParse(response: Response): List { val chapters = mutableListOf() - var document = response.asJsoup() - var continueParsing = true - // Chapter list is paginated - while (continueParsing) { + // Chapter list may be paginated, get recursively + fun addChapters(document: Document) { document.select(chapterListSelector()).map { chapters.add(chapterFromElement(it)) } - // Next page of chapters - document.select("${latestUpdatesNextPageSelector()}:not([id])").let { - if (it.isNotEmpty()) { - document = client.newCall(GET(it.attr("abs:href"), headers)).execute().asJsoup() - } else { - continueParsing = false - } - } + document.select("${latestUpdatesNextPageSelector()}:not([id])").firstOrNull() + ?.let { addChapters(client.newCall(GET(it.attr("abs:href").addTrailingSlash(), headers)).execute().asJsoup()) } } + + addChapters(response.asJsoup()) return chapters } override fun chapterFromElement(element: Element): SChapter { - val chapter = SChapter.create() - - element.select("a").let { - chapter.setUrlWithoutDomain(it.attr("href")) - chapter.name = it.text() + return SChapter.create().apply { + element.select("a").let { + setUrlWithoutDomain(it.attr("href").addTrailingSlash()) + name = it.text() + } + date_upload = element.select("div.chapter-date")?.text()?.let { parseChapterDate(it) } ?: 0 } - chapter.date_upload = parseChapterDate(element.select("div.chapter-date").text()) - - return chapter } companion object { @@ -174,26 +168,22 @@ abstract class HManga( // Pages override fun pageListParse(document: Document): List { - val pages = mutableListOf() - - document.select("div.chapter-content img").forEach { - pages.add(Page(pages.size, "", it.attr("src"))) + return document.select("div.chapter-content img").mapIndexed { i, img -> + Page(i, "", img.attr("abs:src")) } - - return pages } override fun imageUrlParse(document: Document): String = throw UnsupportedOperationException("Not used") // Filters - private class TextField(name: String, val key: String) : Filter.Text(name) + private class AuthorField : Filter.Text("Author") override fun getFilterList() = FilterList( Filter.Header("Cannot combine search types!"), Filter.Header("Author name must be exact."), Filter.Separator("-----------------"), - TextField("Author", "author"), + AuthorField(), GenreFilter() ) diff --git a/src/all/zbulu/src/eu/kanade/tachiyomi/extension/all/zbulu/ZbuluFactory.kt b/src/all/zbulu/src/eu/kanade/tachiyomi/extension/all/zbulu/ZbuluFactory.kt new file mode 100644 index 000000000..c34517e4f --- /dev/null +++ b/src/all/zbulu/src/eu/kanade/tachiyomi/extension/all/zbulu/ZbuluFactory.kt @@ -0,0 +1,16 @@ +package eu.kanade.tachiyomi.extension.all.zbulu + +import eu.kanade.tachiyomi.source.Source +import eu.kanade.tachiyomi.source.SourceFactory + +class ZbuluFactory : SourceFactory { + override fun createSources(): List = listOf( + HolyManga(), + HeavenManga(), + KooManga() + ) +} + +class HolyManga : Zbulu("HolyManga", "https://w15.holymanga.net") +class HeavenManga : Zbulu("HeavenManga", "http://heaventoon.com") +class KooManga : Zbulu("Koo Manga", "http://ww1.koomanga.com") diff --git a/src/en/holymanga/res/mipmap-hdpi/ic_launcher.png b/src/en/holymanga/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index b428c5752..000000000 Binary files a/src/en/holymanga/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/src/en/holymanga/res/mipmap-mdpi/ic_launcher.png b/src/en/holymanga/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index 9cc40dec9..000000000 Binary files a/src/en/holymanga/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/src/en/holymanga/res/mipmap-xhdpi/ic_launcher.png b/src/en/holymanga/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index d75154001..000000000 Binary files a/src/en/holymanga/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/src/en/holymanga/res/mipmap-xxhdpi/ic_launcher.png b/src/en/holymanga/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index c981e9e36..000000000 Binary files a/src/en/holymanga/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/src/en/holymanga/res/mipmap-xxxhdpi/ic_launcher.png b/src/en/holymanga/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index 09e9732a2..000000000 Binary files a/src/en/holymanga/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/src/en/holymanga/res/web_hi_res_512.png b/src/en/holymanga/res/web_hi_res_512.png deleted file mode 100644 index 9ec51c8eb..000000000 Binary files a/src/en/holymanga/res/web_hi_res_512.png and /dev/null differ diff --git a/src/en/holymanga/src/eu/kanade/tachiyomi/extension/en/holymanga/HMangaFactory.kt b/src/en/holymanga/src/eu/kanade/tachiyomi/extension/en/holymanga/HMangaFactory.kt deleted file mode 100644 index c8daf6f46..000000000 --- a/src/en/holymanga/src/eu/kanade/tachiyomi/extension/en/holymanga/HMangaFactory.kt +++ /dev/null @@ -1,14 +0,0 @@ -package eu.kanade.tachiyomi.extension.en.holymanga - -import eu.kanade.tachiyomi.source.Source -import eu.kanade.tachiyomi.source.SourceFactory - -class HMangaFactory : SourceFactory { - override fun createSources(): List = listOf( - HolyManga(), - HeavenManga() - ) -} - -class HolyManga : HManga("HolyManga", "http://w12.holymanga.net") -class HeavenManga : HManga("HeavenManga", "http://ww8.heavenmanga.org")