diff --git a/src/en/digitalcomicmuseum/AndroidManifest.xml b/src/en/digitalcomicmuseum/AndroidManifest.xml new file mode 100644 index 000000000..b4571bfa8 --- /dev/null +++ b/src/en/digitalcomicmuseum/AndroidManifest.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/src/en/digitalcomicmuseum/build.gradle b/src/en/digitalcomicmuseum/build.gradle new file mode 100644 index 000000000..610b78c69 --- /dev/null +++ b/src/en/digitalcomicmuseum/build.gradle @@ -0,0 +1,16 @@ +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-android' + +ext { + extName = 'Digital Comic Museum' + pkgNameSuffix = 'en.digitalcomicmuseum' + extClass = '.DigitalComicMuseum' + extVersionCode = 1 +} + +dependencies { + implementation project(':lib-ratelimit') +} + +apply from: "$rootDir/common.gradle" diff --git a/src/en/digitalcomicmuseum/res/mipmap-hdpi/ic_launcher.png b/src/en/digitalcomicmuseum/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 000000000..920762543 Binary files /dev/null and b/src/en/digitalcomicmuseum/res/mipmap-hdpi/ic_launcher.png differ diff --git a/src/en/digitalcomicmuseum/res/mipmap-mdpi/ic_launcher.png b/src/en/digitalcomicmuseum/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 000000000..cdd192b7b Binary files /dev/null and b/src/en/digitalcomicmuseum/res/mipmap-mdpi/ic_launcher.png differ diff --git a/src/en/digitalcomicmuseum/res/mipmap-xhdpi/ic_launcher.png b/src/en/digitalcomicmuseum/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 000000000..41b8d4302 Binary files /dev/null and b/src/en/digitalcomicmuseum/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/src/en/digitalcomicmuseum/res/mipmap-xxhdpi/ic_launcher.png b/src/en/digitalcomicmuseum/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..44cd478aa Binary files /dev/null and b/src/en/digitalcomicmuseum/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/src/en/digitalcomicmuseum/res/mipmap-xxxhdpi/ic_launcher.png b/src/en/digitalcomicmuseum/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 000000000..b1dd6117a Binary files /dev/null and b/src/en/digitalcomicmuseum/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/src/en/digitalcomicmuseum/res/web_hi_res_512.png b/src/en/digitalcomicmuseum/res/web_hi_res_512.png new file mode 100644 index 000000000..cc9d5ba0e Binary files /dev/null and b/src/en/digitalcomicmuseum/res/web_hi_res_512.png differ diff --git a/src/en/digitalcomicmuseum/src/eu/kanade/tachiyomi/extension/en/digitalcomicmuseum/DigitalComicMuseum.kt b/src/en/digitalcomicmuseum/src/eu/kanade/tachiyomi/extension/en/digitalcomicmuseum/DigitalComicMuseum.kt new file mode 100644 index 000000000..c16ad68d1 --- /dev/null +++ b/src/en/digitalcomicmuseum/src/eu/kanade/tachiyomi/extension/en/digitalcomicmuseum/DigitalComicMuseum.kt @@ -0,0 +1,134 @@ +package eu.kanade.tachiyomi.extension.en.digitalcomicmuseum + +import eu.kanade.tachiyomi.network.GET +import eu.kanade.tachiyomi.network.POST +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.source.online.ParsedHttpSource +import okhttp3.Headers +import okhttp3.HttpUrl.Companion.toHttpUrl +import okhttp3.Interceptor +import okhttp3.MultipartBody +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.RequestBody +import okhttp3.Response +import org.jsoup.nodes.Document +import org.jsoup.nodes.Element + +class DigitalComicMuseum() : ParsedHttpSource() { + override val baseUrl = "https://digitalcomicmuseum.com" + override val lang = "en" + override val name = "Digital Comic Museum" + override val supportsLatest = true + + override val client: OkHttpClient = super.client.newBuilder() + .addInterceptor(::errorIntercept) + .build() + + // Latest + override fun latestUpdatesFromElement(element: Element): SManga { + val manga = SManga.create() + manga.thumbnail_url = element.select("img").attr("abs:src") + manga.setUrlWithoutDomain(element.select("a").attr("abs:href")) + manga.title = element.select("a").text() + return manga + } + + override fun latestUpdatesNextPageSelector() = "img[alt=Next]" + + override fun latestUpdatesRequest(page: Int): Request { + return GET("$baseUrl/stats.php?ACT=latest&start=${page - 1}00&limit=100") + } + + override fun latestUpdatesSelector() = "tbody > .mainrow" + + // Popular + + override fun popularMangaFromElement(element: Element) = latestUpdatesFromElement(element) + override fun popularMangaNextPageSelector() = latestUpdatesNextPageSelector() + override fun popularMangaSelector() = latestUpdatesSelector() + + override fun popularMangaRequest(page: Int): Request { + return GET("$baseUrl/stats.php?ACT=topdl&start=${page - 1}00&limit=100") + } + + // Search + + override fun searchMangaFromElement(element: Element): SManga { + val manga = SManga.create() + val baseElement = element.selectFirst("td > a") + manga.setUrlWithoutDomain(baseElement.attr("abs:href")) + manga.title = baseElement.text() + return manga + } + + override fun searchMangaNextPageSelector() = "Not supported" + override fun searchMangaSelector() = "#search-results tbody > tr" + + override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { + val requestBody: RequestBody = MultipartBody.Builder() + .setType(MultipartBody.FORM) + .addFormDataPart("terms", query) + .build() + val requestHeaders: Headers = Headers.Builder() + .addAll(headers) + .add("Content-Type", "multipart/form-data") + .build() + val url = "$baseUrl/index.php".toHttpUrl().newBuilder() + .addQueryParameter("ACT", "dosearch") + .build() + return POST(url.toString(), requestHeaders, requestBody) + } + + // Details + + override fun mangaDetailsParse(document: Document): SManga { + val manga = SManga.create() + val elements = document.select(".tableborder") + manga.title = elements.first().select("#catname").text() + manga.setUrlWithoutDomain(elements.first().select("#catname > a").attr("abs:href")) + manga.thumbnail_url = elements.first().selectFirst("table img").attr("abs:src") + elements.forEach { + when (it.select("#catname").text()) { + "Description" -> manga.description = it.selectFirst("table").text() + } + } + return manga + } + + // Chapters + + override fun chapterFromElement(element: Element): SChapter { + val chapter = SChapter.create() + chapter.name = element.select("#catname").text() + chapter.setUrlWithoutDomain(element.select(".tablefooter a:first-of-type").attr("abs:href")) + return chapter + } + + override fun chapterListSelector() = ".tableborder:first-of-type" + + override fun pageListParse(document: Document): List { + val pages = mutableListOf() + document.select(".latest-slide > .slick-slide > a").forEachIndexed() { index, element -> + pages.add(Page(index, element.attr("abs:href"))) + } + return pages + } + + override fun imageUrlParse(document: Document): String { + return document.select("body > a:nth-of-type(2) > img").attr("src") + } + + // Interceptor + private fun errorIntercept(chain: Interceptor.Chain): Response { + val response: Response = chain.proceed(chain.request()) + if (response.code == 403) { + val newRequest = response.request + return client.newCall(newRequest).execute() + } + return response + } +}