mirror of
https://github.com/recloudstream/cloudstream-extensions.git
synced 2024-08-15 03:03:54 +00:00
updated nginx provider
This commit is contained in:
parent
c8f6c84de1
commit
9617444dcc
3 changed files with 337 additions and 197 deletions
|
@ -5,7 +5,7 @@ dependencies {
|
||||||
}
|
}
|
||||||
|
|
||||||
// use an integer for version numbers
|
// use an integer for version numbers
|
||||||
version = 7
|
version = 8
|
||||||
|
|
||||||
|
|
||||||
cloudstream {
|
cloudstream {
|
||||||
|
|
|
@ -52,7 +52,7 @@
|
||||||
NginxProvider.loginCredentials = null
|
NginxProvider.loginCredentials = null
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
NginxProvider.overrideUrl = data.server?.removeSuffix("/")
|
NginxProvider.overrideUrl = data.server?.removeSuffix("/") + "/"
|
||||||
NginxProvider.loginCredentials = "${data.username ?: ""}:${data.password ?: ""}"
|
NginxProvider.loginCredentials = "${data.username ?: ""}:${data.password ?: ""}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,46 @@
|
||||||
package com.lagradost
|
package com.lagradost
|
||||||
|
|
||||||
|
|
||||||
|
import com.lagradost.cloudstream3.TvType
|
||||||
|
import com.lagradost.cloudstream3.MainAPI
|
||||||
|
import com.lagradost.cloudstream3.SearchResponse
|
||||||
|
|
||||||
import com.lagradost.cloudstream3.*
|
import com.lagradost.cloudstream3.*
|
||||||
|
import com.lagradost.cloudstream3.LoadResponse.Companion.addActors
|
||||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
|
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
|
||||||
|
import com.lagradost.cloudstream3.mvvm.logError
|
||||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
import com.lagradost.cloudstream3.utils.Qualities
|
import com.lagradost.cloudstream3.utils.Qualities
|
||||||
|
import com.lagradost.cloudstream3.utils.SubtitleHelper
|
||||||
|
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||||
|
|
||||||
class NginxProvider : MainAPI() {
|
class NginxProvider : MainAPI() {
|
||||||
override var name = "Nginx"
|
override var name = "Nginx"
|
||||||
override val hasQuickSearch = false
|
// override var lang = "en" //no specific language
|
||||||
override val hasMainPage = true
|
override val hasMainPage = true
|
||||||
|
override val hasQuickSearch = false
|
||||||
override val supportedTypes = setOf(TvType.AnimeMovie, TvType.TvSeries, TvType.Movie)
|
override val supportedTypes = setOf(TvType.AnimeMovie, TvType.TvSeries, TvType.Movie)
|
||||||
|
// override val hasSearch = false
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
var companionName = "Nginx"
|
||||||
var loginCredentials: String? = null
|
var loginCredentials: String? = null
|
||||||
var overrideUrl: String? = null
|
var overrideUrl: String? = null
|
||||||
|
var pathToLibrary: String? = null // the library displayed when getting overrideUrl /home/username/media/
|
||||||
const val ERROR_STRING = "No nginx url specified in the settings"
|
const val ERROR_STRING = "No nginx url specified in the settings"
|
||||||
|
|
||||||
|
fun getDirectMediaLink(path: String): String? {
|
||||||
|
val storedPathToLibrary = pathToLibrary
|
||||||
|
val storedOverrideUrl = overrideUrl // may be null if change value later
|
||||||
|
if (storedPathToLibrary == null || storedOverrideUrl == null) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return path.replace(storedPathToLibrary, storedOverrideUrl)
|
||||||
|
// /home/username/media/Movies/The Northman (2022)/The.Northman.2022.MULTi.1080p.AMZN.WEBRip.DDP5.1.Atmos.x264-VROOMM.mkv
|
||||||
|
// becomes:
|
||||||
|
// https://website.hosting.com/Movies/The Northman (2022)/The.Northman.2022.MULTi.1080p.AMZN.WEBRip.DDP5.1.Atmos.x264-VROOMM.mkv
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getAuthHeader(): Map<String, String> {
|
private fun getAuthHeader(): Map<String, String> {
|
||||||
|
@ -31,252 +57,365 @@ class NginxProvider : MainAPI() {
|
||||||
}
|
}
|
||||||
|
|
||||||
val basicAuthToken =
|
val basicAuthToken =
|
||||||
base64Encode(localCredentials.toByteArray()) // will this be loaded when not using the provider ??? can increase load
|
base64Encode(localCredentials.toByteArray())
|
||||||
|
|
||||||
return mapOf("Authorization" to "Basic $basicAuthToken")
|
return mapOf("Authorization" to "Basic $basicAuthToken")
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun load(url: String): LoadResponse {
|
|
||||||
val authHeader =
|
|
||||||
getAuthHeader() // call again because it isn't reloaded if in main class and storedCredentials loads after
|
|
||||||
// url can be tvshow.nfo for series or mediaRootUrl for movies
|
|
||||||
|
|
||||||
val mainRootDocument = app.get(url, authHeader).document
|
override suspend fun load(url: String): LoadResponse? {
|
||||||
|
|
||||||
val nfoUrl = url + mainRootDocument.getElementsByAttributeValueContaining("href", ".nfo")
|
val authHeader = getAuthHeader() // reload
|
||||||
.attr("href") // metadata url file
|
|
||||||
|
|
||||||
val metadataDocument = app.get(nfoUrl, authHeader).document // get the metadata nfo file
|
val isValid = url.contains(".nfo")
|
||||||
|
val isSerie = url.contains("tvshow.nfo")
|
||||||
|
|
||||||
val isMovie = !nfoUrl.contains("tvshow.nfo")
|
val metadataDocument = app.get(url, authHeader).document // get the metadata nfo file
|
||||||
|
|
||||||
val title = metadataDocument.selectFirst("title")!!.text()
|
val title = metadataDocument.selectFirst("title")?.text()?.replace("/", "") ?: url.substringBeforeLast("/").substringAfterLast("/")
|
||||||
|
// gets the content between slashes: https://g.com/nameOfShow/tvshow.nfo
|
||||||
|
|
||||||
val description = metadataDocument.selectFirst("plot")!!.text()
|
val description = metadataDocument.selectFirst("plot")?.text()
|
||||||
|
|
||||||
if (isMovie) {
|
val mediaRootUrl = url.substringBeforeLast("/") + "/"
|
||||||
val poster = metadataDocument.selectFirst("thumb")!!.text()
|
val mediaRootDocument = app.get(mediaRootUrl, authHeader).document
|
||||||
val trailer = metadataDocument.select("trailer").mapNotNull {
|
|
||||||
it?.text()?.replace(
|
if (!isValid) {
|
||||||
"plugin://plugin.video.youtube/play/?video_id=",
|
if (".mp4" in url || ".mkv" in url) {
|
||||||
"https://www.youtube.com/watch?v="
|
val fixedUrl = fixUrl(url)
|
||||||
|
return newMovieLoadResponse(
|
||||||
|
title,
|
||||||
|
fixedUrl,
|
||||||
|
TvType.Movie,
|
||||||
|
fixedUrl,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
val partialUrl =
|
return null
|
||||||
mainRootDocument.getElementsByAttributeValueContaining("href", ".nfo").attr("href")
|
|
||||||
.replace(".nfo", ".")
|
|
||||||
val date = metadataDocument.selectFirst("year")?.text()?.toIntOrNull()
|
|
||||||
val ratingAverage = metadataDocument.selectFirst("value")?.text()?.toIntOrNull()
|
|
||||||
val tagsList = metadataDocument.select("genre")
|
|
||||||
.mapNotNull { // all the tags like action, thriller ...
|
|
||||||
it?.text()
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
val dataList =
|
|
||||||
mainRootDocument.getElementsByAttributeValueContaining( // list of all urls of the webpage
|
|
||||||
"href",
|
|
||||||
partialUrl
|
|
||||||
)
|
|
||||||
|
|
||||||
val data = url + dataList.firstNotNullOf { item ->
|
|
||||||
item.takeIf {
|
|
||||||
(!it.attr("href").contains(".nfo") && !it.attr("href").contains(".jpg"))
|
|
||||||
}
|
|
||||||
}.attr("href").toString() // exclude poster and nfo (metadata) file
|
|
||||||
|
|
||||||
return newMovieLoadResponse(
|
|
||||||
title,
|
|
||||||
url,
|
|
||||||
TvType.Movie,
|
|
||||||
data
|
|
||||||
) {
|
|
||||||
this.year = date
|
|
||||||
this.plot = description
|
|
||||||
this.rating = ratingAverage
|
|
||||||
this.tags = tagsList
|
|
||||||
addTrailer(trailer)
|
|
||||||
addPoster(poster, authHeader)
|
|
||||||
}
|
|
||||||
} else // a tv serie
|
|
||||||
{
|
|
||||||
val list = ArrayList<Pair<Int, String>>()
|
|
||||||
val mediaRootUrl = url.replace("tvshow.nfo", "")
|
|
||||||
val posterUrl = mediaRootUrl + "poster.jpg"
|
|
||||||
val mediaRootDocument = app.get(mediaRootUrl, authHeader).document
|
|
||||||
val seasons =
|
|
||||||
mediaRootDocument.getElementsByAttributeValueContaining("href", "Season%20")
|
|
||||||
|
|
||||||
|
|
||||||
val tagsList = metadataDocument.select("genre")
|
|
||||||
.mapNotNull { // all the tags like action, thriller ...; unused variable
|
|
||||||
it?.text()
|
|
||||||
}
|
|
||||||
|
|
||||||
//val actorsList = document.select("actor")
|
|
||||||
// ?.mapNotNull { // all the tags like action, thriller ...; unused variable
|
|
||||||
// it?.text()
|
|
||||||
// }
|
|
||||||
|
|
||||||
seasons.forEach { element ->
|
|
||||||
val season =
|
|
||||||
element.attr("href").replace("Season%20", "").replace("/", "").toIntOrNull()
|
|
||||||
val href = mediaRootUrl + element.attr("href")
|
|
||||||
if (season != null && season > 0 && href.isNotBlank()) {
|
|
||||||
list.add(Pair(season, href))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (list.isEmpty()) throw ErrorLoadingException("No Seasons Found")
|
|
||||||
|
|
||||||
val episodeList = ArrayList<Episode>()
|
|
||||||
|
|
||||||
|
|
||||||
list.apmap { (seasonInt, seasonString) ->
|
|
||||||
val seasonDocument = app.get(seasonString, authHeader).document
|
|
||||||
val episodes = seasonDocument.getElementsByAttributeValueContaining(
|
|
||||||
"href",
|
|
||||||
".nfo"
|
|
||||||
) // get metadata
|
|
||||||
episodes.forEach { episode ->
|
|
||||||
val nfoDocument = app.get(
|
|
||||||
seasonString + episode.attr("href"),
|
|
||||||
authHeader
|
|
||||||
).document // get episode metadata file
|
|
||||||
val epNum = nfoDocument.selectFirst("episode")?.text()?.toIntOrNull()
|
|
||||||
val poster =
|
|
||||||
seasonString + episode.attr("href").replace(".nfo", "-thumb.jpg")
|
|
||||||
val name = nfoDocument.selectFirst("title")!!.text()
|
|
||||||
// val seasonInt = nfoDocument.selectFirst("season").text().toIntOrNull()
|
|
||||||
val date = nfoDocument.selectFirst("aired")?.text()
|
|
||||||
val plot = nfoDocument.selectFirst("plot")?.text()
|
|
||||||
|
|
||||||
val dataList = seasonDocument.getElementsByAttributeValueContaining(
|
|
||||||
"href",
|
|
||||||
episode.attr("href").replace(".nfo", "")
|
|
||||||
)
|
|
||||||
val data = seasonString + dataList.firstNotNullOf { item ->
|
|
||||||
item.takeIf {
|
|
||||||
(!it.attr("href").contains(".nfo") && !it.attr("href").contains(".jpg"))
|
|
||||||
}
|
|
||||||
}.attr("href").toString() // exclude poster and nfo (metadata) file
|
|
||||||
|
|
||||||
episodeList.add(
|
|
||||||
newEpisode(data) {
|
|
||||||
this.name = name
|
|
||||||
this.season = seasonInt
|
|
||||||
this.episode = epNum
|
|
||||||
this.posterUrl = poster // will require headers too
|
|
||||||
this.description = plot
|
|
||||||
addDate(date)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return newTvSeriesLoadResponse(title, url, TvType.TvSeries, episodeList) {
|
|
||||||
this.name = title
|
|
||||||
this.url = url
|
|
||||||
this.episodes = episodeList
|
|
||||||
this.plot = description
|
|
||||||
this.tags = tagsList
|
|
||||||
addPoster(posterUrl, authHeader)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// There is metadata and library is correctly organised!
|
||||||
|
if (!isSerie) { // Movie
|
||||||
|
|
||||||
|
val poster = metadataDocument.selectFirst("thumb[aspect=poster]")?.text()
|
||||||
|
val fanart = metadataDocument.selectFirst("fanart > thumb")?.text()
|
||||||
|
val trailer = metadataDocument.selectFirst("trailer")?.text()?.replace(
|
||||||
|
"plugin://plugin.video.youtube/play/?video_id=",
|
||||||
|
"https://www.youtube.com/watch?v="
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
val date = metadataDocument.selectFirst("year")?.text()?.toIntOrNull()
|
||||||
|
val durationInMinutes = metadataDocument.selectFirst("duration")?.text()?.toIntOrNull()
|
||||||
|
val ratingAverage = metadataDocument.selectFirst("value")?.text()?.toIntOrNull()
|
||||||
|
val tagsList = metadataDocument.select("genre")
|
||||||
|
.mapNotNull { // all the tags like action, thriller ...
|
||||||
|
it?.text()
|
||||||
|
}
|
||||||
|
val actors = metadataDocument.select("actor").mapNotNull {
|
||||||
|
val name = it?.selectFirst("name")?.text() ?: return@mapNotNull null
|
||||||
|
val image = it.selectFirst("thumb")?.text() ?: return@mapNotNull null
|
||||||
|
Actor(name, image)
|
||||||
|
}
|
||||||
|
|
||||||
|
val mkvElementsResult = mediaRootDocument.getElementsByAttributeValueContaining( // list of all urls of the mkv url in the webpage
|
||||||
|
"href",
|
||||||
|
".mkv"
|
||||||
|
)
|
||||||
|
|
||||||
|
val mp4ElementsResult = mediaRootDocument.getElementsByAttributeValueContaining( // list of all urls of the webpage
|
||||||
|
"href",
|
||||||
|
".mp4"
|
||||||
|
)
|
||||||
|
|
||||||
|
val dataList = if (mkvElementsResult.isNotEmpty()) { // there is probably a better way to do it
|
||||||
|
mkvElementsResult[0].attr("href").toString()
|
||||||
|
} else {
|
||||||
|
if(mp4ElementsResult.isNotEmpty()) {
|
||||||
|
mp4ElementsResult[0].attr("href").toString()
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (dataList != null) {
|
||||||
|
return newMovieLoadResponse(
|
||||||
|
title,
|
||||||
|
mediaRootUrl,
|
||||||
|
TvType.Movie,
|
||||||
|
mediaRootUrl + dataList,
|
||||||
|
) {
|
||||||
|
this.year = date
|
||||||
|
this.plot = description
|
||||||
|
this.rating = ratingAverage
|
||||||
|
this.tags = tagsList
|
||||||
|
this.backgroundPosterUrl = fanart
|
||||||
|
this.duration = durationInMinutes
|
||||||
|
addPoster(poster, authHeader)
|
||||||
|
addActors(actors)
|
||||||
|
addTrailer(trailer)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// a tv show
|
||||||
|
|
||||||
|
|
||||||
|
val list = ArrayList<Pair<Int, String>>()
|
||||||
|
|
||||||
|
val posterUrl = mediaRootUrl + "poster.jpg"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
val tagsList = metadataDocument.select("genre")
|
||||||
|
.mapNotNull { // all the tags like action, thriller ...; unused variable
|
||||||
|
it?.text()
|
||||||
|
}
|
||||||
|
|
||||||
|
val actorsList = metadataDocument.select("actor")
|
||||||
|
.mapNotNull { // all the tags like action, thriller ...; unused variable
|
||||||
|
if (it.selectFirst("name")?.text() != null && it.selectFirst("role")?.text() != null) {
|
||||||
|
|
||||||
|
it.selectFirst("name")?.text()
|
||||||
|
it.selectFirst("role")?.text()
|
||||||
|
} else null
|
||||||
|
}
|
||||||
|
|
||||||
|
val seasons =
|
||||||
|
mediaRootDocument.getElementsByAttributeValueContaining("href", "Season%20")
|
||||||
|
|
||||||
|
|
||||||
|
seasons.forEach { element ->
|
||||||
|
val season =
|
||||||
|
element.attr("href").replace("Season%20", "").replace("/", "").toIntOrNull()
|
||||||
|
val href = mediaRootUrl + element.attr("href")
|
||||||
|
if (season != null && season > 0 && href.isNotBlank()) {
|
||||||
|
list.add(Pair(season, href))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (list.isEmpty()) throw ErrorLoadingException("No Seasons Found, make sure to use season folders")
|
||||||
|
|
||||||
|
val episodeList = ArrayList<Episode>()
|
||||||
|
|
||||||
|
|
||||||
|
list.apmap { (seasonInt, seasonString) ->
|
||||||
|
val seasonDocument = app.get(seasonString, authHeader).document
|
||||||
|
val episodes = seasonDocument.getElementsByAttributeValueContaining(
|
||||||
|
"href",
|
||||||
|
".nfo"
|
||||||
|
) // get metadata
|
||||||
|
episodes.forEach { episode ->
|
||||||
|
val nfoDocument = app.get(seasonString + episode.attr("href"), authHeader).document // get episode metadata file
|
||||||
|
val epNum = nfoDocument.selectFirst("episode")?.text()?.toIntOrNull()
|
||||||
|
val poster =
|
||||||
|
seasonString + episode.attr("href").replace(".nfo", "-thumb.jpg")
|
||||||
|
val name = nfoDocument.selectFirst("title")?.text()
|
||||||
|
// val seasonInt = nfoDocument.selectFirst("season").text().toIntOrNull()
|
||||||
|
val date = nfoDocument.selectFirst("aired")?.text()
|
||||||
|
val plot = nfoDocument.selectFirst("plot")?.text()
|
||||||
|
|
||||||
|
val dataList = seasonDocument.getElementsByAttributeValueContaining(
|
||||||
|
"href",
|
||||||
|
episode.attr("href").replace(".nfo", "")
|
||||||
|
)
|
||||||
|
val data = seasonString + dataList.firstNotNullOf { item -> item.takeIf { (!it.attr("href").contains(".nfo") && !it.attr("href").contains(".jpg"))} }.attr("href").toString() // exclude poster and nfo (metadata) file
|
||||||
|
|
||||||
|
episodeList.add(
|
||||||
|
newEpisode(data) {
|
||||||
|
this.name = name
|
||||||
|
this.season = seasonInt
|
||||||
|
this.episode = epNum
|
||||||
|
this.posterUrl = poster // will require headers too
|
||||||
|
this.description = plot
|
||||||
|
addDate(date)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newTvSeriesLoadResponse(title, url, TvType.TvSeries, episodeList) {
|
||||||
|
this.name = title
|
||||||
|
this.url = url
|
||||||
|
this.episodes = episodeList
|
||||||
|
this.plot = description
|
||||||
|
this.tags = tagsList
|
||||||
|
addPoster(posterUrl, authHeader)
|
||||||
|
addActors(actorsList)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
///
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
override suspend fun loadLinks(
|
override suspend fun loadLinks(
|
||||||
data: String,
|
data: String,
|
||||||
isCasting: Boolean,
|
isCasting: Boolean,
|
||||||
subtitleCallback: (SubtitleFile) -> Unit,
|
subtitleCallback: (SubtitleFile) -> Unit,
|
||||||
callback: (ExtractorLink) -> Unit
|
callback: (ExtractorLink) -> Unit
|
||||||
): Boolean {
|
): Boolean {
|
||||||
// loadExtractor(data, null) { callback(it.copy(headers=authHeader)) }
|
// println("loadling link $data")
|
||||||
val authHeader =
|
|
||||||
getAuthHeader() // call again because it isn't reloaded if in main class and storedCredentials loads after
|
val authHeader = getAuthHeader() // refresh crendentials
|
||||||
callback.invoke(
|
|
||||||
|
try {
|
||||||
|
val mediaRootUrl = data.substringBeforeLast("/") + "/"
|
||||||
|
val mediaRootDocument = app.get(mediaRootUrl, authHeader).document
|
||||||
|
|
||||||
|
val subtitlesElements = mediaRootDocument.getElementsByAttributeValueContaining(
|
||||||
|
// list of all urls of the mkv url in the webpage
|
||||||
|
"href",
|
||||||
|
".srt", // all of subtitles files in the folder
|
||||||
|
)
|
||||||
|
|
||||||
|
subtitlesElements.forEach {
|
||||||
|
subtitleCallback.invoke(
|
||||||
|
SubtitleFile(
|
||||||
|
SubtitleHelper.fromTwoLettersToLanguage(it.attr("href").replace(".srt", "").substringAfterLast(".")) ?: "English",
|
||||||
|
mediaRootUrl + "/" + it.attr("href")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
logError(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
callback.invoke (
|
||||||
ExtractorLink(
|
ExtractorLink(
|
||||||
name,
|
name,
|
||||||
name,
|
name,
|
||||||
data,
|
data,
|
||||||
data, // referer not needed
|
"", // referer not needed
|
||||||
Qualities.Unknown.value,
|
Qualities.Unknown.value,
|
||||||
false,
|
false,
|
||||||
authHeader,
|
authHeader,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
|
private fun cleanElement(elementUrl: String): String {
|
||||||
val authHeader =
|
return if (elementUrl[0] == '/') { // if starts by "/", remove it
|
||||||
getAuthHeader() // call again because it isn't reloaded if in main class and storedCredentials loads after
|
elementUrl.drop(1)
|
||||||
|
} else {
|
||||||
|
elementUrl
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getMainPage(
|
||||||
|
page: Int,
|
||||||
|
request : MainPageRequest,
|
||||||
|
): HomePageResponse {
|
||||||
|
val authHeader = getAuthHeader() // reload
|
||||||
|
if (mainUrl == "NONE" || mainUrl == "" || mainUrl == "nginx_url_key"){ // mainurl: http://192.168.1.10/media/
|
||||||
|
throw ErrorLoadingException("No nginx url specified in the settings: Nginx Settigns > Nginx server url, try again in a few seconds") // getString(R.string.nginx_load_exception) or @strings/nginx_load_exception
|
||||||
|
}
|
||||||
val document = app.get(mainUrl, authHeader).document
|
val document = app.get(mainUrl, authHeader).document
|
||||||
val categories = document.select("a")
|
val categories = document.select("a") // select all of the categories
|
||||||
val returnList = categories.mapNotNull {
|
val returnList = categories.mapNotNull { // for each category
|
||||||
val categoryTitle = it.text() // get the category title like Movies or Series
|
val categoryPath = mainUrl + cleanElement(it.attr("href")) // ?: return@mapNotNull null // get the url of the category; like http://192.168.1.10/media/Movies/
|
||||||
if (categoryTitle != "../" && categoryTitle != "Music/") { // exclude parent dir and Music dir
|
val categoryTitle = it.text() // get the category title like Movies/ or Series/
|
||||||
val href = it?.attr("href")
|
if (categoryTitle != "../" && categoryTitle != "/") { // exclude parent dir
|
||||||
val categoryPath = fixUrlNull(href?.trim())
|
val categoryDocument = app.get(categoryPath, authHeader).document // queries the page http://192.168.1.10/media/Movies/
|
||||||
?: return@mapNotNull null // get the url of the category; like http://192.168.1.10/media/Movies/
|
val contentLinks = categoryDocument.select("a") // select all links
|
||||||
|
val currentList = contentLinks.mapNotNull { head -> // for each of those elements
|
||||||
val categoryDocument = app.get(
|
val linkToElement = head.attr("href")
|
||||||
categoryPath,
|
if (linkToElement != "../" && linkToElement != "/") {
|
||||||
authHeader
|
val isAFolderBool = linkToElement.endsWith("/")
|
||||||
).document // queries the page http://192.168.1.10/media/Movies/
|
|
||||||
val contentLinks = categoryDocument.select("a")
|
|
||||||
val currentList = contentLinks.mapNotNull { head ->
|
|
||||||
if (head.attr("href") != "../") {
|
|
||||||
try {
|
try {
|
||||||
val mediaRootUrl =
|
val mediaRootUrl =
|
||||||
categoryPath + head.attr("href")// like http://192.168.1.10/media/Series/Chernobyl/
|
categoryPath + cleanElement(linkToElement) // like http://192.168.1.10/Series/Chernobyl/ or http://192.168.1.10/Movies/zjfbfvz.mp4
|
||||||
val mediaDocument = app.get(mediaRootUrl, authHeader).document
|
if (isAFolderBool) { // content is organised in folders for each element
|
||||||
val nfoFilename = mediaDocument.getElementsByAttributeValueContaining(
|
|
||||||
"href",
|
|
||||||
".nfo"
|
|
||||||
)[0].attr("href")
|
|
||||||
val isMovieType = nfoFilename != "tvshow.nfo"
|
|
||||||
val nfoPath =
|
|
||||||
mediaRootUrl + nfoFilename // must exist or will raise errors, only the first one is taken
|
|
||||||
val nfoContent =
|
|
||||||
app.get(nfoPath, authHeader).document // all the metadata
|
|
||||||
|
|
||||||
if (isMovieType) {
|
/*
|
||||||
val movieName = nfoContent.select("title").text()
|
├── Movies
|
||||||
val posterUrl = mediaRootUrl + "poster.jpg"
|
├── Eternals (2021) // the media root folder will be 'http://192.168.1.10/media/Movies/Eternals (2021)/'
|
||||||
|
├── Eternals.2021.MULTi.WiTH.TRUEFRENCH.iMAX.1080p.DSNP.WEB-DL.DDP5.1.H264-FRATERNiTY.mkv
|
||||||
|
├── Eternals.2021.MULTi.WiTH.TRUEFRENCH.iMAX.1080p.DSNP.WEB-DL.DDP5.1.H264-FRATERNiTY.en.srt
|
||||||
|
├── Eternals.2021.MULTi.WiTH.TRUEFRENCH.iMAX.1080p.DSNP.WEB-DL.DDP5.1.H264-FRATERNiTY.nfo
|
||||||
|
├── fanart.jpg
|
||||||
|
└── poster.jpg
|
||||||
|
*/
|
||||||
|
|
||||||
|
val mediaDocument = app.get(mediaRootUrl, authHeader).document
|
||||||
|
val nfoFilename = try {
|
||||||
|
mediaDocument.getElementsByAttributeValueContaining(
|
||||||
|
"href",
|
||||||
|
".nfo"
|
||||||
|
)[0]?.attr("href")
|
||||||
|
} catch (e: Exception) {
|
||||||
|
logError(e)
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
val isSerieType =
|
||||||
|
nfoFilename.toString() == "tvshow.nfo" // will be a movie if no metadata
|
||||||
|
|
||||||
|
|
||||||
|
val nfoPath = if (nfoFilename != null) {
|
||||||
|
mediaRootUrl + nfoFilename // metadata must exist
|
||||||
|
} else {
|
||||||
|
return@mapNotNull newMovieSearchResponse(
|
||||||
|
linkToElement,
|
||||||
|
mediaRootUrl,
|
||||||
|
TvType.Movie,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val nfoContent = app.get(nfoPath, authHeader).document // get all the metadata
|
||||||
|
|
||||||
|
|
||||||
|
if (isSerieType) {
|
||||||
|
val serieName = nfoContent.select("title").text() ?: linkToElement // name of the tv show
|
||||||
|
|
||||||
|
val posterUrl = mediaRootUrl + "poster.jpg" // poster.jpg in the same folder
|
||||||
|
|
||||||
|
newTvSeriesSearchResponse(
|
||||||
|
serieName,
|
||||||
|
nfoPath,
|
||||||
|
TvType.TvSeries,
|
||||||
|
) {
|
||||||
|
addPoster(posterUrl, authHeader)
|
||||||
|
}
|
||||||
|
} else { // Movie
|
||||||
|
val movieName = nfoContent.select("title").text() ?: linkToElement
|
||||||
|
val posterUrl = nfoContent.selectFirst("thumb[aspect=poster]")?.text() // poster should be stored in the same folder
|
||||||
|
// val fanartUrl = mediaRootUrl + "fanart.jpg" // backdrop should be stored in the same folder
|
||||||
|
return@mapNotNull newMovieSearchResponse(
|
||||||
|
movieName,
|
||||||
|
nfoPath,
|
||||||
|
TvType.Movie,
|
||||||
|
) {
|
||||||
|
addPoster(posterUrl, authHeader)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else { // return direct file
|
||||||
|
|
||||||
|
/*
|
||||||
|
├── Movies
|
||||||
|
├── Eternals.2021.MULTi.WiTH.TRUEFRENCH.iMAX.1080p.DSNP.WEB-DL.DDP5.1.H264-FRATERNiTY.mkv // the media root folder
|
||||||
|
├── Juste la fin du monde (2016) VOF 1080p mHD x264 AC3-SANTACRUZ.mkv
|
||||||
|
*/
|
||||||
return@mapNotNull newMovieSearchResponse(
|
return@mapNotNull newMovieSearchResponse(
|
||||||
movieName,
|
linkToElement,
|
||||||
mediaRootUrl,
|
mediaRootUrl,
|
||||||
TvType.Movie,
|
TvType.Movie,
|
||||||
) {
|
)
|
||||||
addPoster(posterUrl, authHeader)
|
|
||||||
}
|
|
||||||
} else { // tv serie
|
|
||||||
val serieName = nfoContent.select("title").text()
|
|
||||||
|
|
||||||
val posterUrl = mediaRootUrl + "poster.jpg"
|
|
||||||
|
|
||||||
newTvSeriesSearchResponse(
|
|
||||||
serieName,
|
|
||||||
nfoPath,
|
|
||||||
TvType.TvSeries,
|
|
||||||
) {
|
|
||||||
addPoster(posterUrl, authHeader)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (e: Exception) { // can cause issues invisible errors
|
} catch (e: Exception) { // can cause issues invisible errors
|
||||||
null
|
null
|
||||||
//logError(e) // not working because it changes the return type of currentList to Any
|
//logError(e) // not working because it changes the return type of currentList to Any
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
} else null
|
} else null
|
||||||
}
|
}
|
||||||
if (currentList.isNotEmpty() && categoryTitle != "../") { // exclude upper dir
|
if (currentList.isNotEmpty() && categoryTitle != "../" && categoryTitle != "/") { // exclude upper dir
|
||||||
HomePageList(categoryTitle, currentList)
|
HomePageList(categoryTitle.replace("/", " "), currentList)
|
||||||
} else null
|
} else null
|
||||||
} else null // the path is ../ which is parent directory
|
} else null // the path is ../ which is parent directory
|
||||||
}
|
}
|
||||||
|
@ -284,3 +423,4 @@ class NginxProvider : MainAPI() {
|
||||||
return HomePageResponse(returnList)
|
return HomePageResponse(returnList)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue