Delegate Pururin.io
This commit is contained in:
parent
68de7b516e
commit
5195cb8eda
@ -154,6 +154,7 @@
|
|||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
|
||||||
|
<!-- EH -->
|
||||||
<data
|
<data
|
||||||
android:host="g.e-hentai.org"
|
android:host="g.e-hentai.org"
|
||||||
android:pathPrefix="/g/"
|
android:pathPrefix="/g/"
|
||||||
@ -170,6 +171,8 @@
|
|||||||
android:host="e-hentai.org"
|
android:host="e-hentai.org"
|
||||||
android:pathPrefix="/g/"
|
android:pathPrefix="/g/"
|
||||||
android:scheme="https" />
|
android:scheme="https" />
|
||||||
|
|
||||||
|
<!-- EXH -->
|
||||||
<data
|
<data
|
||||||
android:host="exhentai.org"
|
android:host="exhentai.org"
|
||||||
android:pathPrefix="/g/"
|
android:pathPrefix="/g/"
|
||||||
@ -178,6 +181,8 @@
|
|||||||
android:host="exhentai.org"
|
android:host="exhentai.org"
|
||||||
android:pathPrefix="/g/"
|
android:pathPrefix="/g/"
|
||||||
android:scheme="https" />
|
android:scheme="https" />
|
||||||
|
|
||||||
|
<!-- nhentai -->
|
||||||
<data
|
<data
|
||||||
android:host="nhentai.net"
|
android:host="nhentai.net"
|
||||||
android:pathPrefix="/g/"
|
android:pathPrefix="/g/"
|
||||||
@ -186,6 +191,8 @@
|
|||||||
android:host="nhentai.net"
|
android:host="nhentai.net"
|
||||||
android:pathPrefix="/g/"
|
android:pathPrefix="/g/"
|
||||||
android:scheme="https" />
|
android:scheme="https" />
|
||||||
|
|
||||||
|
<!-- Perv Eden -->
|
||||||
<data
|
<data
|
||||||
android:host="www.perveden.com"
|
android:host="www.perveden.com"
|
||||||
android:pathPattern="/.*/.*-manga/.*"
|
android:pathPattern="/.*/.*-manga/.*"
|
||||||
@ -194,6 +201,8 @@
|
|||||||
android:host="www.perveden.com"
|
android:host="www.perveden.com"
|
||||||
android:pathPattern="/.*/.*-manga/.*"
|
android:pathPattern="/.*/.*-manga/.*"
|
||||||
android:scheme="https" />
|
android:scheme="https" />
|
||||||
|
|
||||||
|
<!-- Hentai Cafe -->
|
||||||
<data
|
<data
|
||||||
android:host="hentai.cafe"
|
android:host="hentai.cafe"
|
||||||
android:pathPattern="/.*/.*"
|
android:pathPattern="/.*/.*"
|
||||||
@ -202,6 +211,8 @@
|
|||||||
android:host="hentai.cafe"
|
android:host="hentai.cafe"
|
||||||
android:pathPattern="/.*/.*"
|
android:pathPattern="/.*/.*"
|
||||||
android:scheme="https" />
|
android:scheme="https" />
|
||||||
|
|
||||||
|
<!-- Tsumino -->
|
||||||
<data
|
<data
|
||||||
android:host="www.tsumino.com"
|
android:host="www.tsumino.com"
|
||||||
android:pathPrefix="/Book/Info/"
|
android:pathPrefix="/Book/Info/"
|
||||||
@ -218,6 +229,8 @@
|
|||||||
android:host="www.tsumino.com"
|
android:host="www.tsumino.com"
|
||||||
android:pathPrefix="/Read/View/"
|
android:pathPrefix="/Read/View/"
|
||||||
android:scheme="https" />
|
android:scheme="https" />
|
||||||
|
|
||||||
|
<!-- Hitomi.la -->
|
||||||
<data
|
<data
|
||||||
android:host="hitomi.la"
|
android:host="hitomi.la"
|
||||||
android:pathPrefix="/galleries/"
|
android:pathPrefix="/galleries/"
|
||||||
@ -234,6 +247,16 @@
|
|||||||
android:host="hitomi.la"
|
android:host="hitomi.la"
|
||||||
android:pathPrefix="/reader/"
|
android:pathPrefix="/reader/"
|
||||||
android:scheme="https" />
|
android:scheme="https" />
|
||||||
|
|
||||||
|
<!-- Pururin.io -->
|
||||||
|
<data
|
||||||
|
android:host="pururin.io"
|
||||||
|
android:pathPrefix="/gallery/"
|
||||||
|
android:scheme="http" />
|
||||||
|
<data
|
||||||
|
android:host="pururin.io"
|
||||||
|
android:pathPrefix="/gallery/"
|
||||||
|
android:scheme="https" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
|
@ -11,6 +11,7 @@ import eu.kanade.tachiyomi.data.preference.getOrDefault
|
|||||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||||
import eu.kanade.tachiyomi.source.online.all.*
|
import eu.kanade.tachiyomi.source.online.all.*
|
||||||
import eu.kanade.tachiyomi.source.online.english.HentaiCafe
|
import eu.kanade.tachiyomi.source.online.english.HentaiCafe
|
||||||
|
import eu.kanade.tachiyomi.source.online.english.Pururin
|
||||||
import eu.kanade.tachiyomi.source.online.english.Tsumino
|
import eu.kanade.tachiyomi.source.online.english.Tsumino
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import exh.EH_SOURCE_ID
|
import exh.EH_SOURCE_ID
|
||||||
@ -149,12 +150,18 @@ open class SourceManager(private val context: Context) {
|
|||||||
260868874183818481,
|
260868874183818481,
|
||||||
"eu.kanade.tachiyomi.extension.all.foolslide.HentaiCafe",
|
"eu.kanade.tachiyomi.extension.all.foolslide.HentaiCafe",
|
||||||
HentaiCafe::class
|
HentaiCafe::class
|
||||||
|
),
|
||||||
|
DelegatedSource(
|
||||||
|
"Pururin",
|
||||||
|
2221515250486218861,
|
||||||
|
"eu.kanade.tachiyomi.extension.en.pururin.Pururin",
|
||||||
|
Pururin::class
|
||||||
)
|
)
|
||||||
).associateBy { it.originalSourcePackageName }
|
).associateBy { it.originalSourceQualifiedClassName }
|
||||||
|
|
||||||
data class DelegatedSource(val sourceName: String,
|
data class DelegatedSource(val sourceName: String,
|
||||||
val sourceId: Long,
|
val sourceId: Long,
|
||||||
val originalSourcePackageName: String,
|
val originalSourceQualifiedClassName: String,
|
||||||
val newSourceClass: KClass<out DelegatedHttpSource>)
|
val newSourceClass: KClass<out DelegatedHttpSource>)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,19 @@
|
|||||||
package eu.kanade.tachiyomi.source.online.english
|
package eu.kanade.tachiyomi.source.online.english
|
||||||
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||||
import eu.kanade.tachiyomi.source.model.FilterList
|
import eu.kanade.tachiyomi.source.model.FilterList
|
||||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||||
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||||
import eu.kanade.tachiyomi.source.online.LewdSource
|
import eu.kanade.tachiyomi.source.online.LewdSource
|
||||||
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
||||||
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import exh.metadata.metadata.PururinSearchMetadata
|
import exh.metadata.metadata.PururinSearchMetadata
|
||||||
|
import exh.metadata.metadata.base.RaisedTag
|
||||||
import exh.source.DelegatedHttpSource
|
import exh.source.DelegatedHttpSource
|
||||||
|
import exh.util.dropBlank
|
||||||
|
import exh.util.trimAll
|
||||||
import exh.util.urlImportFetchSearchManga
|
import exh.util.urlImportFetchSearchManga
|
||||||
import org.jsoup.nodes.Document
|
import org.jsoup.nodes.Document
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
@ -26,7 +32,6 @@ class Pururin(delegate: HttpSource) : DelegatedHttpSource(delegate),
|
|||||||
//Support direct URL importing
|
//Support direct URL importing
|
||||||
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
|
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
|
||||||
val trimmedIdQuery = query.trim().removePrefix("id:")
|
val trimmedIdQuery = query.trim().removePrefix("id:")
|
||||||
// TODO Fetch gallery shortlink
|
|
||||||
val newQuery = if(trimmedIdQuery.toIntOrNull() ?: -1 >= 0) {
|
val newQuery = if(trimmedIdQuery.toIntOrNull() ?: -1 >= 0) {
|
||||||
"$baseUrl/gallery/$trimmedIdQuery/-"
|
"$baseUrl/gallery/$trimmedIdQuery/-"
|
||||||
} else query
|
} else query
|
||||||
@ -36,6 +41,15 @@ class Pururin(delegate: HttpSource) : DelegatedHttpSource(delegate),
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun fetchMangaDetails(manga: SManga): Observable<SManga> {
|
||||||
|
return client.newCall(mangaDetailsRequest(manga))
|
||||||
|
.asObservableSuccess()
|
||||||
|
.flatMap {
|
||||||
|
parseToManga(manga, it.asJsoup())
|
||||||
|
.andThen(Observable.just(manga))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun parseIntoMetadata(metadata: PururinSearchMetadata, input: Document) {
|
override fun parseIntoMetadata(metadata: PururinSearchMetadata, input: Document) {
|
||||||
val selfLink = input.select("[itemprop=name]").last().parent()
|
val selfLink = input.select("[itemprop=name]").last().parent()
|
||||||
val parsedSelfLink = Uri.parse(selfLink.attr("href")).pathSegments
|
val parsedSelfLink = Uri.parse(selfLink.attr("href")).pathSegments
|
||||||
@ -44,7 +58,52 @@ class Pururin(delegate: HttpSource) : DelegatedHttpSource(delegate),
|
|||||||
prId = parsedSelfLink[parsedSelfLink.lastIndex - 1].toIntOrNull()
|
prId = parsedSelfLink[parsedSelfLink.lastIndex - 1].toIntOrNull()
|
||||||
prShortLink = parsedSelfLink.last()
|
prShortLink = parsedSelfLink.last()
|
||||||
|
|
||||||
title =
|
val contentWrapper = input.selectFirst(".content-wrapper")
|
||||||
|
title = contentWrapper.selectFirst(".title h1").text()
|
||||||
|
altTitle = contentWrapper.selectFirst(".alt-title").text()
|
||||||
|
|
||||||
|
thumbnailUrl = "https:" + input.selectFirst(".cover-wrapper v-lazy-image").attr("src")
|
||||||
|
|
||||||
|
tags.clear()
|
||||||
|
contentWrapper.select(".table-gallery-info > tbody > tr").forEach { ele ->
|
||||||
|
val key = ele.child(0).text().toLowerCase()
|
||||||
|
val value = ele.child(1)
|
||||||
|
when(key) {
|
||||||
|
"pages" -> {
|
||||||
|
val split = value.text().split("(").trimAll().dropBlank()
|
||||||
|
|
||||||
|
pages = split.first().toIntOrNull()
|
||||||
|
fileSize = split.last().removeSuffix(")").trim()
|
||||||
|
}
|
||||||
|
"ratings" -> {
|
||||||
|
ratingCount = value.selectFirst("[itemprop=ratingCount]").attr("content").toIntOrNull()
|
||||||
|
averageRating = value.selectFirst("[itemprop=ratingValue]").attr("content").toDoubleOrNull()
|
||||||
|
}
|
||||||
|
"uploader" -> {
|
||||||
|
uploaderDisp = value.text()
|
||||||
|
uploader = Uri.parse(value.child(0).attr("href")).lastPathSegment
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
value.select("a").forEach { link ->
|
||||||
|
val searchUrl = Uri.parse(link.attr("href"))
|
||||||
|
tags += RaisedTag(
|
||||||
|
searchUrl.pathSegments[searchUrl.pathSegments.lastIndex - 2],
|
||||||
|
searchUrl.lastPathSegment!!.substringBefore("."),
|
||||||
|
PururinSearchMetadata.TAG_TYPE_DEFAULT
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override val matchingHosts = listOf(
|
||||||
|
"pururin.io",
|
||||||
|
"www.pururin.io"
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun mapUrlToMangaUrl(uri: Uri): String? {
|
||||||
|
return "${PururinSearchMetadata.BASE_URL}/gallery/${uri.pathSegments[1]}/${uri.lastPathSegment}"
|
||||||
|
}
|
||||||
}
|
}
|
@ -3,6 +3,7 @@ package exh
|
|||||||
import eu.kanade.tachiyomi.source.Source
|
import eu.kanade.tachiyomi.source.Source
|
||||||
import eu.kanade.tachiyomi.source.SourceManager
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
import eu.kanade.tachiyomi.source.online.english.HentaiCafe
|
import eu.kanade.tachiyomi.source.online.english.HentaiCafe
|
||||||
|
import eu.kanade.tachiyomi.source.online.english.Pururin
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Source helpers
|
* Source helpers
|
||||||
@ -21,7 +22,8 @@ const val HITOMI_SOURCE_ID = LEWD_SOURCE_SERIES + 10
|
|||||||
const val MERGED_SOURCE_ID = LEWD_SOURCE_SERIES + 69
|
const val MERGED_SOURCE_ID = LEWD_SOURCE_SERIES + 69
|
||||||
|
|
||||||
private val DELEGATED_LEWD_SOURCES = listOf(
|
private val DELEGATED_LEWD_SOURCES = listOf(
|
||||||
HentaiCafe::class
|
HentaiCafe::class,
|
||||||
|
Pururin::class
|
||||||
)
|
)
|
||||||
|
|
||||||
private inline fun <reified T> delegatedSourceId(): Long {
|
private inline fun <reified T> delegatedSourceId(): Long {
|
||||||
|
@ -14,27 +14,6 @@ class PururinSearchMetadata : RaisedSearchMetadata() {
|
|||||||
|
|
||||||
var thumbnailUrl: String? = null
|
var thumbnailUrl: String? = null
|
||||||
|
|
||||||
var artist: String? = null
|
|
||||||
var artistDisp: String? = null
|
|
||||||
|
|
||||||
var circle: String? = null
|
|
||||||
var circleDisp: String? = null
|
|
||||||
|
|
||||||
var parody: String? = null // TODO Mult
|
|
||||||
var parodyDisp: String? = null
|
|
||||||
|
|
||||||
var character: String? = null // TODO Mult
|
|
||||||
var characterDisp: String? = null
|
|
||||||
|
|
||||||
var category: String? = null
|
|
||||||
var categoryDisp: String? = null
|
|
||||||
|
|
||||||
var collection: String? = null
|
|
||||||
var collectionDisp: String? = null
|
|
||||||
|
|
||||||
var language: String? = null
|
|
||||||
var languageDisp: String? = null
|
|
||||||
|
|
||||||
var uploaderDisp: String? = null
|
var uploaderDisp: String? = null
|
||||||
|
|
||||||
var pages: Int? = null
|
var pages: Int? = null
|
||||||
@ -59,9 +38,7 @@ class PururinSearchMetadata : RaisedSearchMetadata() {
|
|||||||
manga.thumbnail_url = it
|
manga.thumbnail_url = it
|
||||||
}
|
}
|
||||||
|
|
||||||
(artistDisp ?: artist)?.let {
|
manga.artist = tags.ofNamespace(TAG_NAMESPACE_ARTIST).joinToString { it.name }
|
||||||
manga.artist = it
|
|
||||||
}
|
|
||||||
|
|
||||||
manga.genre = tagsToGenreString()
|
manga.genre = tagsToGenreString()
|
||||||
|
|
||||||
@ -70,10 +47,10 @@ class PururinSearchMetadata : RaisedSearchMetadata() {
|
|||||||
altTitle?.let { titleDesc += "Japanese Title: $it\n" }
|
altTitle?.let { titleDesc += "Japanese Title: $it\n" }
|
||||||
|
|
||||||
val detailsDesc = StringBuilder()
|
val detailsDesc = StringBuilder()
|
||||||
(uploaderDisp ?: uploader)?.let { detailsDesc += "Uploader: $it"}
|
(uploaderDisp ?: uploader)?.let { detailsDesc += "Uploader: $it\n"}
|
||||||
pages?.let { detailsDesc += "Length: $it pages" }
|
pages?.let { detailsDesc += "Length: $it pages\n" }
|
||||||
fileSize?.let { detailsDesc += "Size: $it" }
|
fileSize?.let { detailsDesc += "Size: $it\n" }
|
||||||
ratingCount?.let { detailsDesc += "Rating: $averageRating ($ratingCount)" }
|
ratingCount?.let { detailsDesc += "Rating: $averageRating ($ratingCount)\n" }
|
||||||
|
|
||||||
val tagsDesc = tagsToDescription()
|
val tagsDesc = tagsToDescription()
|
||||||
|
|
||||||
@ -86,7 +63,9 @@ class PururinSearchMetadata : RaisedSearchMetadata() {
|
|||||||
private const val TITLE_TYPE_TITLE = 0
|
private const val TITLE_TYPE_TITLE = 0
|
||||||
private const val TITLE_TYPE_ALT_TITLE = 1
|
private const val TITLE_TYPE_ALT_TITLE = 1
|
||||||
|
|
||||||
const val TAG_TYPE_CONTENTS = 0
|
const val TAG_TYPE_DEFAULT = 0
|
||||||
|
|
||||||
|
private const val TAG_NAMESPACE_ARTIST = "artist"
|
||||||
|
|
||||||
val BASE_URL = "https://pururin.io"
|
val BASE_URL = "https://pururin.io"
|
||||||
}
|
}
|
||||||
|
@ -60,6 +60,10 @@ abstract class RaisedSearchMetadata {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun List<RaisedTag>.ofNamespace(ns: String): List<RaisedTag> {
|
||||||
|
return filter { it.namespace == ns }
|
||||||
|
}
|
||||||
|
|
||||||
fun flatten(): FlatMetadata {
|
fun flatten(): FlatMetadata {
|
||||||
require(mangaId != -1L)
|
require(mangaId != -1L)
|
||||||
|
|
||||||
|
5
app/src/main/java/exh/util/StringUtil.kt
Normal file
5
app/src/main/java/exh/util/StringUtil.kt
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package exh.util
|
||||||
|
|
||||||
|
fun List<String>.trimAll() = map { it.trim() }
|
||||||
|
fun List<String>.dropBlank() = filter { it.isNotBlank() }
|
||||||
|
fun List<String>.dropEmpty() = filter { it.isNotEmpty() }
|
Loading…
x
Reference in New Issue
Block a user