add Masonry multisrc ()

* Masonry Multisrc

* fixes

* explicit `imageUrl`

Co-authored-by: beerpsi <92439990+beerpiss@users.noreply.github.com>

---------

Co-authored-by: beerpsi <92439990+beerpiss@users.noreply.github.com>
This commit is contained in:
AwkwardPeak7 2024-02-05 14:01:35 +05:00 committed by Draff
parent c023c40f54
commit aae435c058
38 changed files with 269 additions and 0 deletions
multisrc
overrides/masonry
elitebabes/res
mipmap-hdpi
mipmap-mdpi
mipmap-xhdpi
mipmap-xxhdpi
mipmap-xxxhdpi
femjoyhunter/res
mipmap-hdpi
mipmap-mdpi
mipmap-xhdpi
mipmap-xxhdpi
mipmap-xxxhdpi
ftvhunter/res
mipmap-hdpi
mipmap-mdpi
mipmap-xhdpi
mipmap-xxhdpi
mipmap-xxxhdpi
joymiihub/res
mipmap-hdpi
mipmap-mdpi
mipmap-xhdpi
mipmap-xxhdpi
mipmap-xxxhdpi
metarthunter/res
mipmap-hdpi
mipmap-mdpi
mipmap-xhdpi
mipmap-xxhdpi
mipmap-xxxhdpi
playmatehunter/res
mipmap-hdpi
mipmap-mdpi
mipmap-xhdpi
mipmap-xxhdpi
mipmap-xxxhdpi
xarthunter/res
mipmap-hdpi
mipmap-mdpi
mipmap-xhdpi
mipmap-xxhdpi
mipmap-xxxhdpi
src/main/java/eu/kanade/tachiyomi/multisrc/masonry

Binary file not shown.

After

(image error) Size: 3.6 KiB

Binary file not shown.

After

(image error) Size: 2.0 KiB

Binary file not shown.

After

(image error) Size: 4.5 KiB

Binary file not shown.

After

(image error) Size: 8.2 KiB

Binary file not shown.

After

(image error) Size: 11 KiB

Binary file not shown.

After

(image error) Size: 3.7 KiB

Binary file not shown.

After

(image error) Size: 1.8 KiB

Binary file not shown.

After

(image error) Size: 4.0 KiB

Binary file not shown.

After

(image error) Size: 7.4 KiB

Binary file not shown.

After

(image error) Size: 10 KiB

Binary file not shown.

After

(image error) Size: 3.9 KiB

Binary file not shown.

After

(image error) Size: 2.4 KiB

Binary file not shown.

After

(image error) Size: 5.1 KiB

Binary file not shown.

After

(image error) Size: 8.7 KiB

Binary file not shown.

After

(image error) Size: 12 KiB

Binary file not shown.

After

(image error) Size: 4.2 KiB

Binary file not shown.

After

(image error) Size: 2.7 KiB

Binary file not shown.

After

(image error) Size: 5.3 KiB

Binary file not shown.

After

(image error) Size: 10 KiB

Binary file not shown.

After

(image error) Size: 13 KiB

Binary file not shown.

After

(image error) Size: 4.0 KiB

Binary file not shown.

After

(image error) Size: 2.3 KiB

Binary file not shown.

After

(image error) Size: 5.4 KiB

Binary file not shown.

After

(image error) Size: 8.9 KiB

Binary file not shown.

After

(image error) Size: 12 KiB

Binary file not shown.

After

(image error) Size: 3.7 KiB

Binary file not shown.

After

(image error) Size: 2.3 KiB

Binary file not shown.

After

(image error) Size: 4.9 KiB

Binary file not shown.

After

(image error) Size: 7.8 KiB

Binary file not shown.

After

(image error) Size: 12 KiB

Binary file not shown.

After

(image error) Size: 4.1 KiB

Binary file not shown.

After

(image error) Size: 2.3 KiB

Binary file not shown.

After

(image error) Size: 5.0 KiB

Binary file not shown.

After

(image error) Size: 8.6 KiB

Binary file not shown.

After

(image error) Size: 12 KiB

@ -0,0 +1,199 @@
package eu.kanade.tachiyomi.multisrc.masonry
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.source.model.Filter
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.model.UpdateStrategy
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.Request
import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import rx.Observable
import java.lang.UnsupportedOperationException
abstract class Masonry(
override val name: String,
override val baseUrl: String,
override val lang: String,
) : ParsedHttpSource() {
override val supportsLatest = true
override val client = network.cloudflareClient
override fun headersBuilder() = super.headersBuilder()
.set("Referer", "$baseUrl/")
override fun popularMangaRequest(page: Int): Request {
val url = when (page) {
1 -> baseUrl
2 -> "$baseUrl/archive/"
else -> "$baseUrl/archive/page/${page - 1}/"
}
return GET(url, headers)
}
override fun popularMangaParse(response: Response): MangasPage {
getTags()
return super.popularMangaParse(response)
}
override fun popularMangaSelector() = ".list-gallery:not(.static) figure:not(:has(a[href*=/video/]))"
override fun popularMangaNextPageSelector() = ".pagination-a li.next"
override fun popularMangaFromElement(element: Element) = SManga.create().apply {
element.selectFirst("a")!!.also {
setUrlWithoutDomain(it.absUrl("href"))
title = it.attr("title")
}
thumbnail_url = element.selectFirst("img")?.imgAttr()
}
override fun latestUpdatesRequest(page: Int): Request {
return GET("$baseUrl/updates/sort/newest/mpage/$page/", headers)
}
override fun latestUpdatesParse(response: Response) = popularMangaParse(response)
override fun latestUpdatesSelector() = popularMangaSelector()
override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector()
override fun latestUpdatesFromElement(element: Element) = popularMangaFromElement(element)
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
return if (query.isNotEmpty()) {
val url = "$baseUrl/search/post/".toHttpUrl().newBuilder()
.addPathSegment(query.trim())
.addEncodedPathSegments("mpage/$page/")
.build()
GET(url, headers)
} else {
val tagFilter = filters.filterIsInstance<TagFilter>().firstOrNull()
val sortFilter = filters.filterIsInstance<SortFilter>().first()
val url = baseUrl.toHttpUrl().newBuilder().apply {
if (tagFilter == null || tagFilter.selected == "") {
addPathSegment("updates")
sortFilter.getUriPartIfNeeded("search").also {
if (it.isBlank()) {
addEncodedPathSegments("page/$page/")
} else {
addEncodedPathSegments(it)
addEncodedPathSegments("mpage/$page/")
}
}
} else {
addPathSegment("tag")
addPathSegment(tagFilter.selected)
sortFilter.getUriPartIfNeeded("tag").also {
if (it.isBlank()) {
addEncodedPathSegments("page/$page/")
} else {
addEncodedPathSegments(it)
addEncodedPathSegments("mpage/$page/")
}
}
}
}.build()
GET(url, headers)
}
}
private var tags = emptyList<Pair<String, String>>()
private var tagsFetchAttempt = 0
private fun getTags() {
if (tags.isEmpty() && tagsFetchAttempt < 3) {
runCatching {
tags = client.newCall(GET("$baseUrl/updates/sort/newest/", headers))
.execute().asJsoup()
.select("#filter-a span:has(> input)")
.mapNotNull {
Pair(
it.select("label").text(),
it.select("input").attr("value"),
)
}.let {
listOf(Pair("", "")) + it
}
}
tagsFetchAttempt++
}
}
override fun getFilterList(): FilterList {
val filters = mutableListOf(
Filter.Header("Filters ignored with text search"),
Filter.Separator(),
SortFilter(),
)
if (tags.isEmpty()) {
filters.add(
Filter.Header("Press 'reset' to attempt to load tags"),
)
} else {
filters.add(
TagFilter(tags),
)
}
return FilterList(filters)
}
override fun searchMangaParse(response: Response) = popularMangaParse(response)
override fun searchMangaSelector() = popularMangaSelector()
override fun searchMangaNextPageSelector() = popularMangaNextPageSelector()
override fun searchMangaFromElement(element: Element) = popularMangaFromElement(element)
override fun mangaDetailsParse(document: Document) = SManga.create().apply {
document.selectFirst("p.link-btn")?.run {
artist = select("a[href*=/model/]").eachText().joinToString()
genre = select("a[href*=/tag/]").eachText().joinToString()
author = selectFirst("a")?.text()
}
description = document.selectFirst("#content > p")?.text()
status = SManga.COMPLETED
update_strategy = UpdateStrategy.ONLY_FETCH_ONCE
}
override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> {
return Observable.just(
listOf(
SChapter.create().apply {
name = "Gallery"
url = manga.url
},
),
)
}
override fun chapterListSelector() = throw UnsupportedOperationException()
override fun chapterFromElement(element: Element) = throw UnsupportedOperationException()
override fun pageListParse(document: Document): List<Page> {
return document.select(".list-gallery a[href^=https://cdn.]").mapIndexed { idx, img ->
Page(idx, imageUrl = img.absUrl("href"))
}
}
override fun imageUrlParse(document: Document) = throw UnsupportedOperationException()
protected fun Element.imgAttr(): String? {
return when {
hasAttr("srcset") -> attr("abs:srcset").substringBefore(" ")
hasAttr("data-cfsrc") -> attr("abs:data-cfsrc")
hasAttr("data-src") -> attr("abs:data-src")
hasAttr("data-lazy-src") -> attr("abs:data-lazy-src")
else -> attr("abs:src")
}
}
}

@ -0,0 +1,40 @@
package eu.kanade.tachiyomi.multisrc.masonry
import eu.kanade.tachiyomi.source.model.Filter
abstract class SelectFilter(
name: String,
private val options: List<Pair<String, String>>,
) : Filter.Select<String>(
name,
options.map { it.first }.toTypedArray(),
) {
val selected get() = options[state].second
}
class SortFilter : SelectFilter("Sort by", sortFilterOptions) {
fun getUriPartIfNeeded(part: String) =
when (part) {
"search" -> {
when (state) {
2 -> ""
else -> selected
}
}
"tag" -> {
when (state) {
0 -> ""
else -> selected
}
}
else -> ""
}
}
private val sortFilterOptions = listOf(
Pair("Trending", "sort/trending"),
Pair("Newest", "sort/newest"),
Pair("Popular", "sort/popular"),
)
class TagFilter(options: List<Pair<String, String>>) : SelectFilter("Tags", options)

@ -0,0 +1,30 @@
package eu.kanade.tachiyomi.multisrc.masonry
import generator.ThemeSourceData.SingleLang
import generator.ThemeSourceGenerator
class MasonryGenerator : ThemeSourceGenerator {
override val themePkg = "masonry"
override val themeClass = "Masonry"
override val baseVersionCode = 1
override val sources = listOf(
SingleLang("Elite Babes", "https://www.elitebabes.com", "all", isNsfw = true),
SingleLang("Femjoy Hunter", "https://www.femjoyhunter.com", "all", isNsfw = true),
SingleLang("FTV Hunter", "https://www.ftvhunter.com", "all", isNsfw = true),
SingleLang("Joymii Hub", "https://www.joymiihub.com", "all", isNsfw = true),
SingleLang("Metart Hunter", "https://www.metarthunter.com", "all", isNsfw = true),
SingleLang("Playmate Hunter", "https://pmatehunter.com", "all", isNsfw = true),
SingleLang("XArt Hunter", "https://www.xarthunter.com", "all", isNsfw = true),
)
companion object {
@JvmStatic
fun main(args: Array<String>) {
MasonryGenerator().createAll()
}
}
}