Add Remanga source
parent
0d0e3acd04
commit
85c424580a
@ -1,10 +1,12 @@
|
|||||||
package org.koitharu.kotatsu.core.parser.site
|
package org.koitharu.kotatsu.core.parser.site
|
||||||
|
|
||||||
/*
|
import org.koitharu.kotatsu.base.domain.MangaLoaderContext
|
||||||
|
import org.koitharu.kotatsu.core.model.MangaSource
|
||||||
|
|
||||||
class HentaiLibRepository(loaderContext: MangaLoaderContext) : MangaLibRepository(loaderContext) {
|
class HentaiLibRepository(loaderContext: MangaLoaderContext) : MangaLibRepository(loaderContext) {
|
||||||
|
|
||||||
protected override val defaultDomain = "hentailib.me"
|
override val defaultDomain = "hentailib.me"
|
||||||
|
|
||||||
override val source = MangaSource.HENTAILIB
|
override val source = MangaSource.HENTAILIB
|
||||||
|
|
||||||
}*/
|
}
|
||||||
|
|||||||
@ -0,0 +1,183 @@
|
|||||||
|
package org.koitharu.kotatsu.core.parser.site
|
||||||
|
|
||||||
|
import androidx.collection.arraySetOf
|
||||||
|
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||||
|
import org.json.JSONArray
|
||||||
|
import org.json.JSONException
|
||||||
|
import org.json.JSONObject
|
||||||
|
import org.koitharu.kotatsu.base.domain.MangaLoaderContext
|
||||||
|
import org.koitharu.kotatsu.core.exceptions.ParseException
|
||||||
|
import org.koitharu.kotatsu.core.model.*
|
||||||
|
import org.koitharu.kotatsu.core.parser.RemoteMangaRepository
|
||||||
|
import org.koitharu.kotatsu.core.prefs.SourceSettings
|
||||||
|
import org.koitharu.kotatsu.utils.ext.*
|
||||||
|
import java.util.*
|
||||||
|
import kotlin.collections.ArrayList
|
||||||
|
|
||||||
|
class RemangaRepository(loaderContext: MangaLoaderContext) : RemoteMangaRepository(loaderContext) {
|
||||||
|
|
||||||
|
override val source = MangaSource.REMANGA
|
||||||
|
|
||||||
|
override val sortOrders: Set<SortOrder> = EnumSet.of(
|
||||||
|
SortOrder.POPULARITY,
|
||||||
|
SortOrder.RATING,
|
||||||
|
SortOrder.ALPHABETICAL,
|
||||||
|
SortOrder.UPDATED,
|
||||||
|
SortOrder.NEWEST
|
||||||
|
)
|
||||||
|
|
||||||
|
override suspend fun getList(
|
||||||
|
offset: Int,
|
||||||
|
query: String?,
|
||||||
|
sortOrder: SortOrder?,
|
||||||
|
tag: MangaTag?
|
||||||
|
): List<Manga> {
|
||||||
|
val domain = conf.getDomain(DEFAULT_DOMAIN)
|
||||||
|
val urlBuilder = StringBuilder()
|
||||||
|
.append("https://api.")
|
||||||
|
.append(domain)
|
||||||
|
if (query != null) {
|
||||||
|
urlBuilder.append("/api/search/?query=")
|
||||||
|
.append(query.urlEncoded())
|
||||||
|
} else {
|
||||||
|
urlBuilder.append("/api/search/catalog/?page=")
|
||||||
|
.append("&ordering=")
|
||||||
|
.append(getSortKey(sortOrder))
|
||||||
|
if (tag != null) {
|
||||||
|
urlBuilder.append("&genres=" + tag.key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
urlBuilder.append((offset / PAGE_SIZE) + 1)
|
||||||
|
.append("&count=")
|
||||||
|
.append(PAGE_SIZE)
|
||||||
|
val content = loaderContext.httpGet(urlBuilder.toString()).parseJson()
|
||||||
|
.getJSONArray("content")
|
||||||
|
return content.map { jo ->
|
||||||
|
val url = "https://$domain/manga/${jo.getString("dir")}"
|
||||||
|
val img = jo.getJSONObject("img")
|
||||||
|
Manga(
|
||||||
|
id = generateUid(url),
|
||||||
|
url = url,
|
||||||
|
title = jo.getString("rus_name"),
|
||||||
|
altTitle = jo.getString("en_name"),
|
||||||
|
rating = jo.getString("avg_rating").toFloatOrNull()?.div(10f) ?: Manga.NO_RATING,
|
||||||
|
coverUrl = "https://api.$domain${img.getString("mid")}",
|
||||||
|
largeCoverUrl = "https://api.$domain${img.getString("high")}",
|
||||||
|
author = null,
|
||||||
|
tags = jo.optJSONArray("genres")?.mapToSet { g ->
|
||||||
|
MangaTag(
|
||||||
|
title = g.getString("name"),
|
||||||
|
key = g.getInt("id").toString(),
|
||||||
|
source = MangaSource.REMANGA
|
||||||
|
)
|
||||||
|
}.orEmpty(),
|
||||||
|
source = MangaSource.REMANGA
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getDetails(manga: Manga): Manga {
|
||||||
|
val domain = conf.getDomain(DEFAULT_DOMAIN)
|
||||||
|
val slug = manga.url.toHttpUrl().pathSegments.last()
|
||||||
|
val data = loaderContext.httpGet(
|
||||||
|
url = "https://api.$domain/api/titles/$slug/"
|
||||||
|
).parseJson()
|
||||||
|
val content = try {
|
||||||
|
data.getJSONObject("content")
|
||||||
|
} catch (e: JSONException) {
|
||||||
|
throw ParseException(data.optString("msg"), e)
|
||||||
|
}
|
||||||
|
val branchId = content.getJSONArray("branches").optJSONObject(0)
|
||||||
|
?.getLong("id") ?: throw ParseException("No branches found")
|
||||||
|
val chapters = loaderContext.httpGet(
|
||||||
|
url = "https://api.$domain/api/titles/chapters/?branch_id=$branchId"
|
||||||
|
).parseJson().getJSONArray("content")
|
||||||
|
return manga.copy(
|
||||||
|
description = content.getString("description"),
|
||||||
|
state = when (content.optJSONObject("status")?.getInt("id")) {
|
||||||
|
STATUS_ONGOING -> MangaState.ONGOING
|
||||||
|
STATUS_FINISHED -> MangaState.FINISHED
|
||||||
|
else -> null
|
||||||
|
},
|
||||||
|
tags = content.getJSONArray("genres").mapToSet { g ->
|
||||||
|
MangaTag(
|
||||||
|
title = g.getString("name"),
|
||||||
|
key = g.getInt("id").toString(),
|
||||||
|
source = MangaSource.REMANGA
|
||||||
|
)
|
||||||
|
},
|
||||||
|
chapters = chapters.mapIndexed { i, jo ->
|
||||||
|
val id = jo.getLong("id")
|
||||||
|
val name = jo.getString("name")
|
||||||
|
MangaChapter(
|
||||||
|
id = generateUid(id.toInt()),
|
||||||
|
url = "https://api.$domain/api/titles/chapters/$id/",
|
||||||
|
number = chapters.length() - i,
|
||||||
|
name = buildString {
|
||||||
|
append("Глава ")
|
||||||
|
append(jo.getString("chapter"))
|
||||||
|
if (name.isNotEmpty()) {
|
||||||
|
append(" - ")
|
||||||
|
append(name)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
source = MangaSource.REMANGA
|
||||||
|
)
|
||||||
|
}.asReversed()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
|
||||||
|
val referer = "https://${conf.getDomain(DEFAULT_DOMAIN)}/"
|
||||||
|
val content = loaderContext.httpGet(chapter.url).parseJson()
|
||||||
|
.getJSONObject("content").getJSONArray("pages")
|
||||||
|
val pages = ArrayList<MangaPage>(content.length())
|
||||||
|
for (i in 0 until content.length()) {
|
||||||
|
when (val item = content.get(i)) {
|
||||||
|
is JSONObject -> pages += parsePage(item, referer)
|
||||||
|
is JSONArray -> item.mapTo(pages) { parsePage(it, referer) }
|
||||||
|
else -> throw ParseException("Unknown json item $item")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pages
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getTags(): Set<MangaTag> {
|
||||||
|
val domain = conf.getDomain(DEFAULT_DOMAIN)
|
||||||
|
val content = loaderContext.httpGet("https://api.$domain/api/forms/titles/?get=genres")
|
||||||
|
.parseJson().getJSONObject("content").getJSONArray("genres")
|
||||||
|
return content.mapToSet { jo ->
|
||||||
|
MangaTag(
|
||||||
|
title = jo.getString("name"),
|
||||||
|
key = jo.getInt("id").toString(),
|
||||||
|
source = source
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreatePreferences() = arraySetOf(SourceSettings.KEY_DOMAIN)
|
||||||
|
|
||||||
|
private fun getSortKey(order: SortOrder?) = when (order) {
|
||||||
|
SortOrder.UPDATED -> "-chapter_date"
|
||||||
|
SortOrder.POPULARITY -> "-rating"
|
||||||
|
SortOrder.RATING -> "-votes"
|
||||||
|
SortOrder.NEWEST -> "-id"
|
||||||
|
else -> "-rating"
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun parsePage(jo: JSONObject, referer: String) = MangaPage(
|
||||||
|
id = generateUid(jo.getLong("id").toInt()),
|
||||||
|
url = jo.getString("link"),
|
||||||
|
referer = referer,
|
||||||
|
source = source
|
||||||
|
)
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
|
||||||
|
const val PAGE_SIZE = 30
|
||||||
|
const val DEFAULT_DOMAIN = "remanga.org"
|
||||||
|
|
||||||
|
const val STATUS_ONGOING = 1
|
||||||
|
const val STATUS_FINISHED = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue