[RU]Remanga alt free img server (#15538)
* [RU]Remanga alt free img server * right injecting * minFix * fix header load * LimitHost * authorization breaks exManga * separation of paid and ex manga chapters + crutch for search rus chapters * do not disrupt the operation of the main source * alt domain exmanga * fix bookmarks * callback request for update outside the library * no need fixLink * exremanga icon * notify - no hide chapters * notify long * fix mangaID * low ping low stress * getChapterUrl * notify of non-availability
|
@ -6,7 +6,7 @@ ext {
|
||||||
extName = 'Remanga'
|
extName = 'Remanga'
|
||||||
pkgNameSuffix = 'ru.remanga'
|
pkgNameSuffix = 'ru.remanga'
|
||||||
extClass = '.Remanga'
|
extClass = '.Remanga'
|
||||||
extVersionCode = 62
|
extVersionCode = 63
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 7.5 KiB |
Before Width: | Height: | Size: 9.3 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 112 KiB |
|
@ -1,6 +1,5 @@
|
||||||
package eu.kanade.tachiyomi.extension.ru.remanga
|
package eu.kanade.tachiyomi.extension.ru.remanga
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.annotation.TargetApi
|
import android.annotation.TargetApi
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
|
@ -10,11 +9,14 @@ import androidx.preference.ListPreference
|
||||||
import eu.kanade.tachiyomi.extension.ru.remanga.dto.BookDto
|
import eu.kanade.tachiyomi.extension.ru.remanga.dto.BookDto
|
||||||
import eu.kanade.tachiyomi.extension.ru.remanga.dto.BranchesDto
|
import eu.kanade.tachiyomi.extension.ru.remanga.dto.BranchesDto
|
||||||
import eu.kanade.tachiyomi.extension.ru.remanga.dto.ChunksPageDto
|
import eu.kanade.tachiyomi.extension.ru.remanga.dto.ChunksPageDto
|
||||||
|
import eu.kanade.tachiyomi.extension.ru.remanga.dto.ExBookDto
|
||||||
import eu.kanade.tachiyomi.extension.ru.remanga.dto.LibraryDto
|
import eu.kanade.tachiyomi.extension.ru.remanga.dto.LibraryDto
|
||||||
import eu.kanade.tachiyomi.extension.ru.remanga.dto.MangaDetDto
|
import eu.kanade.tachiyomi.extension.ru.remanga.dto.MangaDetDto
|
||||||
import eu.kanade.tachiyomi.extension.ru.remanga.dto.MyLibraryDto
|
import eu.kanade.tachiyomi.extension.ru.remanga.dto.MyLibraryDto
|
||||||
import eu.kanade.tachiyomi.extension.ru.remanga.dto.PageDto
|
import eu.kanade.tachiyomi.extension.ru.remanga.dto.PageDto
|
||||||
import eu.kanade.tachiyomi.extension.ru.remanga.dto.PageWrapperDto
|
import eu.kanade.tachiyomi.extension.ru.remanga.dto.PageWrapperDto
|
||||||
|
import eu.kanade.tachiyomi.extension.ru.remanga.dto.PagesDto
|
||||||
|
import eu.kanade.tachiyomi.extension.ru.remanga.dto.SeriesExWrapperDto
|
||||||
import eu.kanade.tachiyomi.extension.ru.remanga.dto.SeriesWrapperDto
|
import eu.kanade.tachiyomi.extension.ru.remanga.dto.SeriesWrapperDto
|
||||||
import eu.kanade.tachiyomi.extension.ru.remanga.dto.TagsDto
|
import eu.kanade.tachiyomi.extension.ru.remanga.dto.TagsDto
|
||||||
import eu.kanade.tachiyomi.extension.ru.remanga.dto.UserDto
|
import eu.kanade.tachiyomi.extension.ru.remanga.dto.UserDto
|
||||||
|
@ -71,6 +73,10 @@ class Remanga : ConfigurableSource, HttpSource() {
|
||||||
private val baseMirr: String = "https://api.xn--80aaig9ahr.xn--c1avg" // https://реманга.орг
|
private val baseMirr: String = "https://api.xn--80aaig9ahr.xn--c1avg" // https://реманга.орг
|
||||||
private val domain: String? = preferences.getString(DOMAIN_PREF, baseOrig)
|
private val domain: String? = preferences.getString(DOMAIN_PREF, baseOrig)
|
||||||
|
|
||||||
|
private val baseRuss: String = "https://exmanga.ru"
|
||||||
|
private val baseUkr: String = "https://ex.euromc.com.ua"
|
||||||
|
private val exManga: String = preferences.getString(exDOMAIN_PREF, baseRuss) ?: baseRuss
|
||||||
|
|
||||||
override val baseUrl = domain.toString()
|
override val baseUrl = domain.toString()
|
||||||
|
|
||||||
override val supportsLatest = true
|
override val supportsLatest = true
|
||||||
|
@ -82,9 +88,19 @@ class Remanga : ConfigurableSource, HttpSource() {
|
||||||
.add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/jxl,image/webp,*/*;q=0.8")
|
.add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/jxl,image/webp,*/*;q=0.8")
|
||||||
.add("Referer", baseUrl.replace("api.", ""))
|
.add("Referer", baseUrl.replace("api.", ""))
|
||||||
|
|
||||||
|
private fun exHeaders() = Headers.Builder()
|
||||||
|
.set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36 Edg/110.0.1587.57")
|
||||||
|
.set("Accept", "image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8")
|
||||||
|
.set("Referer", baseUrl.replace("api.", ""))
|
||||||
|
.build()
|
||||||
private fun authIntercept(chain: Interceptor.Chain): Response {
|
private fun authIntercept(chain: Interceptor.Chain): Response {
|
||||||
val request = chain.request()
|
val request = chain.request()
|
||||||
|
|
||||||
|
// authorization breaks exManga
|
||||||
|
if (request.url.toString().contains(exManga)) {
|
||||||
|
return chain.proceed(request)
|
||||||
|
}
|
||||||
|
|
||||||
val cookies = client.cookieJar.loadForRequest(baseUrl.replace("api.", "").toHttpUrl())
|
val cookies = client.cookieJar.loadForRequest(baseUrl.replace("api.", "").toHttpUrl())
|
||||||
val authCookie = cookies
|
val authCookie = cookies
|
||||||
.firstOrNull { cookie -> cookie.name == "user" }
|
.firstOrNull { cookie -> cookie.name == "user" }
|
||||||
|
@ -121,6 +137,7 @@ class Remanga : ConfigurableSource, HttpSource() {
|
||||||
network.cloudflareClient.newBuilder()
|
network.cloudflareClient.newBuilder()
|
||||||
.rateLimitHost("https://img3.reimg.org".toHttpUrl(), 2)
|
.rateLimitHost("https://img3.reimg.org".toHttpUrl(), 2)
|
||||||
.rateLimitHost("https://img5.reimg.org".toHttpUrl(), 2)
|
.rateLimitHost("https://img5.reimg.org".toHttpUrl(), 2)
|
||||||
|
.rateLimitHost(exManga.toHttpUrl(), 2)
|
||||||
.addInterceptor { imageContentTypeIntercept(it) }
|
.addInterceptor { imageContentTypeIntercept(it) }
|
||||||
.addInterceptor { authIntercept(it) }
|
.addInterceptor { authIntercept(it) }
|
||||||
.build()
|
.build()
|
||||||
|
@ -129,6 +146,8 @@ class Remanga : ConfigurableSource, HttpSource() {
|
||||||
|
|
||||||
private var branches = mutableMapOf<String, List<BranchesDto>>()
|
private var branches = mutableMapOf<String, List<BranchesDto>>()
|
||||||
|
|
||||||
|
private var mangaIDs = mutableMapOf<String, Long>()
|
||||||
|
|
||||||
override fun popularMangaRequest(page: Int) = GET("$baseUrl/api/search/catalog/?ordering=-rating&count=$count&page=$page", headers)
|
override fun popularMangaRequest(page: Int) = GET("$baseUrl/api/search/catalog/?ordering=-rating&count=$count&page=$page", headers)
|
||||||
|
|
||||||
override fun popularMangaParse(response: Response): MangasPage = searchMangaParse(response)
|
override fun popularMangaParse(response: Response): MangasPage = searchMangaParse(response)
|
||||||
|
@ -331,17 +350,20 @@ class Remanga : ConfigurableSource, HttpSource() {
|
||||||
}
|
}
|
||||||
override fun mangaDetailsParse(response: Response): SManga {
|
override fun mangaDetailsParse(response: Response): SManga {
|
||||||
val series = json.decodeFromString<SeriesWrapperDto<MangaDetDto>>(response.body.string())
|
val series = json.decodeFromString<SeriesWrapperDto<MangaDetDto>>(response.body.string())
|
||||||
branches[series.content.en_name] = series.content.branches
|
branches[series.content.dir] = series.content.branches
|
||||||
|
mangaIDs[series.content.dir] = series.content.id
|
||||||
return series.content.toSManga()
|
return series.content.toSManga()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun mangaBranches(manga: SManga): List<BranchesDto> {
|
private fun mangaBranches(manga: SManga): List<BranchesDto> {
|
||||||
val responseString = client.newCall(GET(baseUrl + manga.url)).execute().body.string()
|
val responseString = client.newCall(GET(baseUrl + manga.url)).execute().body.string()
|
||||||
// manga requiring login return "content" as a JsonArray instead of the JsonObject we expect
|
// manga requiring login return "content" as a JsonArray instead of the JsonObject we expect
|
||||||
|
// callback request for update outside the library
|
||||||
val content = json.decodeFromString<JsonObject>(responseString)["content"]
|
val content = json.decodeFromString<JsonObject>(responseString)["content"]
|
||||||
return if (content is JsonObject) {
|
return if (content is JsonObject) {
|
||||||
val series = json.decodeFromJsonElement<MangaDetDto>(content)
|
val series = json.decodeFromJsonElement<MangaDetDto>(content)
|
||||||
branches[series.en_name] = series.branches
|
branches[series.dir] = series.branches
|
||||||
|
mangaIDs[series.dir] = series.id
|
||||||
series.branches
|
series.branches
|
||||||
} else {
|
} else {
|
||||||
emptyList()
|
emptyList()
|
||||||
|
@ -350,7 +372,8 @@ class Remanga : ConfigurableSource, HttpSource() {
|
||||||
|
|
||||||
private fun selector(b: BranchesDto): Int = b.count_chapters
|
private fun selector(b: BranchesDto): Int = b.count_chapters
|
||||||
override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> {
|
override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> {
|
||||||
val branch = branches.getOrElse(manga.title) { mangaBranches(manga) }
|
val branch = branches.getOrElse(manga.url.substringAfter("/api/titles/").substringBefore("/")) { mangaBranches(manga) }
|
||||||
|
val mangaID = mangaIDs[manga.url.substringAfter("/api/titles/").substringBefore("/")]
|
||||||
return when {
|
return when {
|
||||||
manga.status == SManga.LICENSED && branch.isEmpty() -> {
|
manga.status == SManga.LICENSED && branch.isEmpty() -> {
|
||||||
Observable.error(Exception("Лицензировано - Нет глав"))
|
Observable.error(Exception("Лицензировано - Нет глав"))
|
||||||
|
@ -362,7 +385,7 @@ class Remanga : ConfigurableSource, HttpSource() {
|
||||||
val selectedBranch = branch.maxByOrNull { selector(it) }!!
|
val selectedBranch = branch.maxByOrNull { selector(it) }!!
|
||||||
return (1..(selectedBranch.count_chapters / 100 + 1)).map {
|
return (1..(selectedBranch.count_chapters / 100 + 1)).map {
|
||||||
val response = chapterListRequest(selectedBranch.id, it)
|
val response = chapterListRequest(selectedBranch.id, it)
|
||||||
chapterListParse(response, manga)
|
chapterListParse(response, manga, mangaID)
|
||||||
}.let { Observable.just(it.flatten()) }
|
}.let { Observable.just(it.flatten()) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -382,29 +405,22 @@ class Remanga : ConfigurableSource, HttpSource() {
|
||||||
this
|
this
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("DefaultLocale")
|
|
||||||
private fun chapterName(book: BookDto): String {
|
|
||||||
var chapterName = "${book.tome}. Глава ${book.chapter}"
|
|
||||||
if (book.is_paid and (book.is_bought != true)) {
|
|
||||||
chapterName += " \uD83D\uDCB2 "
|
|
||||||
}
|
|
||||||
if (book.name.isNotBlank()) {
|
|
||||||
chapterName += " ${book.name.capitalize()}"
|
|
||||||
}
|
|
||||||
return chapterName
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun chapterListParse(response: Response) = throw UnsupportedOperationException("chapterListParse(response: Response, manga: SManga)")
|
override fun chapterListParse(response: Response) = throw UnsupportedOperationException("chapterListParse(response: Response, manga: SManga)")
|
||||||
|
|
||||||
private fun chapterListParse(response: Response, manga: SManga): List<SChapter> {
|
private fun chapterListParse(response: Response, manga: SManga, mangaID: Long?): List<SChapter> {
|
||||||
var chapters = json.decodeFromString<SeriesWrapperDto<List<BookDto>>>(response.body.string()).content
|
val chapters = json.decodeFromString<SeriesWrapperDto<List<BookDto>>>(response.body.string()).content
|
||||||
if (!preferences.getBoolean(PAID_PREF, false)) {
|
val exChapters = if (preferences.getBoolean(exPAID_PREF, true)) {
|
||||||
chapters = chapters.filter { !it.is_paid or (it.is_bought == true) }
|
try {
|
||||||
|
json.decodeFromString<SeriesExWrapperDto<List<ExBookDto>>>(client.newCall(GET("$exManga/chapter/history/$mangaID", exHeaders())).execute().body.string()).data
|
||||||
|
} catch (_: Exception) {
|
||||||
|
throw Exception("Домен $exManga сервиса exmanga недоступен, выберите другой в настройках расширения")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
emptyList()
|
||||||
}
|
}
|
||||||
return chapters.map { chapter ->
|
var chaptersList = chapters.map { chapter ->
|
||||||
SChapter.create().apply {
|
SChapter.create().apply {
|
||||||
chapter_number = chapter.chapter.split(".").take(2).joinToString(".").toFloat()
|
chapter_number = chapter.chapter.split(".").take(2).joinToString(".").toFloat()
|
||||||
name = chapterName(chapter)
|
|
||||||
url = "/manga/${manga.url.substringAfterLast("/api/titles/")}ch${chapter.id}"
|
url = "/manga/${manga.url.substringAfterLast("/api/titles/")}ch${chapter.id}"
|
||||||
date_upload = parseDate(chapter.upload_date)
|
date_upload = parseDate(chapter.upload_date)
|
||||||
scanlator = if (chapter.publishers.isNotEmpty()) {
|
scanlator = if (chapter.publishers.isNotEmpty()) {
|
||||||
|
@ -412,8 +428,34 @@ class Remanga : ConfigurableSource, HttpSource() {
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var exChID = exChapters.find { (it.id == chapter.id) }
|
||||||
|
if (preferences.getBoolean(exPAID_PREF, true)) {
|
||||||
|
if (chapter.is_paid) {
|
||||||
|
if (exChID != null) {
|
||||||
|
url = "$exManga/chapter?id=${exChID.id}"
|
||||||
|
scanlator = "exmanga"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
exChID = null
|
||||||
|
}
|
||||||
|
|
||||||
|
var chapterName = "${chapter.tome}. Глава ${chapter.chapter}"
|
||||||
|
if (chapter.is_paid and (chapter.is_bought != true) and (exChID == null)) {
|
||||||
|
chapterName += " \uD83D\uDCB2 "
|
||||||
|
}
|
||||||
|
if (chapter.name.isNotBlank()) {
|
||||||
|
chapterName += " ${chapter.name.capitalize()}"
|
||||||
|
}
|
||||||
|
|
||||||
|
name = chapterName
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!preferences.getBoolean(PAID_PREF, false)) {
|
||||||
|
chaptersList = chaptersList.filter { !it.name.contains("\uD83D\uDCB2") }
|
||||||
|
}
|
||||||
|
return chaptersList
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun fixLink(link: String): String {
|
private fun fixLink(link: String): String {
|
||||||
|
@ -427,25 +469,47 @@ class Remanga : ConfigurableSource, HttpSource() {
|
||||||
override fun pageListParse(response: Response): List<Page> {
|
override fun pageListParse(response: Response): List<Page> {
|
||||||
val body = response.body.string()
|
val body = response.body.string()
|
||||||
val heightEmptyChunks = 10
|
val heightEmptyChunks = 10
|
||||||
return try {
|
try {
|
||||||
val page = json.decodeFromString<SeriesWrapperDto<PageDto>>(body)
|
val exPage = json.decodeFromString<SeriesExWrapperDto<List<List<PagesDto>>>>(body)
|
||||||
page.content.pages.filter { it.height > heightEmptyChunks }.map {
|
|
||||||
Page(it.page, "", fixLink(it.link))
|
|
||||||
}
|
|
||||||
} catch (e: SerializationException) {
|
|
||||||
val page = json.decodeFromString<SeriesWrapperDto<ChunksPageDto>>(body)
|
|
||||||
val result = mutableListOf<Page>()
|
val result = mutableListOf<Page>()
|
||||||
page.content.pages.forEach {
|
exPage.data.forEach {
|
||||||
it.filter { page -> page.height > heightEmptyChunks }.forEach { page ->
|
it.filter { page -> page.height > heightEmptyChunks }.forEach { page ->
|
||||||
result.add(Page(result.size, "", fixLink(page.link)))
|
result.add(Page(result.size, "", page.link))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
|
} catch (e: SerializationException) {
|
||||||
|
return try {
|
||||||
|
val page = json.decodeFromString<SeriesWrapperDto<PageDto>>(body)
|
||||||
|
page.content.pages.filter { it.height > heightEmptyChunks }.map {
|
||||||
|
Page(it.page, "", fixLink(it.link))
|
||||||
|
}
|
||||||
|
} catch (e: SerializationException) {
|
||||||
|
val page = json.decodeFromString<SeriesWrapperDto<ChunksPageDto>>(body)
|
||||||
|
val result = mutableListOf<Page>()
|
||||||
|
page.content.pages.forEach {
|
||||||
|
it.filter { page -> page.height > heightEmptyChunks }.forEach { page ->
|
||||||
|
result.add(Page(result.size, "", fixLink(page.link)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun pageListRequest(chapter: SChapter): Request {
|
override fun pageListRequest(chapter: SChapter): Request {
|
||||||
return GET(baseUrl + "/api/titles/chapters/" + chapter.url.substringAfterLast("/ch"), headers)
|
return if (chapter.url.contains(exManga)) {
|
||||||
|
GET(chapter.url, exHeaders())
|
||||||
|
} else {
|
||||||
|
if (chapter.name.contains("\uD83D\uDCB2")) {
|
||||||
|
throw Exception("Глава платная. Если вы покупаете главу, то, пожалуйста, поделитесь с другими через браузерное расширение exmanga.")
|
||||||
|
}
|
||||||
|
GET(baseUrl + "/api/titles/chapters/" + chapter.url.substringAfterLast("/ch"), headers)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getChapterUrl(chapter: SChapter): String {
|
||||||
|
return if (chapter.url.contains(exManga)) chapter.url else baseUrl.replace("api.", "") + chapter.url
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun fetchImageUrl(page: Page): Observable<String> = Observable.just(page.imageUrl!!)
|
override fun fetchImageUrl(page: Page): Observable<String> = Observable.just(page.imageUrl!!)
|
||||||
|
@ -479,7 +543,11 @@ class Remanga : ConfigurableSource, HttpSource() {
|
||||||
|
|
||||||
override fun imageRequest(page: Page): Request {
|
override fun imageRequest(page: Page): Request {
|
||||||
val refererHeaders = headersBuilder().build()
|
val refererHeaders = headersBuilder().build()
|
||||||
return GET(page.imageUrl!!, refererHeaders)
|
return if (page.imageUrl!!.contains(exManga)) {
|
||||||
|
GET(page.imageUrl!!, exHeaders())
|
||||||
|
} else {
|
||||||
|
GET(page.imageUrl!!, refererHeaders)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SearchFilter(name: String, val id: String) : Filter.TriState(name)
|
private class SearchFilter(name: String, val id: String) : Filter.TriState(name)
|
||||||
|
@ -686,18 +754,18 @@ class Remanga : ConfigurableSource, HttpSource() {
|
||||||
|
|
||||||
private fun getMyList() = listOf(
|
private fun getMyList() = listOf(
|
||||||
MyListUnit("Каталог", "-"),
|
MyListUnit("Каталог", "-"),
|
||||||
MyListUnit("Читаю", "0"),
|
MyListUnit("Читаю", "1"),
|
||||||
MyListUnit("Буду читать", "1"),
|
MyListUnit("Буду читать", "2"),
|
||||||
MyListUnit("Прочитано", "2"),
|
MyListUnit("Прочитано", "3"),
|
||||||
MyListUnit("Отложено", "4"),
|
MyListUnit("Брошено ", "4"),
|
||||||
MyListUnit("Брошено ", "3"),
|
MyListUnit("Отложено", "5"),
|
||||||
MyListUnit("Не интересно ", "5"),
|
MyListUnit("Не интересно ", "6"),
|
||||||
)
|
)
|
||||||
private var isEng: String? = preferences.getString(LANGUAGE_PREF, "eng")
|
private var isEng: String? = preferences.getString(LANGUAGE_PREF, "eng")
|
||||||
override fun setupPreferenceScreen(screen: androidx.preference.PreferenceScreen) {
|
override fun setupPreferenceScreen(screen: androidx.preference.PreferenceScreen) {
|
||||||
val domainPref = ListPreference(screen.context).apply {
|
val domainPref = ListPreference(screen.context).apply {
|
||||||
key = DOMAIN_PREF
|
key = DOMAIN_PREF
|
||||||
title = DOMAIN_PREF_Title
|
title = "Выбор домена"
|
||||||
entries = arrayOf("Основной (remanga.org)", "Зеркало (реманга.орг)")
|
entries = arrayOf("Основной (remanga.org)", "Зеркало (реманга.орг)")
|
||||||
entryValues = arrayOf(baseOrig, baseMirr)
|
entryValues = arrayOf(baseOrig, baseMirr)
|
||||||
summary = "%s"
|
summary = "%s"
|
||||||
|
@ -730,7 +798,7 @@ class Remanga : ConfigurableSource, HttpSource() {
|
||||||
}
|
}
|
||||||
val paidChapterShow = androidx.preference.CheckBoxPreference(screen.context).apply {
|
val paidChapterShow = androidx.preference.CheckBoxPreference(screen.context).apply {
|
||||||
key = PAID_PREF
|
key = PAID_PREF
|
||||||
title = PAID_PREF_Title
|
title = "Показывать платные главы"
|
||||||
summary = "Показывает не купленные\uD83D\uDCB2 главы(может вызвать ошибки при обновлении/автозагрузке)"
|
summary = "Показывает не купленные\uD83D\uDCB2 главы(может вызвать ошибки при обновлении/автозагрузке)"
|
||||||
setDefaultValue(false)
|
setDefaultValue(false)
|
||||||
|
|
||||||
|
@ -739,6 +807,36 @@ class Remanga : ConfigurableSource, HttpSource() {
|
||||||
preferences.edit().putBoolean(key, checkValue).commit()
|
preferences.edit().putBoolean(key, checkValue).commit()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
val exChapterShow = androidx.preference.CheckBoxPreference(screen.context).apply {
|
||||||
|
key = exPAID_PREF
|
||||||
|
title = "Показывать главы из exmanga"
|
||||||
|
summary = "Показывает главы купленные другими людьми и поделившиеся ими через браузерное расширение exmanga"
|
||||||
|
setDefaultValue(true)
|
||||||
|
|
||||||
|
setOnPreferenceChangeListener { _, newValue ->
|
||||||
|
val checkValue = newValue as Boolean
|
||||||
|
preferences.edit().putBoolean(key, checkValue).commit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val domainExPref = ListPreference(screen.context).apply {
|
||||||
|
key = exDOMAIN_PREF
|
||||||
|
title = "Выбор домена для exmanga"
|
||||||
|
entries = arrayOf("Россия (exmanga.ru)", "Украина (ex.euromc.com.ua)")
|
||||||
|
entryValues = arrayOf(baseRuss, baseUkr)
|
||||||
|
summary = "%s"
|
||||||
|
setDefaultValue(baseRuss)
|
||||||
|
setOnPreferenceChangeListener { _, newValue ->
|
||||||
|
try {
|
||||||
|
val res = preferences.edit().putString(exDOMAIN_PREF, newValue as String).commit()
|
||||||
|
val warning = "Для смены домена необходимо перезапустить приложение с полной остановкой."
|
||||||
|
Toast.makeText(screen.context, warning, Toast.LENGTH_LONG).show()
|
||||||
|
res
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
val bookmarksHide = androidx.preference.CheckBoxPreference(screen.context).apply {
|
val bookmarksHide = androidx.preference.CheckBoxPreference(screen.context).apply {
|
||||||
key = isLib_PREF
|
key = isLib_PREF
|
||||||
title = isLib_PREF_Title
|
title = isLib_PREF_Title
|
||||||
|
@ -753,24 +851,29 @@ class Remanga : ConfigurableSource, HttpSource() {
|
||||||
screen.addPreference(domainPref)
|
screen.addPreference(domainPref)
|
||||||
screen.addPreference(titleLanguagePref)
|
screen.addPreference(titleLanguagePref)
|
||||||
screen.addPreference(paidChapterShow)
|
screen.addPreference(paidChapterShow)
|
||||||
|
screen.addPreference(exChapterShow)
|
||||||
|
screen.addPreference(domainExPref)
|
||||||
screen.addPreference(bookmarksHide)
|
screen.addPreference(bookmarksHide)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val json: Json by injectLazy()
|
private val json: Json by injectLazy()
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
private var USER_ID = ""
|
private var USER_ID = ""
|
||||||
|
|
||||||
const val PREFIX_SLUG_SEARCH = "slug:"
|
const val PREFIX_SLUG_SEARCH = "slug:"
|
||||||
|
|
||||||
private const val DOMAIN_PREF = "REMangaDomain"
|
private const val DOMAIN_PREF = "REMangaDomain"
|
||||||
private const val DOMAIN_PREF_Title = "Выбор домена"
|
|
||||||
|
private const val exDOMAIN_PREF = "EXMangaDomain"
|
||||||
|
|
||||||
private const val LANGUAGE_PREF = "ReMangaTitleLanguage"
|
private const val LANGUAGE_PREF = "ReMangaTitleLanguage"
|
||||||
private const val LANGUAGE_PREF_Title = "Выбор языка на обложке"
|
private const val LANGUAGE_PREF_Title = "Выбор языка на обложке"
|
||||||
|
|
||||||
private const val PAID_PREF = "PaidChapter"
|
private const val PAID_PREF = "PaidChapter"
|
||||||
private const val PAID_PREF_Title = "Показывать платные главы"
|
|
||||||
|
private const val exPAID_PREF = "ExChapter"
|
||||||
|
|
||||||
private const val isLib_PREF = "LibBookmarks"
|
private const val isLib_PREF = "LibBookmarks"
|
||||||
private const val isLib_PREF_Title = "Скрыть «Закладки»"
|
private const val isLib_PREF_Title = "Скрыть «Закладки»"
|
||||||
|
|
|
@ -96,6 +96,16 @@ data class BookDto(
|
||||||
val publishers: List<PublisherDto>,
|
val publishers: List<PublisherDto>,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class SeriesExWrapperDto<T>(
|
||||||
|
val data: T,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class ExBookDto(
|
||||||
|
val id: Long,
|
||||||
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class PagesDto(
|
data class PagesDto(
|
||||||
val id: Int,
|
val id: Int,
|
||||||
|
|