2022-08-19 02:51:58 +00:00
|
|
|
package com.jacekun
|
|
|
|
|
|
|
|
import com.fasterxml.jackson.annotation.JsonProperty
|
|
|
|
import com.lagradost.cloudstream3.*
|
|
|
|
import com.lagradost.cloudstream3.app
|
|
|
|
import com.lagradost.cloudstream3.mvvm.logError
|
|
|
|
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
|
|
|
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
|
|
|
import com.lagradost.cloudstream3.utils.loadExtractor
|
|
|
|
import org.jsoup.Jsoup
|
|
|
|
|
|
|
|
class JavFreeProvider : MainAPI() {
|
|
|
|
private val tvType = TvType.NSFW
|
|
|
|
override var name = "JavFree"
|
|
|
|
override var mainUrl = "https://javfree.sh"
|
|
|
|
override val supportedTypes: Set<TvType> get() = setOf(tvType)
|
|
|
|
override val hasDownloadSupport: Boolean get() = false
|
|
|
|
override val hasMainPage: Boolean get() = true
|
|
|
|
override val hasQuickSearch: Boolean get() = false
|
|
|
|
|
|
|
|
private data class ResponseJson(
|
|
|
|
@JsonProperty("list") val list: List<ResponseData>?
|
|
|
|
)
|
|
|
|
private data class ResponseData(
|
|
|
|
@JsonProperty("url") val file: String?,
|
|
|
|
@JsonProperty("server") val server: String?,
|
|
|
|
@JsonProperty("active") val active: Int?
|
|
|
|
)
|
|
|
|
|
2022-08-21 23:52:43 +00:00
|
|
|
private fun String.cleanText() : String = this.trim().removePrefix("Watch JAV Free")
|
2022-08-20 23:17:35 +00:00
|
|
|
.removeSuffix("HD Free Online on JAVFree.SH").trim()
|
|
|
|
.removePrefix("Watch JAV").trim()
|
2022-08-19 02:51:58 +00:00
|
|
|
|
|
|
|
override suspend fun getMainPage(
|
|
|
|
page: Int,
|
|
|
|
request: MainPageRequest
|
|
|
|
): HomePageResponse {
|
|
|
|
val html = app.get(mainUrl).text
|
|
|
|
val document = Jsoup.parse(html)
|
|
|
|
val all = ArrayList<HomePageList>()
|
|
|
|
|
2022-08-21 23:52:43 +00:00
|
|
|
document.getElementsByTag("body").select("div#page")
|
2022-08-19 02:51:58 +00:00
|
|
|
.select("div#content").select("div#primary")
|
|
|
|
.select("main")
|
2022-08-21 23:52:43 +00:00
|
|
|
.select("section").forEach { it2 ->
|
2022-08-19 02:51:58 +00:00
|
|
|
// Fetch row title
|
|
|
|
val title = it2?.select("h2.widget-title")?.text() ?: "Unnamed Row"
|
|
|
|
// Fetch list of items and map
|
2022-08-21 23:52:43 +00:00
|
|
|
it2.select("div.videos-list").select("article")
|
|
|
|
.let { inner ->
|
2022-08-19 02:51:58 +00:00
|
|
|
|
2022-08-21 23:52:43 +00:00
|
|
|
val elements: List<SearchResponse> = inner.mapNotNull {
|
2022-08-19 02:51:58 +00:00
|
|
|
|
|
|
|
val aa = it.select("a").firstOrNull()
|
2022-08-21 23:52:43 +00:00
|
|
|
val link = fixUrlNull(aa?.attr("href")) ?: return@mapNotNull null
|
2022-08-19 02:51:58 +00:00
|
|
|
val name = aa?.attr("title") ?: "<No Title>"
|
|
|
|
|
2022-08-21 23:52:43 +00:00
|
|
|
var image = aa?.select("div")?.select("img")?.attr("data-src")
|
|
|
|
if (image.isNullOrBlank()) {
|
|
|
|
image = aa?.select("div")?.select("video")?.attr("poster")
|
2022-08-19 02:51:58 +00:00
|
|
|
}
|
|
|
|
val year = null
|
|
|
|
|
|
|
|
MovieSearchResponse(
|
|
|
|
name = name,
|
|
|
|
url = link,
|
|
|
|
apiName = this.name,
|
|
|
|
type = tvType,
|
|
|
|
posterUrl = image,
|
|
|
|
year = year
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
all.add(
|
|
|
|
HomePageList(
|
|
|
|
name = title,
|
|
|
|
list = elements,
|
|
|
|
isHorizontalImages = true
|
|
|
|
)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return HomePageResponse(all)
|
|
|
|
}
|
|
|
|
|
|
|
|
override suspend fun search(query: String): List<SearchResponse> {
|
2022-08-21 23:52:43 +00:00
|
|
|
val searchUrl = "$mainUrl/search/movie/${query}"
|
|
|
|
val document = app.get(searchUrl).document
|
|
|
|
.select("div.videos-list").select("article[id^=post]")
|
2022-08-19 02:51:58 +00:00
|
|
|
|
2022-08-21 23:52:43 +00:00
|
|
|
return document.mapNotNull {
|
|
|
|
val aa = it?.select("a") ?: return@mapNotNull null
|
|
|
|
val url = fixUrlNull(aa.attr("href")) ?: return@mapNotNull null
|
2022-08-19 02:51:58 +00:00
|
|
|
val title = aa.attr("title")
|
|
|
|
val year = null
|
2022-08-21 23:52:43 +00:00
|
|
|
var image = aa.select("div.post-thumbnail.thumbs-rotation")
|
2022-08-19 02:51:58 +00:00
|
|
|
.select("img").attr("data-src")
|
2022-08-21 23:52:43 +00:00
|
|
|
if (image.isNullOrBlank()) {
|
|
|
|
image = aa.select("div").select("video").attr("poster").toString()
|
|
|
|
}
|
2022-08-19 02:51:58 +00:00
|
|
|
|
|
|
|
MovieSearchResponse(
|
|
|
|
name = title,
|
2022-08-21 23:52:43 +00:00
|
|
|
url = url,
|
2022-08-19 02:51:58 +00:00
|
|
|
apiName = this.name,
|
|
|
|
type = tvType,
|
|
|
|
posterUrl = image,
|
|
|
|
year = year
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
override suspend fun load(url: String): LoadResponse {
|
|
|
|
val doc = app.get(url).document
|
|
|
|
//Log.i(this.name, "Result => (url) ${url}")
|
|
|
|
val poster = doc.select("meta[property=og:image]").firstOrNull()?.attr("content")
|
|
|
|
val title = doc.select("meta[name=title]").firstOrNull()?.attr("content")?.toString()?.cleanText() ?: ""
|
|
|
|
val descript = doc.select("meta[name=description]").firstOrNull()?.attr("content")?.cleanText()
|
|
|
|
|
|
|
|
val body = doc.getElementsByTag("body")
|
|
|
|
val yearElem = body
|
|
|
|
.select("div#page > div#content > div#primary > main > article")
|
|
|
|
.select("div.entry-content > div.tab-content > div#video-about > div#video-date")
|
|
|
|
//Log.i(this.name, "Result => (yearElem) ${yearElem}")
|
|
|
|
val year = yearElem.text().trim().takeLast(4).toIntOrNull()
|
|
|
|
|
|
|
|
var streamUrl = body
|
|
|
|
.select("div#page > div#content > div#primary > main > article > header > div > div > div > script")
|
|
|
|
.toString()
|
|
|
|
if (streamUrl.isNotEmpty()) {
|
|
|
|
val startS = "<iframe src="
|
|
|
|
streamUrl = streamUrl.substring(streamUrl.indexOf(startS) + startS.length + 1)
|
|
|
|
//Log.i(this.name, "Result => (id) ${id}")
|
|
|
|
streamUrl = streamUrl.substring(0, streamUrl.indexOf("\""))
|
|
|
|
}
|
|
|
|
//Log.i(this.name, "Result => (id) ${id}")
|
|
|
|
return MovieLoadResponse(
|
|
|
|
name = title,
|
|
|
|
url = url,
|
|
|
|
apiName = this.name,
|
|
|
|
type = tvType,
|
|
|
|
dataUrl = streamUrl,
|
|
|
|
posterUrl = poster,
|
|
|
|
year = year,
|
|
|
|
plot = descript
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
override suspend fun loadLinks(
|
|
|
|
data: String,
|
|
|
|
isCasting: Boolean,
|
|
|
|
subtitleCallback: (SubtitleFile) -> Unit,
|
|
|
|
callback: (ExtractorLink) -> Unit
|
|
|
|
): Boolean {
|
|
|
|
|
|
|
|
try {
|
|
|
|
// GET request to: https://player.javfree.sh/stream/687234424271726c
|
|
|
|
val id = data.substring(data.indexOf("#")).substring(1)
|
|
|
|
val linkToGet = "https://player.javfree.sh/stream/$id"
|
|
|
|
val jsonres = app.get(linkToGet, referer = mainUrl).text
|
|
|
|
val referer = "https://player.javfree.sh/embed.html"
|
|
|
|
//Log.i(this.name, "Result => (jsonres) ${jsonres}")
|
|
|
|
tryParseJson<ResponseJson?>(jsonres)?.let { item ->
|
|
|
|
item.list?.forEach { link ->
|
|
|
|
val linkUrl = link.file ?: ""
|
|
|
|
if (linkUrl.isNotBlank()) {
|
|
|
|
//Log.i(this.name, "ApiError => (link url) $linkUrl")
|
|
|
|
loadExtractor(
|
|
|
|
url= linkUrl,
|
|
|
|
referer = referer,
|
|
|
|
subtitleCallback = subtitleCallback,
|
|
|
|
callback = callback
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
} catch (e: Exception) {
|
2022-08-21 23:52:43 +00:00
|
|
|
//e.printStackTrace()
|
2022-08-19 02:51:58 +00:00
|
|
|
logError(e)
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|