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

Commit 1555f1b

Browse files
Update extension [Pornhub] (#20)
* add PH CDN extractor * update extractor * update code * update gradle version * update version * fix preference screen * fix version
1 parent aa00bfb commit 1555f1b

File tree

4 files changed

+66
-46
lines changed

4 files changed

+66
-46
lines changed

Diff for: gradle/wrapper/gradle-wrapper.properties

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1+
#Mon Jul 31 23:55:52 NPT 2023
12
distributionBase=GRADLE_USER_HOME
23
distributionPath=wrapper/dists
3-
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-bin.zip
4+
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
45
zipStoreBase=GRADLE_USER_HOME
56
zipStorePath=wrapper/dists

Diff for: src/all/pornhub/build.gradle

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ ext {
66
extName = 'Pornhub'
77
pkgNameSuffix = 'all.pornhub'
88
extClass = '.Pornhub'
9-
extVersionCode = 5
9+
extVersionCode = 6
1010
libVersion = '13'
1111
containsNsfw = true
1212
}

Diff for: src/all/pornhub/src/eu/kanade/tachiyomi/animeextension/all/pornhub/Pornhub.kt

+4-44
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import android.text.SpannableString
88
import android.text.Spanned
99
import androidx.preference.ListPreference
1010
import androidx.preference.PreferenceScreen
11+
import eu.kanade.tachiyomi.animeextension.all.pornhub.extractors.PhCdnExtractor
1112
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
1213
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
1314
import eu.kanade.tachiyomi.animesource.model.SAnime
@@ -92,21 +93,7 @@ class Pornhub : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
9293
@OptIn(ExperimentalSerializationApi::class)
9394
override fun videoListParse(response: Response): List<Video> {
9495
val url = response.request.url.toString()
95-
val videoList = mutableListOf<Video>()
96-
// credits to: https://github.com/Joel2B
97-
val document = client.newCall(GET("https://appsdev.cyou/xv-ph-rt/api/?data=$url")).execute().asJsoup().body().text()
98-
val jsonResponse = json.decodeFromString<PornApiResponse>(document)
99-
100-
return listOf(
101-
Video(jsonResponse.hls!!.all!!, "HLS: ALL", jsonResponse.hls!!.all),
102-
Video(jsonResponse.hls!!.low!!, "HLS: LOW", jsonResponse.hls!!.low),
103-
Video(jsonResponse.hls!!.hd!!, "HLS: HD", jsonResponse.hls!!.hd),
104-
Video(jsonResponse.hls!!.fhd!!, "HLS: FHD", jsonResponse.hls!!.fhd),
105-
Video(jsonResponse.mp4!!.low!!, "MP4: LOW", jsonResponse.mp4!!.low),
106-
Video(jsonResponse.mp4!!.sd!!, "MP4: SD", jsonResponse.mp4!!.sd),
107-
Video(jsonResponse.mp4!!.hd!!, "MP4: HD", jsonResponse.mp4!!.hd),
108-
Video(jsonResponse.mp4!!.fhd!!, "MP4: FHD", jsonResponse.mp4!!.fhd)
109-
).filter { it.url.isNotBlank() }
96+
return PhCdnExtractor(client).videoFromUrl(url)
11097
}
11198

11299
override fun videoListSelector() = throw Exception("not used")
@@ -116,7 +103,7 @@ class Pornhub : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
116103
override fun videoFromElement(element: Element) = throw Exception("not used")
117104

118105
override fun List<Video>.sort(): List<Video> {
119-
val quality = preferences.getString("preferred_quality", "720p")
106+
val quality = preferences.getString("preferred_quality", "480p")
120107
if (quality != null) {
121108
val newList = mutableListOf<Video>()
122109
var preferred = 0
@@ -176,7 +163,7 @@ class Pornhub : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
176163
title = "Preferred quality"
177164
entries = arrayOf("1080p", "720p", "480p", "240p")
178165
entryValues = arrayOf("1080p", "720p", "480p", "240p")
179-
setDefaultValue("1080p")
166+
setDefaultValue("480p")
180167
summary = "%s"
181168

182169
setOnPreferenceChangeListener { _, newValue ->
@@ -189,33 +176,6 @@ class Pornhub : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
189176
screen.addPreference(videoQualityPref)
190177
}
191178

192-
@Serializable
193-
data class PornApiResponse(
194-
var hls: Hls? = Hls(),
195-
var mp4: Mp4? = Mp4(),
196-
var thumb: String? = null,
197-
var thumbnails: String? = null
198-
199-
)
200-
201-
@Serializable
202-
data class Hls(
203-
var all: String? = "",
204-
@SerialName("1080p") var fhd: String? = "",
205-
@SerialName("720p") var hd: String? = "",
206-
@SerialName("480p") var sd: String? = "",
207-
@SerialName("240p") var low: String? = ""
208-
209-
)
210-
211-
@Serializable
212-
data class Mp4(
213-
@SerialName("1080p") var fhd: String? = "",
214-
@SerialName("720p") var hd: String? = "",
215-
@SerialName("480p") var sd: String? = "",
216-
@SerialName("240p") var low: String? = ""
217-
)
218-
219179
@Serializable
220180
data class VideoDetail(
221181
@SerialName("@context") var context: String? = null,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package eu.kanade.tachiyomi.animeextension.all.pornhub.extractors
2+
3+
import eu.kanade.tachiyomi.animesource.model.Video
4+
import eu.kanade.tachiyomi.network.GET
5+
import eu.kanade.tachiyomi.util.asJsoup
6+
import okhttp3.OkHttpClient
7+
8+
class PhCdnExtractor(private val client: OkHttpClient) {
9+
fun videoFromUrl(videoUrl: String): MutableList<Video> {
10+
val pattern = Regex("(?<=viewkey=)[^&]+")
11+
val key = pattern.find(videoUrl)?.value
12+
val document = client.newCall(GET("https://www.pornhub.com/embed/$key")).execute().asJsoup()
13+
val scriptPart = document.select("body > script:nth-child(7)").html()
14+
// contains the stream url broken into multiple random variables and comments
15+
var vars = scriptPart.subSequence(
16+
scriptPart.indexOf("var ra"),
17+
scriptPart.indexOf(";flashvars.mediaDefinitions.hls") + 1
18+
).toString().split(";").toMutableList()
19+
vars = vars.map {
20+
it.replace("var ", "")
21+
}.toMutableList()
22+
23+
var hls = String()
24+
var quality = String()
25+
// create a map of variable to value
26+
val data = mutableMapOf<String, String>()
27+
for (v in vars) {
28+
if (v.isEmpty()) {
29+
continue
30+
}
31+
val index = v.indexOf("=")
32+
if (v.startsWith("hls")) {
33+
val tmp = removeComment(v)
34+
quality = tmp.replace("hls", "").split("=")[0]
35+
hls = tmp.subSequence(index + 1, tmp.length).toString()
36+
} else {
37+
val x = v.subSequence(0, index).toString()
38+
val y = v.subSequence(index + 1, v.length).toString().replace("\"", "").replace(" + ", "")
39+
data.put(x, y)
40+
}
41+
}
42+
// replace the variables in hls from the map created above
43+
var finalHls = String()
44+
for (part in hls.split(" + ")) {
45+
finalHls += data.get(part)
46+
}
47+
val streamFile = client.newCall(GET(finalHls)).execute().body!!.string().split("\n").filter {
48+
it.contains("index")
49+
}[0]
50+
val streamUrl = finalHls.subSequence(0, finalHls.indexOf("master")).toString() + streamFile
51+
val videoList = mutableListOf<Video>()
52+
videoList.add(Video(streamUrl, quality + 'p', streamUrl))
53+
return videoList
54+
}
55+
56+
private fun removeComment(v: String): String {
57+
return v.replace(Regex("""(\/\/[^\n]*|\/\*(.|[\r\n])*?\*\/)"""), "")
58+
}
59+
}

0 commit comments

Comments
 (0)