Fix fetching video data and add new setting to filter by specific uploaders by ID (#462)

This commit is contained in:
Nathan 2025-01-03 02:12:54 -05:00 committed by GitHub
parent 7b2afcf2ad
commit 7fcde32166
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 102 additions and 20 deletions

View file

@ -1,7 +1,7 @@
ext { ext {
extName = 'Rule34Video' extName = 'Rule34Video'
extClass = '.Rule34Video' extClass = '.Rule34Video'
extVersionCode = 8 extVersionCode = 9
isNsfw = true isNsfw = true
} }

View file

@ -1,8 +1,10 @@
package eu.kanade.tachiyomi.animeextension.en.rule34video package eu.kanade.tachiyomi.animeextension.en.rule34video
import android.app.Application import android.app.Application
import android.util.Log
import androidx.preference.EditTextPreference
import androidx.preference.ListPreference import androidx.preference.ListPreference
import androidx.preference.PreferenceScreen import androidx.preference.PreferenceScreen
import androidx.preference.SwitchPreferenceCompat
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
import eu.kanade.tachiyomi.animesource.model.AnimeFilter import eu.kanade.tachiyomi.animesource.model.AnimeFilter
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
@ -41,7 +43,21 @@ class Rule34Video : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
} }
// ============================== Popular =============================== // ============================== Popular ===============================
override fun popularAnimeRequest(page: Int) = GET("$baseUrl/latest-updates/$page/") override fun popularAnimeRequest(page: Int): Request {
return if (preferences.getBoolean(PREF_UPLOADER_FILTER_ENABLED_KEY, false)) {
val uploaderId = preferences.getString(PREF_UPLOADER_ID_KEY, "") ?: ""
if (uploaderId.isNotBlank()) {
val url = "$baseUrl/members/$uploaderId/videos/?mode=async&function=get_block&block_id=list_videos_uploaded_videos&sort_by=&from_videos=$page"
Log.e("Rule34Video", "Loading popular videos from uploader ID: $uploaderId, page: $page, URL: $url")
GET(url)
} else {
Log.e("Rule34Video", "Uploader filter enabled but ID is blank, loading latest updates.")
GET("$baseUrl/latest-updates/$page/")
}
} else {
GET("$baseUrl/latest-updates/$page/")
}
}
override fun popularAnimeSelector() = "div.item.thumb" override fun popularAnimeSelector() = "div.item.thumb"
@ -102,21 +118,60 @@ class Rule34Video : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
// =========================== Anime Details ============================ // =========================== Anime Details ============================
override fun animeDetailsParse(document: Document) = SAnime.create().apply { override fun animeDetailsParse(document: Document) = SAnime.create().apply {
title = document.selectFirst("h1.title_video")!!.text() title = document.selectFirst("h1.title_video")?.text().toString()
val info = document.selectFirst("#tab_video_info")!!
author = info.select("div.label:contains(Artist:) + a").eachText().joinToString() val infoRow = document.selectFirst("div.info.row")
val detailRows = document.select("div.row")
val artistElement = detailRows.select("div.col:has(div.label:contains(Artist)) a.item span.name").firstOrNull()
author = artistElement?.text().orEmpty()
description = buildString { description = buildString {
info.selectFirst("div.label:contains(Description:) > em")?.text()?.also { append("$it\n") } detailRows.select("div.row:has(div.label > em) > div.label > em").html()
info.selectFirst("i.icon-eye + span")?.text()?.also { append("\nViews : ${it.replace(" ", ",")}") } .replace("<br>", "\n") // Ensure single <br> tags are followed by a newline
info.selectFirst("i.icon-clock + span")?.text()?.also { append("\nDuration : $it") } .let { text ->
document.select("div.label:contains(Download) ~ a.tag_item") append(text)
}
append("\n\n") // Add extra spacing
infoRow?.selectFirst("div.item_info:nth-child(1) > span")?.text()?.let {
append("Uploaded: $it\n")
}
val artist = detailRows.select("div.col:has(div.label:contains(Artist)) a.item span.name")
.eachText()
.joinToString()
if (artist.isNotEmpty()) {
append("Artists: $artist\n")
}
val categories = detailRows.select("div.col:has(div.label:contains(Categories)) a.item span")
.eachText()
.joinToString()
if (categories.isNotEmpty()) {
append("Categories: $categories\n")
}
val uploader = detailRows.select("div.col:has(div.label:contains(Uploaded by)) a.item").text()
if (uploader.isNotEmpty()) {
append("Uploader: $uploader\n")
}
infoRow?.select("div.item_info:nth-child(2) > span")?.text()?.let {
val views = it.substringBefore(" ").replace(",", "")
append("Views: $views\n")
}
infoRow?.select("div.item_info:nth-child(3) > span")?.text()?.let { append("Duration: $it\n") }
document.select("div.row:has(div.label:contains(Download)) a.tag_item")
.eachText() .eachText()
.joinToString { it.substringAfter(" ") } .joinToString { it.substringAfter(" ") }
.also { append("\nQuality : $it") } .also { append("Quality: $it") }
} }
genre = document.select("div.label:contains(Tags) ~ a.tag_item:not(:contains(Suggest))")
genre = document.select("div.row_spacer:has(div.label:contains(Tags)) a.tag_item:not(:contains(Suggest))")
.eachText() .eachText()
.joinToString() .joinToString()
status = SAnime.COMPLETED status = SAnime.COMPLETED
} }
@ -186,6 +241,24 @@ class Rule34Video : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
// ============================== Settings ============================== // ============================== Settings ==============================
override fun setupPreferenceScreen(screen: PreferenceScreen) { override fun setupPreferenceScreen(screen: PreferenceScreen) {
SwitchPreferenceCompat(screen.context).apply {
key = PREF_UPLOADER_FILTER_ENABLED_KEY
title = "Filter by Uploader"
summary = "Load videos only from the specified uploader ID."
setDefaultValue(false)
}.also(screen::addPreference)
EditTextPreference(screen.context).apply {
key = PREF_UPLOADER_ID_KEY
title = "Uploader ID"
summary = "Enter the ID of the uploader (e.g., 98965). Requires \"Filter by Uploader\" to be enabled."
dialogTitle = "Enter Uploader ID"
var dependency = PREF_UPLOADER_FILTER_ENABLED_KEY
setOnPreferenceChangeListener { _, newValue ->
newValue?.toString().isNullOrBlank().not()
}
}.also(screen::addPreference)
ListPreference(screen.context).apply { ListPreference(screen.context).apply {
key = PREF_QUALITY_KEY key = PREF_QUALITY_KEY
title = PREF_QUALITY_TITLE title = PREF_QUALITY_TITLE
@ -218,14 +291,20 @@ class Rule34Video : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
return tagList.toTypedArray() return tagList.toTypedArray()
} }
override fun getFilterList(): AnimeFilterList = AnimeFilterList( override fun getFilterList(): AnimeFilterList = if (preferences.getBoolean(PREF_UPLOADER_FILTER_ENABLED_KEY, false) &&
OrderFilter(), preferences.getString(PREF_UPLOADER_ID_KEY, "")?.isNotBlank() == true
CategoryBy(), ) {
AnimeFilter.Separator(), AnimeFilterList() // If uploader filter is enabled and ID is set, show no other filters
AnimeFilter.Header("Entered a \"tag\", click on \"filter\" then Click \"reset\" to load tags."), } else {
TagFilter(), AnimeFilterList(
TagSearch(tagsResults(tagDocument)), OrderFilter(),
) CategoryBy(),
AnimeFilter.Separator(),
AnimeFilter.Header("Entered a \"tag\", click on \"filter\" then Click \"reset\" to load tags."),
TagFilter(),
TagSearch(tagsResults(tagDocument)),
)
}
private class TagFilter : AnimeFilter.Text("Click \"reset\" without any text to load all A-Z tags.", "") private class TagFilter : AnimeFilter.Text("Click \"reset\" without any text to load all A-Z tags.", "")
@ -267,5 +346,8 @@ class Rule34Video : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
private const val PREF_QUALITY_TITLE = "Preferred quality" private const val PREF_QUALITY_TITLE = "Preferred quality"
private const val PREF_QUALITY_DEFAULT = "1080p" private const val PREF_QUALITY_DEFAULT = "1080p"
private val PREF_QUALITY_ENTRIES = arrayOf("2160p", "1080p", "720p", "480p", "360p") private val PREF_QUALITY_ENTRIES = arrayOf("2160p", "1080p", "720p", "480p", "360p")
private const val PREF_UPLOADER_FILTER_ENABLED_KEY = "uploader_filter_enabled"
private const val PREF_UPLOADER_ID_KEY = "uploader_id"
} }
} }