Skip to content
This repository was archived by the owner on Jan 12, 2024. It is now read-only.

Commit c811627

Browse files
authored
new source xvideos
2 parents 30eecf6 + 327fb45 commit c811627

File tree

8 files changed

+198
-0
lines changed

8 files changed

+198
-0
lines changed

src/all/xvideos/AndroidManifest.xml

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<manifest package="eu.kanade.tachiyomi.animeextension" />

src/all/xvideos/build.gradle

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
apply plugin: 'com.android.application'
2+
apply plugin: 'kotlin-android'
3+
4+
ext {
5+
extName = 'Xvideos'
6+
pkgNameSuffix = 'all.xvideos'
7+
extClass = '.Xvideos'
8+
extVersionCode = 1
9+
libVersion = '12'
10+
containsNsfw = true
11+
}
12+
13+
apply from: "$rootDir/common.gradle"
6.27 KB
Loading
6.27 KB
Loading
6.27 KB
Loading
Loading
Loading
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
package eu.kanade.tachiyomi.animeextension.all.xvideos
2+
3+
import android.app.Application
4+
import android.content.SharedPreferences
5+
import androidx.preference.ListPreference
6+
import androidx.preference.PreferenceScreen
7+
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
8+
import eu.kanade.tachiyomi.animesource.model.AnimeFilter
9+
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
10+
import eu.kanade.tachiyomi.animesource.model.SAnime
11+
import eu.kanade.tachiyomi.animesource.model.SEpisode
12+
import eu.kanade.tachiyomi.animesource.model.Video
13+
import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource
14+
import eu.kanade.tachiyomi.network.GET
15+
import eu.kanade.tachiyomi.util.asJsoup
16+
import okhttp3.OkHttpClient
17+
import okhttp3.Request
18+
import okhttp3.Response
19+
import org.jsoup.nodes.Document
20+
import org.jsoup.nodes.Element
21+
import uy.kohesive.injekt.Injekt
22+
import uy.kohesive.injekt.api.get
23+
import java.lang.Exception
24+
25+
class Xvideos : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
26+
27+
override val name = "Xvideos"
28+
29+
override val baseUrl = "https://www.xvideos.com"
30+
31+
override val lang = "all"
32+
33+
override val supportsLatest = false
34+
35+
override val client: OkHttpClient = network.cloudflareClient
36+
37+
private val preferences: SharedPreferences by lazy {
38+
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
39+
}
40+
41+
override fun popularAnimeSelector(): String = "div#main div#content div.mozaique.cust-nb-cols > div"
42+
43+
override fun popularAnimeRequest(page: Int): Request = GET("https://www.xvideos.com/new/$page")
44+
45+
override fun popularAnimeFromElement(element: Element): SAnime {
46+
val anime = SAnime.create()
47+
anime.setUrlWithoutDomain(
48+
"$baseUrl${element.select("div.thumb-inside div.thumb a").attr("href")}"
49+
)
50+
anime.title = element.select("div.thumb-under p.title").text()
51+
anime.thumbnail_url = element.select("div.thumb-inside div.thumb a img").attr("data-src")
52+
return anime
53+
}
54+
55+
override fun popularAnimeNextPageSelector(): String = "a.no-page.next-page"
56+
57+
override fun episodeListParse(response: Response): List<SEpisode> {
58+
val episodes = mutableListOf<SEpisode>()
59+
val episode = SEpisode.create().apply {
60+
name = "Video"
61+
url = response.request.url.toString().replace("https://www.xvideos.com", "")
62+
date_upload = System.currentTimeMillis()
63+
}
64+
episodes.add(episode)
65+
66+
return episodes
67+
}
68+
69+
override fun episodeListSelector() = throw Exception("not used")
70+
71+
override fun episodeFromElement(element: Element) = throw Exception("not used")
72+
73+
override fun videoListParse(response: Response): List<Video> {
74+
val document = response.asJsoup()
75+
val sourcesJson = document.select("script:containsData(html5player.setVideoUrl)").toString()
76+
val lowQuality = sourcesJson.substringAfter("VideoUrlLow('").substringBefore("')")
77+
val hlsQuality = sourcesJson.substringAfter("setVideoHLS('").substringBefore("')")
78+
val highQuality = sourcesJson.substringAfter("VideoUrlHigh('").substringBefore("')")
79+
return listOf(
80+
Video(lowQuality, "Low", lowQuality, null),
81+
Video(hlsQuality, "HLS", hlsQuality, null),
82+
Video(highQuality, "High", highQuality, null)
83+
)
84+
}
85+
86+
override fun videoListSelector() = throw Exception("not used")
87+
88+
override fun videoUrlParse(document: Document) = throw Exception("not used")
89+
90+
override fun videoFromElement(element: Element) = throw Exception("not used")
91+
92+
override fun List<Video>.sort(): List<Video> {
93+
val quality = preferences.getString("preferred_quality", "High")
94+
if (quality != null) {
95+
val newList = mutableListOf<Video>()
96+
var preferred = 0
97+
for (video in this) {
98+
if (video.quality == quality) {
99+
newList.add(preferred, video)
100+
preferred++
101+
} else {
102+
newList.add(video)
103+
}
104+
}
105+
return newList
106+
}
107+
return this
108+
}
109+
110+
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
111+
112+
return when {
113+
query.isNotBlank() -> GET("$baseUrl/?k=$query&p=$page", headers)
114+
else -> GET("$baseUrl/tags/${getSearchParameters(filters)}/$page ")
115+
}
116+
}
117+
override fun searchAnimeFromElement(element: Element): SAnime {
118+
return popularAnimeFromElement(element)
119+
}
120+
121+
override fun searchAnimeNextPageSelector(): String = popularAnimeNextPageSelector()
122+
123+
override fun searchAnimeSelector(): String = popularAnimeSelector()
124+
125+
override fun animeDetailsParse(document: Document): SAnime {
126+
val anime = SAnime.create()
127+
anime.title = document.select("h2.page-title").text()
128+
anime.description = ""
129+
anime.genre = document.select("div.video-metadata ul li a span").joinToString { it.text() }
130+
anime.status = SAnime.COMPLETED
131+
return anime
132+
}
133+
134+
override fun latestUpdatesNextPageSelector() = throw Exception("not used")
135+
136+
override fun latestUpdatesFromElement(element: Element) = throw Exception("not used")
137+
138+
override fun latestUpdatesRequest(page: Int) = throw Exception("not used")
139+
140+
override fun latestUpdatesSelector() = throw Exception("not used")
141+
142+
override fun getFilterList(): AnimeFilterList = AnimeFilterList(
143+
AnimeFilter.Header("Search by text does not affect the filter"),
144+
Tags("", "Tag")
145+
)
146+
147+
private fun getSearchParameters(filters: AnimeFilterList): String {
148+
var finalstring = ""
149+
var tags = ""
150+
151+
filters.forEach { filter ->
152+
when (filter) {
153+
is Tags -> {
154+
tags = filter.state.ifEmpty { "" }
155+
}
156+
else -> {}
157+
}
158+
finalstring += tags
159+
}
160+
return finalstring
161+
}
162+
163+
internal class Tags(val input: String, name: String) : AnimeFilter.Text(name)
164+
165+
override fun setupPreferenceScreen(screen: PreferenceScreen) {
166+
val videoQualityPref = ListPreference(screen.context).apply {
167+
key = "preferred_quality"
168+
title = "Preferred quality"
169+
entries = arrayOf("High", "Low", "HLS")
170+
entryValues = arrayOf("High", "Low", "HLS")
171+
setDefaultValue("HLS")
172+
summary = "%s"
173+
174+
setOnPreferenceChangeListener { _, newValue ->
175+
val selected = newValue as String
176+
val index = findIndexOfValue(selected)
177+
val entry = entryValues[index] as String
178+
preferences.edit().putString(key, entry).commit()
179+
}
180+
}
181+
screen.addPreference(videoQualityPref)
182+
}
183+
}

0 commit comments

Comments
 (0)