diff --git a/src/en/mangamainac/build.gradle b/src/en/mangamainac/build.gradle new file mode 100644 index 000000000..cf0dee2b2 --- /dev/null +++ b/src/en/mangamainac/build.gradle @@ -0,0 +1,12 @@ +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' + +ext { + appName = 'Tachiyomi: MangaMainac' + pkgNameSuffix = 'en.mangamainac' + extClass = '.MangaMainac' + extVersionCode = 1 + libVersion = '1.2' +} + +apply from: "$rootDir/common.gradle" diff --git a/src/en/mangamainac/res/mipmap-hdpi/ic_launcher.png b/src/en/mangamainac/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 000000000..3c0563ec3 Binary files /dev/null and b/src/en/mangamainac/res/mipmap-hdpi/ic_launcher.png differ diff --git a/src/en/mangamainac/res/mipmap-mdpi/ic_launcher.png b/src/en/mangamainac/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 000000000..f44f3cbd6 Binary files /dev/null and b/src/en/mangamainac/res/mipmap-mdpi/ic_launcher.png differ diff --git a/src/en/mangamainac/res/mipmap-xhdpi/ic_launcher.png b/src/en/mangamainac/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 000000000..a7ec78d51 Binary files /dev/null and b/src/en/mangamainac/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/src/en/mangamainac/res/mipmap-xxhdpi/ic_launcher.png b/src/en/mangamainac/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..70f741710 Binary files /dev/null and b/src/en/mangamainac/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/src/en/mangamainac/res/mipmap-xxxhdpi/ic_launcher.png b/src/en/mangamainac/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 000000000..c30953939 Binary files /dev/null and b/src/en/mangamainac/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/src/en/mangamainac/res/web_hi_res_512.png b/src/en/mangamainac/res/web_hi_res_512.png new file mode 100644 index 000000000..87d091aab Binary files /dev/null and b/src/en/mangamainac/res/web_hi_res_512.png differ diff --git a/src/en/mangamainac/src/eu/kanade/tachiyomi/extension/en/mangamainac/MangaMainac.kt b/src/en/mangamainac/src/eu/kanade/tachiyomi/extension/en/mangamainac/MangaMainac.kt new file mode 100644 index 000000000..2994a5130 --- /dev/null +++ b/src/en/mangamainac/src/eu/kanade/tachiyomi/extension/en/mangamainac/MangaMainac.kt @@ -0,0 +1,143 @@ +package eu.kanade.tachiyomi.extension.en.mangamainac + +import eu.kanade.tachiyomi.network.GET +import eu.kanade.tachiyomi.source.model.* +import eu.kanade.tachiyomi.source.online.ParsedHttpSource +import okhttp3.Request +import org.jsoup.nodes.Document +import org.jsoup.nodes.Element +import rx.Observable +import java.util.* + +//MangaManiac is a network of sites built by Animemaniac.co. + +class MangaMainac : ParsedHttpSource() { + + companion object { + val sourceList = listOf>( + Pair("Boku No Hero Academia","https://w15.readheroacademia.com"), + Pair("One Punch Man","https://w12.readonepunchman.net"), + Pair("One Punch Man (webcomic)","https://onewebcomic.net"), + Pair("Solo Leveling","https://sololeveling.net"), + Pair("Jojolion","https://readjojolion.com"), + Pair("Hajime no Ippo","https://readhajimenoippo.com"), + Pair("Berserk","http://berserkmanga.net"), + Pair("The Quintessential Quintuplets","https://5-toubunnohanayome.net"), + Pair("Kaguya Wants to be Confessed To","https://kaguyasama.net"), + Pair("Domestic Girlfriend","https://domesticgirlfriend.net"), + Pair("Black Clover","https://w5.blackclovermanga.com"), + Pair("One Piece","https://1piecemanga.net"), + Pair("The Promised Neverland","https://neverlandmanga.net"), + Pair("Shingeki no Kyojin","https://readshingekinokyojin.com"), + Pair("Nanatsu no Taizai","https://w1.readnanatsutaizai.net") + ).sortedBy { it.first }.distinctBy { it.second } + + } + + //Info + + override val name: String = "MangaMainac (Multiple Sites)" + override val baseUrl: String = "about:blank" + override val lang: String = "en" + override val supportsLatest: Boolean = false + + //Popular + + override fun fetchPopularManga(page: Int): Observable { + return Observable.just(MangasPage(sourceList.map { popularMangaFromPair(it.first,it.second ) }, false)) + } + private fun popularMangaFromPair(name: String, sourceurl: String ): SManga = SManga.create().apply { + title = name + url = sourceurl + } + override fun popularMangaRequest(page: Int): Request = throw Exception("Not used") + override fun popularMangaNextPageSelector(): String? = throw Exception("Not used") + override fun popularMangaSelector(): String = throw Exception("Not used") + override fun popularMangaFromElement(element: Element) = throw Exception("Not used") + + + //Latest + override fun latestUpdatesRequest(page: Int): Request = throw Exception("Not used") + override fun latestUpdatesNextPageSelector(): String? = throw Exception("Not used") + override fun latestUpdatesSelector(): String = throw Exception("Not used") + override fun latestUpdatesFromElement(element: Element): SManga = throw Exception("Not used") + + //Search + + override fun searchMangaRequest(page: Int, query: String, filters: FilterList)= throw Exception("No Search Function") + override fun searchMangaNextPageSelector() = throw Exception("Not used") + override fun searchMangaSelector() = throw Exception("Not used") + override fun searchMangaFromElement(element: Element) = throw Exception("Not used") + + //Get Override + + override fun mangaDetailsRequest(manga: SManga): Request { + return GET( manga.url, headers) + } + override fun chapterListRequest(manga: SManga): Request { + return GET( manga.url, headers) + } + override fun pageListRequest(chapter: SChapter): Request { + return GET( chapter.url, headers) + } + + //Details + + override fun mangaDetailsParse(document: Document): SManga = SManga.create().apply { + val info = document.select(".intro_content").text() + title = document.select(".intro_content h2").text() + author = if ("Author" in info) substringextract(info,"Author(s):","Released") else null + artist = author + genre = if ("Genre" in info) substringextract(info, "Genre(s):","Status") else null + status = when (substringextract(info, "Status:","(")) { + "Ongoing" -> SManga.ONGOING + "Completed" -> SManga.COMPLETED + else -> SManga.UNKNOWN + } + description = if ("Description" in info) info.substringAfter("Description:").trim() else null + thumbnail_url = document.select(".mangainfo_body img").attr("src") + } + private fun substringextract(text: String, start:String, end:String): String = text.substringAfter(start).substringBefore(end).trim() + + //Chapters + + override fun chapterListSelector(): String = ".chap_tab tr" + override fun chapterFromElement(element: Element): SChapter = SChapter.create().apply { + name = element.select("a").text() + url = element.select("a").attr("abs:href") + date_upload = parseRelativeDate(element.select("#time").text().substringBefore(" ago")) + } + + // Subtract relative date (e.g. posted 3 days ago) + private fun parseRelativeDate(date: String): Long { + val calendar = Calendar.getInstance() + + if (date.contains("yesterday")) { + calendar.apply{add(Calendar.DAY_OF_MONTH, -1)} + } else { + val trimmedDate = date.replace("one", "1").removeSuffix("s").split(" ") + + when (trimmedDate[1]) { + "year" -> calendar.apply { add(Calendar.YEAR, -trimmedDate[0].toInt()) } + "month" -> calendar.apply { add(Calendar.MONTH, -trimmedDate[0].toInt()) } + "week" -> calendar.apply { add(Calendar.WEEK_OF_MONTH, -trimmedDate[0].toInt()) } + "day" -> calendar.apply { add(Calendar.DAY_OF_MONTH, -trimmedDate[0].toInt()) } + } + } + + return calendar.timeInMillis + } + + //Pages + + override fun pageListParse(document: Document): List = mutableListOf().apply { + document.select(".img_container img").forEach { img -> + add(Page(size,"",img.attr("src"))) + } + } + + override fun imageUrlParse(document: Document): String = throw Exception("Not Used") + +} + +