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()
}