diff --git a/multisrc/overrides/madara/romance24h/res/mipmap-hdpi/ic_launcher.png b/multisrc/overrides/madara/romance24h/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 000000000..7d2fa1cd7 Binary files /dev/null and b/multisrc/overrides/madara/romance24h/res/mipmap-hdpi/ic_launcher.png differ diff --git a/multisrc/overrides/madara/romance24h/res/mipmap-mdpi/ic_launcher.png b/multisrc/overrides/madara/romance24h/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 000000000..fe4e1a196 Binary files /dev/null and b/multisrc/overrides/madara/romance24h/res/mipmap-mdpi/ic_launcher.png differ diff --git a/multisrc/overrides/madara/romance24h/res/mipmap-xhdpi/ic_launcher.png b/multisrc/overrides/madara/romance24h/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 000000000..7756c33af Binary files /dev/null and b/multisrc/overrides/madara/romance24h/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/multisrc/overrides/madara/romance24h/res/mipmap-xxhdpi/ic_launcher.png b/multisrc/overrides/madara/romance24h/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..425dcef6f Binary files /dev/null and b/multisrc/overrides/madara/romance24h/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/multisrc/overrides/madara/romance24h/res/mipmap-xxxhdpi/ic_launcher.png b/multisrc/overrides/madara/romance24h/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 000000000..c747d7e37 Binary files /dev/null and b/multisrc/overrides/madara/romance24h/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/multisrc/overrides/madara/romance24h/res/web_hi_res_512.png b/multisrc/overrides/madara/romance24h/res/web_hi_res_512.png new file mode 100644 index 000000000..a94b57524 Binary files /dev/null and b/multisrc/overrides/madara/romance24h/res/web_hi_res_512.png differ diff --git a/multisrc/overrides/madara/romance24h/src/Romance24h.kt b/multisrc/overrides/madara/romance24h/src/Romance24h.kt new file mode 100644 index 000000000..3d25d2638 --- /dev/null +++ b/multisrc/overrides/madara/romance24h/src/Romance24h.kt @@ -0,0 +1,5 @@ +package eu.kanade.tachiyomi.extension.en.romance24h + +import eu.kanade.tachiyomi.multisrc.madara.Madara + +class Romance24h : Madara("24hRomance", "https://24hromance.com", "en") diff --git a/multisrc/overrides/madara/setsuscans/res/mipmap-hdpi/ic_launcher.png b/multisrc/overrides/madara/setsuscans/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 000000000..75d9aea0b Binary files /dev/null and b/multisrc/overrides/madara/setsuscans/res/mipmap-hdpi/ic_launcher.png differ diff --git a/multisrc/overrides/madara/setsuscans/res/mipmap-mdpi/ic_launcher.png b/multisrc/overrides/madara/setsuscans/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 000000000..fccf1f01c Binary files /dev/null and b/multisrc/overrides/madara/setsuscans/res/mipmap-mdpi/ic_launcher.png differ diff --git a/multisrc/overrides/madara/setsuscans/res/mipmap-xhdpi/ic_launcher.png b/multisrc/overrides/madara/setsuscans/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 000000000..01238222c Binary files /dev/null and b/multisrc/overrides/madara/setsuscans/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/multisrc/overrides/madara/setsuscans/res/mipmap-xxhdpi/ic_launcher.png b/multisrc/overrides/madara/setsuscans/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..b5b8c56f1 Binary files /dev/null and b/multisrc/overrides/madara/setsuscans/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/multisrc/overrides/madara/setsuscans/res/mipmap-xxxhdpi/ic_launcher.png b/multisrc/overrides/madara/setsuscans/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 000000000..4c85c9153 Binary files /dev/null and b/multisrc/overrides/madara/setsuscans/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/multisrc/overrides/madara/setsuscans/res/web_hi_res_512.png b/multisrc/overrides/madara/setsuscans/res/web_hi_res_512.png new file mode 100644 index 000000000..cd619c91a Binary files /dev/null and b/multisrc/overrides/madara/setsuscans/res/web_hi_res_512.png differ diff --git a/multisrc/overrides/madara/setsuscans/src/SetsuScans.kt b/multisrc/overrides/madara/setsuscans/src/SetsuScans.kt new file mode 100644 index 000000000..962063947 --- /dev/null +++ b/multisrc/overrides/madara/setsuscans/src/SetsuScans.kt @@ -0,0 +1,5 @@ +package eu.kanade.tachiyomi.extension.en.setsuscans + +import eu.kanade.tachiyomi.multisrc.madara.Madara + +class SetsuScans : Madara("Setsu Scans", "https://setsuscans.com", "en") diff --git a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/madara/MadaraGenerator.kt b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/madara/MadaraGenerator.kt index 885a0c253..af67e3647 100644 --- a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/madara/MadaraGenerator.kt +++ b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/madara/MadaraGenerator.kt @@ -13,6 +13,7 @@ class MadaraGenerator : ThemeSourceGenerator { override val baseVersionCode: Int = 3 override val sources = listOf( + SingleLang("24hRomance", "https://24hromance.com", "en", className = "Romance24h"), SingleLang("Adonis Fansub", "https://manga.adonisfansub.com", "tr"), SingleLang("AkuManga", "https://akumanga.com", "ar"), SingleLang("AlianzaMarcial", "https://alianzamarcial.xyz", "es"), @@ -197,6 +198,7 @@ class MadaraGenerator : ThemeSourceGenerator { SingleLang("S2Manga", "https://s2manga.com", "en"), SingleLang("SamuraiScan", "https://samuraiscan.com", "es"), SingleLang("Sekte Doujin", "https://sektedoujin.xyz", "id", isNsfw = true), + SingleLang("Setsu Scans", "https://setsuscans.com", "en"), SingleLang("Shield Manga", "https://shieldmanga.club", "en", overrideVersionCode = 2), SingleLang("Shinzoo Scan", "https://shinzooscan.xyz", "pt-BR", overrideVersionCode = 1), SingleLang("ShoujoHearts", "https://shoujohearts.com", "en", overrideVersionCode = 1), diff --git a/src/fr/furyosquad/AndroidManifest.xml b/src/fr/furyosquad/AndroidManifest.xml new file mode 100644 index 000000000..30deb7f79 --- /dev/null +++ b/src/fr/furyosquad/AndroidManifest.xml @@ -0,0 +1,2 @@ + + diff --git a/src/fr/furyosquad/build.gradle b/src/fr/furyosquad/build.gradle new file mode 100644 index 000000000..82c1b2c58 --- /dev/null +++ b/src/fr/furyosquad/build.gradle @@ -0,0 +1,16 @@ +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' + +ext { + extName = 'FuryoSquad' + pkgNameSuffix = 'fr.furyosquad' + extClass = '.FuryoSquad' + extVersionCode = 1 + libVersion = '1.2' +} + +dependencies { + implementation project(':lib-ratelimit') +} + +apply from: "$rootDir/common.gradle" diff --git a/src/fr/furyosquad/res/mipmap-hdpi/ic_launcher.png b/src/fr/furyosquad/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 000000000..3662df10e Binary files /dev/null and b/src/fr/furyosquad/res/mipmap-hdpi/ic_launcher.png differ diff --git a/src/fr/furyosquad/res/mipmap-mdpi/ic_launcher.png b/src/fr/furyosquad/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 000000000..74396a55a Binary files /dev/null and b/src/fr/furyosquad/res/mipmap-mdpi/ic_launcher.png differ diff --git a/src/fr/furyosquad/res/mipmap-xhdpi/ic_launcher.png b/src/fr/furyosquad/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 000000000..57da9980c Binary files /dev/null and b/src/fr/furyosquad/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/src/fr/furyosquad/res/mipmap-xxhdpi/ic_launcher.png b/src/fr/furyosquad/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..c1e1ff4c8 Binary files /dev/null and b/src/fr/furyosquad/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/src/fr/furyosquad/res/mipmap-xxxhdpi/ic_launcher.png b/src/fr/furyosquad/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 000000000..4e8276dfd Binary files /dev/null and b/src/fr/furyosquad/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/src/fr/furyosquad/res/web_hi_res_512.png b/src/fr/furyosquad/res/web_hi_res_512.png new file mode 100644 index 000000000..b2f8f2de0 Binary files /dev/null and b/src/fr/furyosquad/res/web_hi_res_512.png differ diff --git a/src/fr/furyosquad/src/eu/kanade/tachiyomi/extension/fr/furyosquad/FuryoSquad.kt b/src/fr/furyosquad/src/eu/kanade/tachiyomi/extension/fr/furyosquad/FuryoSquad.kt new file mode 100644 index 000000000..73f92dde3 --- /dev/null +++ b/src/fr/furyosquad/src/eu/kanade/tachiyomi/extension/fr/furyosquad/FuryoSquad.kt @@ -0,0 +1,254 @@ +package eu.kanade.tachiyomi.extension.fr.furyosquad + +import eu.kanade.tachiyomi.lib.ratelimit.RateLimitInterceptor +import eu.kanade.tachiyomi.network.GET +import eu.kanade.tachiyomi.network.asObservableSuccess +import eu.kanade.tachiyomi.source.model.FilterList +import eu.kanade.tachiyomi.source.model.MangasPage +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 eu.kanade.tachiyomi.util.asJsoup +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.Response +import org.jsoup.nodes.Document +import org.jsoup.nodes.Element +import rx.Observable +import java.text.SimpleDateFormat +import java.util.Calendar +import java.util.Locale +import java.util.concurrent.TimeUnit + +class FuryoSquad : ParsedHttpSource() { + + override val name = "FuryoSquad" + + override val baseUrl = "https://www.furyosquad.com/" + + override val lang = "fr" + + override val supportsLatest = true + + private val rateLimitInterceptor = RateLimitInterceptor(1) + + override val client: OkHttpClient = network.cloudflareClient.newBuilder() + .connectTimeout(10, TimeUnit.SECONDS) + .readTimeout(30, TimeUnit.SECONDS) + .addNetworkInterceptor(rateLimitInterceptor) + .build() + + // Popular + + override fun popularMangaRequest(page: Int): Request { + return GET("$baseUrl/mangas", headers) + } + + override fun popularMangaSelector() = "div#fs-tous div.fs-card-body" + + override fun popularMangaFromElement(element: Element): SManga { + val manga = SManga.create() + + with(element) { + manga.url = select("div.fs-card-img-container a").attr("href") + manga.title = select("span.fs-comic-title a").text() + + manga.thumbnail_url = select("div.fs-card-img-container img").attr("abs:src") + } + + return manga + } + + override fun popularMangaNextPageSelector() = "Not needed" + + // Latest + + override fun latestUpdatesRequest(page: Int): Request { + return GET(baseUrl, headers) + } + + override fun latestUpdatesParse(response: Response): MangasPage { + val document = response.asJsoup() + val mangas = mutableListOf() + + document.select(latestUpdatesSelector()).map { mangas.add(latestUpdatesFromElement(it)) } + + return MangasPage(mangas.distinctBy { it.url }, false) + } + + override fun latestUpdatesSelector() = "table.table-striped tr" + + override fun latestUpdatesFromElement(element: Element): SManga { + val manga = SManga.create() + + with(element) { + manga.url = select("span.fs-comic-title a").attr("href") + manga.title = select("span.fs-comic-title a").text() + + manga.thumbnail_url = select("img.fs-chap-img").attr("abs:src") + } + + return manga + } + + override fun latestUpdatesNextPageSelector() = "not needed" + + // Search + + override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable { + return client.newCall(searchMangaRequest(page, query, filters)) + .asObservableSuccess() + .map { response -> + searchMangaParse(response, query) + } + } + + override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request = popularMangaRequest(1) + + private fun searchMangaParse(response: Response, query: String): MangasPage { + return MangasPage(popularMangaParse(response).mangas.filter { it.title.contains(query, ignoreCase = true) }, false) + } + + override fun searchMangaSelector() = throw UnsupportedOperationException("Not used") + + override fun searchMangaFromElement(element: Element): SManga = throw UnsupportedOperationException("Not used") + + override fun searchMangaNextPageSelector() = throw UnsupportedOperationException("Not used") + + // Details + + override fun mangaDetailsParse(document: Document): SManga { + val manga = SManga.create() + + document.select("div.comic-info").let { + it.select("p.fs-comic-label").forEach { el -> + when (el.text().toLowerCase(Locale.ROOT)) { + "scénario" -> manga.author = el.nextElementSibling().text() + "dessins" -> manga.artist = el.nextElementSibling().text() + "genre" -> manga.genre = el.nextElementSibling().text() + } + } + manga.description = it.select("div.fs-comic-description").text() + manga.thumbnail_url = it.select("img.comic-cover").attr("abs:src") + } + + return manga + } + + // Chapters + + override fun chapterListSelector() = "div.fs-chapter-list div.element" + + override fun chapterFromElement(element: Element): SChapter { + val chapter = SChapter.create() + + chapter.url = element.select("div.title a").attr("href") + chapter.name = element.select("div.title a").attr("title") + chapter.date_upload = parseChapterDate(element.select("div.meta_r").text()) + + return chapter + } + + private fun parseChapterDate(date: String): Long { + val lcDate = date.toLowerCase(Locale.ROOT) + if (lcDate.startsWith("il y a")) + parseRelativeDate(lcDate).let { return it } + + // Handle 'day before yesterday', yesterday' and 'today', using midnight + var relativeDate: Calendar? = null + // Result parsed but no year, copy current year over + when { + lcDate.startsWith("avant-hier") -> { + relativeDate = Calendar.getInstance() + relativeDate.add(Calendar.DAY_OF_MONTH, -2) // day before yesterday + relativeDate.set(Calendar.HOUR_OF_DAY, 0) + relativeDate.set(Calendar.MINUTE, 0) + relativeDate.set(Calendar.SECOND, 0) + relativeDate.set(Calendar.MILLISECOND, 0) + } + lcDate.startsWith("hier") -> { + relativeDate = Calendar.getInstance() + relativeDate.add(Calendar.DAY_OF_MONTH, -1) // yesterday + relativeDate.set(Calendar.HOUR_OF_DAY, 0) + relativeDate.set(Calendar.MINUTE, 0) + relativeDate.set(Calendar.SECOND, 0) + relativeDate.set(Calendar.MILLISECOND, 0) + } + lcDate.startsWith("aujourd'hui") -> { + relativeDate = Calendar.getInstance() + relativeDate.set(Calendar.HOUR_OF_DAY, 0) // today + relativeDate.set(Calendar.MINUTE, 0) + relativeDate.set(Calendar.SECOND, 0) + relativeDate.set(Calendar.MILLISECOND, 0) + } + } + + return relativeDate?.timeInMillis ?: 0L + } + + private fun parseRelativeDate(date: String): Long { + + val value = date.split(" ")[3].toIntOrNull() + + return if (value != null) { + when (date.split(" ")[4]) { + "minute", "minutes" -> Calendar.getInstance().apply { + add(Calendar.MINUTE, value * -1) + set(Calendar.SECOND, 0) + set(Calendar.MILLISECOND, 0) + }.timeInMillis + "heure", "heures" -> Calendar.getInstance().apply { + add(Calendar.HOUR_OF_DAY, value * -1) + set(Calendar.SECOND, 0) + set(Calendar.MILLISECOND, 0) + }.timeInMillis + "jour", "jours" -> Calendar.getInstance().apply { + add(Calendar.DATE, value * -1) + set(Calendar.SECOND, 0) + set(Calendar.MILLISECOND, 0) + }.timeInMillis + "semaine", "semaines" -> Calendar.getInstance().apply { + add(Calendar.DATE, value * 7 * -1) + set(Calendar.SECOND, 0) + set(Calendar.MILLISECOND, 0) + }.timeInMillis + "mois" -> Calendar.getInstance().apply { + add(Calendar.MONTH, value * -1) + set(Calendar.SECOND, 0) + set(Calendar.MILLISECOND, 0) + }.timeInMillis + "an", "ans", "année", "années" -> Calendar.getInstance().apply { + add(Calendar.YEAR, value * -1) + set(Calendar.SECOND, 0) + set(Calendar.MILLISECOND, 0) + }.timeInMillis + else -> { + return 0L + } + } + } else { + try { + SimpleDateFormat("dd MMM yyyy", Locale.FRENCH).parse(date.substringAfter("le "))?.time ?: 0 + } catch (_: Exception) { + 0L + } + } + } + + // Pages + + override fun pageListParse(document: Document): List { + val pages = mutableListOf() + + document.select("div.fs-read img[id]").forEachIndexed { i, img -> + pages.add(Page(i, "", img.attr("abs:src"))) + } + + return pages + } + + override fun imageUrlParse(document: Document) = throw UnsupportedOperationException("Not used") + + override fun getFilterList() = FilterList() +} diff --git a/src/fr/kangaryu/src/eu/kanade/tachiyomi/extension/fr/kangaryu/Kangaryu.kt b/src/fr/kangaryu/src/eu/kanade/tachiyomi/extension/fr/kangaryu/Kangaryu.kt index 52be60e49..6f281a219 100644 --- a/src/fr/kangaryu/src/eu/kanade/tachiyomi/extension/fr/kangaryu/Kangaryu.kt +++ b/src/fr/kangaryu/src/eu/kanade/tachiyomi/extension/fr/kangaryu/Kangaryu.kt @@ -42,15 +42,16 @@ class Kangaryu : ParsedHttpSource() { return GET("$baseUrl/manga-list", headers) } - override fun popularMangaSelector() = "div.profile-card-2" + override fun popularMangaSelector() = "div.l-card" override fun popularMangaFromElement(element: Element): SManga { return SManga.create().apply { - element.select("div.profile-name a").let { - setUrlWithoutDomain(it.attr("href")) - title = it.text() + element.select("div.card-image").let { + setUrlWithoutDomain(it.select("a").attr("href")) + thumbnail_url = it.select("img").attr("abs:src") } - thumbnail_url = element.select("img").attr("abs:src") + + title = element.select("a.chart-title").text() } } @@ -114,12 +115,13 @@ class Kangaryu : ParsedHttpSource() { artist = select("dd a[href*=artist]").text() genre = select("dd a[href*=category]").joinToString { it.text() } } + description = document.select("div.col-lg-12 p").text() } } private fun String.toStatus() = when { - this.contains("Ongoing", ignoreCase = true) -> SManga.ONGOING - this.contains("Completed", ignoreCase = true) -> SManga.COMPLETED + this.contains("En cours", ignoreCase = true) -> SManga.ONGOING + this.contains("Terminé", ignoreCase = true) -> SManga.COMPLETED else -> SManga.UNKNOWN } @@ -129,7 +131,7 @@ class Kangaryu : ParsedHttpSource() { override fun chapterFromElement(element: Element): SChapter { return SChapter.create().apply { - name = element.select("h5").text() + name = element.select("h5.chapter-title-rtl").text() setUrlWithoutDomain(element.select("h5 a").attr("href")) date_upload = element.select("div.date-chapter-title-rtl").text().toDate() }