diff --git a/src/pt/lermanga/AndroidManifest.xml b/src/pt/lermanga/AndroidManifest.xml deleted file mode 100644 index 12069eba4..000000000 --- a/src/pt/lermanga/AndroidManifest.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/src/pt/lermanga/build.gradle b/src/pt/lermanga/build.gradle deleted file mode 100644 index 6d19648f2..000000000 --- a/src/pt/lermanga/build.gradle +++ /dev/null @@ -1,8 +0,0 @@ -ext { - extName = 'Ler Mangá' - extClass = '.LerManga' - extVersionCode = 6 - isNsfw = true -} - -apply from: "$rootDir/common.gradle" diff --git a/src/pt/lermanga/res/mipmap-hdpi/ic_launcher.png b/src/pt/lermanga/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index 4b5b1db5c..000000000 Binary files a/src/pt/lermanga/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/src/pt/lermanga/res/mipmap-mdpi/ic_launcher.png b/src/pt/lermanga/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index 4ec85d50f..000000000 Binary files a/src/pt/lermanga/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/src/pt/lermanga/res/mipmap-xhdpi/ic_launcher.png b/src/pt/lermanga/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index 65aa20944..000000000 Binary files a/src/pt/lermanga/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/src/pt/lermanga/res/mipmap-xxhdpi/ic_launcher.png b/src/pt/lermanga/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index cde412bd8..000000000 Binary files a/src/pt/lermanga/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/src/pt/lermanga/res/mipmap-xxxhdpi/ic_launcher.png b/src/pt/lermanga/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index a4dbc9a97..000000000 Binary files a/src/pt/lermanga/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/src/pt/lermanga/src/eu/kanade/tachiyomi/extension/pt/lermanga/LerManga.kt b/src/pt/lermanga/src/eu/kanade/tachiyomi/extension/pt/lermanga/LerManga.kt deleted file mode 100644 index 99d37aa41..000000000 --- a/src/pt/lermanga/src/eu/kanade/tachiyomi/extension/pt/lermanga/LerManga.kt +++ /dev/null @@ -1,206 +0,0 @@ -package eu.kanade.tachiyomi.extension.pt.lermanga - -import android.util.Base64 -import eu.kanade.tachiyomi.network.GET -import eu.kanade.tachiyomi.network.interceptor.rateLimitHost -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 kotlinx.serialization.decodeFromString -import kotlinx.serialization.json.Json -import okhttp3.Headers -import okhttp3.HttpUrl.Companion.toHttpUrl -import okhttp3.OkHttpClient -import okhttp3.Request -import okhttp3.Response -import org.jsoup.nodes.Document -import org.jsoup.nodes.Element -import uy.kohesive.injekt.injectLazy -import java.text.SimpleDateFormat -import java.util.Locale -import java.util.concurrent.TimeUnit -import kotlin.UnsupportedOperationException - -class LerManga : ParsedHttpSource() { - - override val name = "Ler Mangá" - - override val baseUrl = "https://lermanga.org" - - override val lang = "pt-BR" - - override val supportsLatest = true - - override val client: OkHttpClient = network.cloudflareClient.newBuilder() - .rateLimitHost(baseUrl.toHttpUrl(), 1, 1, TimeUnit.SECONDS) - .rateLimitHost(IMG_CDN_URL.toHttpUrl(), 1, 2, TimeUnit.SECONDS) - .build() - - private val json: Json by injectLazy() - - override fun headersBuilder(): Headers.Builder = Headers.Builder() - .add("Referer", "$baseUrl/") - - private fun apiHeadersBuilder(): Headers.Builder = headersBuilder() - .add("Accept", "application/json") - - private val apiHeaders by lazy { apiHeadersBuilder().build() } - - override fun popularMangaRequest(page: Int): Request { - val path = if (page > 1) "page/$page/" else "" - return GET("$baseUrl/mangas/$path?orderby=views&order=desc", headers) - } - - override fun popularMangaSelector(): String = "div.film_list div.flw-item" - - override fun popularMangaFromElement(element: Element): SManga = SManga.create().apply { - title = element.selectFirst("h3.film-name")!!.text() - thumbnail_url = element.selectFirst("img.film-poster-img")!!.srcAttr() - setUrlWithoutDomain(element.selectFirst("a.dynamic-name")!!.attr("href")) - } - - override fun popularMangaNextPageSelector(): String = "div.wp-pagenavi > a:last-child" - - override fun latestUpdatesRequest(page: Int): Request = GET(baseUrl, headers) - - override fun latestUpdatesSelector() = "div.capitulo_recentehome" - - override fun latestUpdatesFromElement(element: Element): SManga = SManga.create().apply { - title = element.selectFirst("h3")!!.text() - thumbnail_url = element.selectFirst("img")!!.absUrl("data-src") - setUrlWithoutDomain(element.selectFirst("h3 > a")!!.attr("href")) - } - - override fun latestUpdatesNextPageSelector(): String? = null - - override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { - if (query.startsWith(PREFIX_SLUG_SEARCH)) { - val slug = query.removePrefix(PREFIX_SLUG_SEARCH) - val tempManga = SManga.create().apply { url = "/mangas/$slug" } - - return mangaDetailsRequest(tempManga) - } - - val apiRequest = "$API_BASE_URL/mangas".toHttpUrl().newBuilder() - .addQueryParameter("page", page.toString()) - .addQueryParameter("search", query) - .addQueryParameter("_fields", "title,slug") - .build() - - return GET(apiRequest, apiHeaders) - } - - override fun searchMangaParse(response: Response): MangasPage { - if (response.request.url.queryParameter("slug") != null) { - val manga = mangaDetailsParse(response) - return MangasPage(listOf(manga), hasNextPage = false) - } - - val result = response.parseAs>() - val mangaList = result.map(LmMangaDto::toSManga) - - val currentPage = response.request.url.queryParameter("page") - .orEmpty().toIntOrNull() ?: 1 - val lastPage = response.headers["X-Wp-TotalPages"]!!.toInt() - val hasNextPage = currentPage < lastPage - - return MangasPage(mangaList, hasNextPage) - } - - override fun searchMangaSelector() = throw UnsupportedOperationException() - - override fun searchMangaFromElement(element: Element) = throw UnsupportedOperationException() - - override fun searchMangaNextPageSelector() = throw UnsupportedOperationException() - - override fun getMangaUrl(manga: SManga): String = baseUrl + manga.url - - override fun mangaDetailsRequest(manga: SManga): Request { - val slug = manga.url.removePrefix("/mangas/").removeSuffix("/") - - val apiRequest = "$API_BASE_URL/mangas".toHttpUrl().newBuilder() - .addQueryParameter("slug", slug) - .addQueryParameter("limit", "1") - .addQueryParameter("_embed", "wp:term") - .addQueryParameter("_fields", "title,slug,content,_links.wp:term,_embedded.wp:term") - .build() - - return GET(apiRequest, apiHeaders) - } - - override fun mangaDetailsParse(response: Response): SManga { - return response.parseAs>().first().toSManga() - } - - override fun mangaDetailsParse(document: Document): SManga = throw UnsupportedOperationException() - - override fun chapterListSelector() = "div.manga-chapters div.single-chapter" - - override fun chapterFromElement(element: Element): SChapter = SChapter.create().apply { - name = element.selectFirst("a")!!.text() - date_upload = element.selectFirst("small small")!!.text().toDate() - setUrlWithoutDomain(element.selectFirst("a")!!.attr("href")) - } - - override fun pageListParse(document: Document): List { - val pagesScript = document.selectFirst("h1.heading-header + script") - ?: return emptyList() - - val pagesJson = when { - pagesScript.hasAttr("src") -> { - pagesScript.attr("src") - .substringAfter("base64,") - .let { Base64.decode(it, Base64.DEFAULT).toString(Charsets.UTF_8) } - } - else -> pagesScript.data() - } - - return pagesJson - .replace(PAGES_VARIABLE_REGEX, "") - .substringBeforeLast(";") - .let { json.decodeFromString>(it) } - .filter { it.isNotBlank() } - .mapIndexed { index, imageUrl -> - Page(index, imageUrl = imageUrl) - } - } - - override fun imageUrlParse(document: Document) = throw UnsupportedOperationException() - - override fun imageRequest(page: Page): Request { - val newHeaders = headersBuilder() - .set("Referer", page.url) - .build() - - return GET(page.imageUrl!!, newHeaders) - } - - private inline fun Response.parseAs(): T = use { - json.decodeFromString(it.body.string()) - } - - private fun Element.srcAttr(): String = when { - hasAttr("data-src") -> absUrl("data-src") - else -> absUrl("src") - } - - private fun String.toDate(): Long { - return runCatching { DATE_FORMATTER.parse(trim())?.time } - .getOrNull() ?: 0L - } - - companion object { - const val API_BASE_URL = "https://lermanga.org/wp-json/wp/v2" - const val IMG_CDN_URL = "https://img.lermanga.org" - private val PAGES_VARIABLE_REGEX = "var imagens_cap\\s*=\\s*".toRegex() - private val DATE_FORMATTER by lazy { - SimpleDateFormat("dd-MM-yyyy", Locale("pt", "BR")) - } - - const val PREFIX_SLUG_SEARCH = "slug:" - private const val ERROR_NO_SEARCH_AVAILABLE = "O site não possui busca própria." - } -} diff --git a/src/pt/lermanga/src/eu/kanade/tachiyomi/extension/pt/lermanga/LerMangaDto.kt b/src/pt/lermanga/src/eu/kanade/tachiyomi/extension/pt/lermanga/LerMangaDto.kt deleted file mode 100644 index 2e5a305e4..000000000 --- a/src/pt/lermanga/src/eu/kanade/tachiyomi/extension/pt/lermanga/LerMangaDto.kt +++ /dev/null @@ -1,38 +0,0 @@ -package eu.kanade.tachiyomi.extension.pt.lermanga - -import eu.kanade.tachiyomi.source.model.SManga -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import org.jsoup.Jsoup -import org.jsoup.nodes.Entities - -@Serializable -data class LmMangaDto( - val slug: String, - val title: LmContentDto, - val content: LmContentDto? = null, - @SerialName("_embedded") val embedded: LmEmbedDto? = null, -) { - - fun toSManga(): SManga = SManga.create().apply { - title = Entities.unescape(this@LmMangaDto.title.rendered) - thumbnail_url = "${LerManga.IMG_CDN_URL}/${slug.first().uppercase()}/$slug/capa.jpg" - description = content?.rendered?.let { Jsoup.parseBodyFragment(it) }?.text()?.trim() - genre = embedded?.wpTerm.orEmpty().flatten() - .filter { it.taxonomy == "generomanga" } - .joinToString { it.name } - url = "/mangas/$slug" - } -} - -@Serializable -data class LmContentDto(val rendered: String) - -@Serializable -data class LmEmbedDto(@SerialName("wp:term") val wpTerm: List>) - -@Serializable -data class LmTaxonomyDto( - val name: String, - val taxonomy: String, -) diff --git a/src/pt/lermanga/src/eu/kanade/tachiyomi/extension/pt/lermanga/LerMangaUrlActivity.kt b/src/pt/lermanga/src/eu/kanade/tachiyomi/extension/pt/lermanga/LerMangaUrlActivity.kt deleted file mode 100644 index 716a5d6fb..000000000 --- a/src/pt/lermanga/src/eu/kanade/tachiyomi/extension/pt/lermanga/LerMangaUrlActivity.kt +++ /dev/null @@ -1,49 +0,0 @@ -package eu.kanade.tachiyomi.extension.pt.lermanga - -import android.app.Activity -import android.content.ActivityNotFoundException -import android.content.Intent -import android.os.Bundle -import android.util.Log -import kotlin.system.exitProcess - -/** - * Activity that accepts https://lermanga.org/mangas/xxx intents and redirects them to - * the main Tachiyomi process. The idea is to not install the intent filter unless - * you have this extension installed, but still let the main Tachiyomi app control - * things. - * - * Main goal was to make it easier to open manga in Tachiyomi in spite of the DDoS blocking - * the usual search screen from working. - * - * Added as the site removed their own search and are using an embedded Google search. - * As Google has a lot of measures to prevent scrapping, this is the best that can - * be done at the moment. - */ -class LerMangaUrlActivity : Activity() { - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - val pathSegments = intent?.data?.pathSegments - - if (pathSegments != null && pathSegments.size > 1) { - val slug = pathSegments[1] - val intent = Intent().apply { - action = "eu.kanade.tachiyomi.SEARCH" - putExtra("query", LerManga.PREFIX_SLUG_SEARCH + slug) - putExtra("filter", packageName) - } - - try { - startActivity(intent) - } catch (e: ActivityNotFoundException) { - Log.e("LerMangaUrlActivity", e.toString()) - } - } else { - Log.e("LerMangaUrlActivity", "Could not parse URI from intent $intent") - } - - finish() - exitProcess(0) - } -}