mirror of
https://github.com/hexated/cloudstream-extensions-hexated.git
synced 2024-08-15 00:03:22 +00:00
[Sora] added flixon & animeKaizoku
This commit is contained in:
parent
7af99309a5
commit
5648710105
3 changed files with 214 additions and 20 deletions
|
@ -13,6 +13,7 @@ import com.lagradost.nicehttp.RequestBodyTypes
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||||
import okhttp3.RequestBody.Companion.toRequestBody
|
import okhttp3.RequestBody.Companion.toRequestBody
|
||||||
|
import org.jsoup.Jsoup
|
||||||
|
|
||||||
val session = Session(Requests().baseClient)
|
val session = Session(Requests().baseClient)
|
||||||
|
|
||||||
|
@ -522,7 +523,8 @@ object SoraExtractor : SoraStream() {
|
||||||
"Accept" to "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8"
|
"Accept" to "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8"
|
||||||
)
|
)
|
||||||
).document
|
).document
|
||||||
val srcm3u8 = resDoc.selectFirst("script:containsData(let url =)")?.data()?.let {
|
val srcm3u8 =
|
||||||
|
resDoc.selectFirst("script:containsData(let url =)")?.data()?.let {
|
||||||
Regex("['|\"](.*?.m3u8)['|\"]").find(it)?.groupValues?.getOrNull(1)
|
Regex("['|\"](.*?.m3u8)['|\"]").find(it)?.groupValues?.getOrNull(1)
|
||||||
}
|
}
|
||||||
callback.invoke(
|
callback.invoke(
|
||||||
|
@ -803,7 +805,8 @@ object SoraExtractor : SoraStream() {
|
||||||
"versioncode" to "11",
|
"versioncode" to "11",
|
||||||
"clienttype" to "ios_jike_default"
|
"clienttype" to "ios_jike_default"
|
||||||
)
|
)
|
||||||
val vipAPI = base64DecodeAPI("cA==YXA=cy8=Y20=di8=LnQ=b2s=a2w=bG8=aS4=YXA=ZS0=aWw=b2I=LW0=Z2E=Ly8=czo=dHA=aHQ=")
|
val vipAPI =
|
||||||
|
base64DecodeAPI("cA==YXA=cy8=Y20=di8=LnQ=b2s=a2w=bG8=aS4=YXA=ZS0=aWw=b2I=LW0=Z2E=Ly8=czo=dHA=aHQ=")
|
||||||
val searchUrl = base64DecodeAPI("b20=LmM=b2s=a2w=bG8=Ly8=czo=dHA=aHQ=")
|
val searchUrl = base64DecodeAPI("b20=LmM=b2s=a2w=bG8=Ly8=czo=dHA=aHQ=")
|
||||||
val doc = app.get(
|
val doc = app.get(
|
||||||
"$searchUrl/search?keyword=$title",
|
"$searchUrl/search?keyword=$title",
|
||||||
|
@ -1088,14 +1091,32 @@ object SoraExtractor : SoraStream() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun invokeZoro(
|
suspend fun invokeAnimes(
|
||||||
id: Int? = null,
|
id: Int? = null,
|
||||||
|
title: String? = null,
|
||||||
season: Int? = null,
|
season: Int? = null,
|
||||||
episode: Int? = null,
|
episode: Int? = null,
|
||||||
subtitleCallback: (SubtitleFile) -> Unit,
|
subtitleCallback: (SubtitleFile) -> Unit,
|
||||||
callback: (ExtractorLink) -> Unit
|
callback: (ExtractorLink) -> Unit
|
||||||
) {
|
) {
|
||||||
val malId = app.get("$tmdb2mal/?id=$id&s=$season").text.trim()
|
val malId = if (season != null) app.get("$tmdb2mal/?id=$id&s=$season").text.trim() else null
|
||||||
|
|
||||||
|
argamap(
|
||||||
|
{
|
||||||
|
if (season != null) invokeZoro(malId, episode, subtitleCallback, callback)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
invokeAnimeKaizoku(title, malId, season, episode, callback)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun invokeZoro(
|
||||||
|
malId: String? = null,
|
||||||
|
episode: Int? = null,
|
||||||
|
subtitleCallback: (SubtitleFile) -> Unit,
|
||||||
|
callback: (ExtractorLink) -> Unit
|
||||||
|
) {
|
||||||
val episodeId = app.get("$consumetMalAPI/info/$malId?provider=zoro")
|
val episodeId = app.get("$consumetMalAPI/info/$malId?provider=zoro")
|
||||||
.parsedSafe<ConsumetDetails>()?.episodes?.find {
|
.parsedSafe<ConsumetDetails>()?.episodes?.find {
|
||||||
it.number == episode
|
it.number == episode
|
||||||
|
@ -1131,7 +1152,74 @@ object SoraExtractor : SoraStream() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun invokeAnimeKaizoku(
|
||||||
|
title: String? = null,
|
||||||
|
malId: String? = null,
|
||||||
|
season: Int? = null,
|
||||||
|
episode: Int? = null,
|
||||||
|
callback: (ExtractorLink) -> Unit
|
||||||
|
) {
|
||||||
|
val fixTitle = title.fixTitle()
|
||||||
|
val search = app.get("$animeKaizokuAPI/?s=${fixTitle?.replace("-", " ")}").document
|
||||||
|
val detailHref =
|
||||||
|
search.select("ul#posts-container li").map { it.selectFirst("a")?.attr("href") }
|
||||||
|
.find {
|
||||||
|
if (season == null) it?.contains(
|
||||||
|
fixTitle ?: return,
|
||||||
|
true
|
||||||
|
) == true else it?.contains(malId ?: return) == true
|
||||||
|
}?.let { fixUrl(it, animeKaizokuAPI) }
|
||||||
|
|
||||||
|
val detail = app.get(detailHref ?: return).document
|
||||||
|
val postId =
|
||||||
|
detail.selectFirst("link[rel=shortlink]")?.attr("href")?.substringAfter("?p=") ?: return
|
||||||
|
val script = detail.selectFirst("script:containsData(DDL)")?.data()?.splitData() ?: return
|
||||||
|
|
||||||
|
val media = fetchingKaizoku(animeKaizokuAPI, postId, script, detailHref).document
|
||||||
|
val iframe = media.select("tbody td[colspan=2]").map { it.attr("onclick") to it.text() }
|
||||||
|
.filter { it.second.contains("1080p", true) }
|
||||||
|
|
||||||
|
val eps = if (season == null) {
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
if (episode!! < 10) "0$episode" else episode
|
||||||
|
}
|
||||||
|
|
||||||
|
iframe.apmap { (data, name) ->
|
||||||
|
val worker =
|
||||||
|
fetchingKaizoku(animeKaizokuAPI, postId, data.splitData(), detailHref).document
|
||||||
|
.select("tbody td")
|
||||||
|
.map { Triple(it.attr("onclick"), it.text(), it.nextElementSibling()?.text()) }
|
||||||
|
|
||||||
|
val episodeData = worker.let { list ->
|
||||||
|
if (season == null) list.firstOrNull() else list.find {
|
||||||
|
it.second.contains(
|
||||||
|
Regex("($eps\\.)|(-\\s$eps)")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} ?: return@apmap null
|
||||||
|
|
||||||
|
val ouo = fetchingKaizoku(
|
||||||
|
animeKaizokuAPI,
|
||||||
|
postId,
|
||||||
|
episodeData.first.splitData(),
|
||||||
|
detailHref
|
||||||
|
).text.substringAfter("openInNewTab(\"")
|
||||||
|
.substringBefore("\")").let { base64Decode(it) }
|
||||||
|
|
||||||
|
if(!ouo.startsWith("https://ouo")) return@apmap null
|
||||||
|
callback.invoke(
|
||||||
|
ExtractorLink(
|
||||||
|
"AnimeKaizoku [${episodeData.third}]",
|
||||||
|
"AnimeKaizoku [${episodeData.third}]",
|
||||||
|
bypassOuo(ouo) ?: return@apmap null,
|
||||||
|
"$animeKaizokuAPI/",
|
||||||
|
Qualities.P1080.value,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun invokeLing(
|
suspend fun invokeLing(
|
||||||
|
@ -1780,6 +1868,58 @@ object SoraExtractor : SoraStream() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun invokeFlixon(
|
||||||
|
tmdbId: Int? = null,
|
||||||
|
imdbId: String? = null,
|
||||||
|
season: Int? = null,
|
||||||
|
episode: Int? = null,
|
||||||
|
callback: (ExtractorLink) -> Unit
|
||||||
|
) {
|
||||||
|
val onionUrl = "https://onionplay.se/"
|
||||||
|
val request = if (season == null) {
|
||||||
|
val res = app.get("$flixonAPI/$imdbId", referer = onionUrl)
|
||||||
|
if (res.text.contains("BEGIN PGP SIGNED MESSAGE")
|
||||||
|
) app.get("$flixonAPI/$imdbId-1", referer = onionUrl) else res
|
||||||
|
} else {
|
||||||
|
app.get("$flixonAPI/$tmdbId-$season-$episode", referer = onionUrl)
|
||||||
|
}
|
||||||
|
|
||||||
|
val script = request.document.selectFirst("script:containsData(= \"\";)")?.data()
|
||||||
|
val collection = script?.substringAfter("= [")?.substringBefore("];")
|
||||||
|
val num = script?.substringAfterLast("(value) -")?.substringBefore(");")?.trim()?.toInt()
|
||||||
|
?: return
|
||||||
|
|
||||||
|
val iframe = collection?.split(",")?.map { it.trim().toInt() }?.map { nums ->
|
||||||
|
nums.minus(num).toChar()
|
||||||
|
}?.joinToString("")?.let { Jsoup.parse(it) }?.selectFirst("button.redirect")
|
||||||
|
?.attr("onclick")
|
||||||
|
?.substringAfter("('")?.substringBefore("')")
|
||||||
|
|
||||||
|
val unPacker =
|
||||||
|
app.get(iframe ?: return).document.selectFirst("script:containsData(JuicyCodes.Run)")
|
||||||
|
?.data()
|
||||||
|
?.substringAfter("JuicyCodes.Run(")?.substringBefore(");")?.split("+")
|
||||||
|
?.joinToString("") { it.replace("\"", "").trim() }
|
||||||
|
?.let { getAndUnpack(base64Decode(it)) }
|
||||||
|
|
||||||
|
val ref = "https://onionflix.ru/"
|
||||||
|
val link = Regex("[\"']file[\"']:[\"'](.+?)[\"'],").find(
|
||||||
|
unPacker ?: return
|
||||||
|
)?.groupValues?.getOrNull(1)?.let { app.get(it, referer = ref).url }
|
||||||
|
|
||||||
|
callback.invoke(
|
||||||
|
ExtractorLink(
|
||||||
|
"Flixon",
|
||||||
|
"Flixon",
|
||||||
|
link ?: return,
|
||||||
|
ref,
|
||||||
|
Qualities.P720.value,
|
||||||
|
link.contains(".m3u8")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class StreamM4u : XStreamCdn() {
|
class StreamM4u : XStreamCdn() {
|
||||||
|
|
|
@ -2,6 +2,7 @@ package com.hexated
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty
|
import com.fasterxml.jackson.annotation.JsonProperty
|
||||||
import com.hexated.SoraExtractor.invoke123Movie
|
import com.hexated.SoraExtractor.invoke123Movie
|
||||||
|
import com.hexated.SoraExtractor.invokeAnimes
|
||||||
import com.hexated.SoraExtractor.invokeBollyMaza
|
import com.hexated.SoraExtractor.invokeBollyMaza
|
||||||
import com.hexated.SoraExtractor.invokeDbgo
|
import com.hexated.SoraExtractor.invokeDbgo
|
||||||
import com.hexated.SoraExtractor.invokeFilmxy
|
import com.hexated.SoraExtractor.invokeFilmxy
|
||||||
|
@ -21,6 +22,7 @@ import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
|
||||||
import com.lagradost.cloudstream3.metaproviders.TmdbProvider
|
import com.lagradost.cloudstream3.metaproviders.TmdbProvider
|
||||||
import com.hexated.SoraExtractor.invokeCrunchyroll
|
import com.hexated.SoraExtractor.invokeCrunchyroll
|
||||||
import com.hexated.SoraExtractor.invokeFDMovies
|
import com.hexated.SoraExtractor.invokeFDMovies
|
||||||
|
import com.hexated.SoraExtractor.invokeFlixon
|
||||||
import com.hexated.SoraExtractor.invokeFwatayako
|
import com.hexated.SoraExtractor.invokeFwatayako
|
||||||
import com.hexated.SoraExtractor.invokeGMovies
|
import com.hexated.SoraExtractor.invokeGMovies
|
||||||
import com.hexated.SoraExtractor.invokeKisskh
|
import com.hexated.SoraExtractor.invokeKisskh
|
||||||
|
@ -32,7 +34,6 @@ import com.hexated.SoraExtractor.invokeRStream
|
||||||
import com.hexated.SoraExtractor.invokeSoraStream
|
import com.hexated.SoraExtractor.invokeSoraStream
|
||||||
import com.hexated.SoraExtractor.invokeTvMovies
|
import com.hexated.SoraExtractor.invokeTvMovies
|
||||||
import com.hexated.SoraExtractor.invokeUhdmovies
|
import com.hexated.SoraExtractor.invokeUhdmovies
|
||||||
import com.hexated.SoraExtractor.invokeZoro
|
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
|
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils.toJson
|
import com.lagradost.cloudstream3.utils.AppUtils.toJson
|
||||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
|
@ -64,7 +65,8 @@ open class SoraStream : TmdbProvider() {
|
||||||
base64DecodeAPI("cHA=LmE=ZWw=cmM=dmU=aC4=dGM=d2E=eHA=Ly8=czo=dHA=aHQ=")
|
base64DecodeAPI("cHA=LmE=ZWw=cmM=dmU=aC4=dGM=d2E=eHA=Ly8=czo=dHA=aHQ=")
|
||||||
|
|
||||||
// private var mainServerAPI = base64DecodeAPI("cA==YXA=bC4=Y2U=ZXI=LnY=aWU=b3Y=LW0=cmE=c28=Ly8=czo=dHA=aHQ=")
|
// private var mainServerAPI = base64DecodeAPI("cA==YXA=bC4=Y2U=ZXI=LnY=aWU=b3Y=LW0=cmE=c28=Ly8=czo=dHA=aHQ=")
|
||||||
var netMoviesAPI = base64DecodeAPI("aQ==YXA=cC8=YXA=bC4=Y2U=ZXI=LnY=bG0=Zmk=dC0=bmU=Ly8=czo=dHA=aHQ=")
|
var netMoviesAPI =
|
||||||
|
base64DecodeAPI("aQ==YXA=cC8=YXA=bC4=Y2U=ZXI=LnY=bG0=Zmk=dC0=bmU=Ly8=czo=dHA=aHQ=")
|
||||||
const val twoEmbedAPI = "https://www.2embed.to"
|
const val twoEmbedAPI = "https://www.2embed.to"
|
||||||
const val vidSrcAPI = "https://v2.vidsrc.me"
|
const val vidSrcAPI = "https://v2.vidsrc.me"
|
||||||
const val dbgoAPI = "https://dbgo.fun"
|
const val dbgoAPI = "https://dbgo.fun"
|
||||||
|
@ -95,6 +97,8 @@ open class SoraStream : TmdbProvider() {
|
||||||
const val bollyMazaAPI = "https://b.bloginguru.info"
|
const val bollyMazaAPI = "https://b.bloginguru.info"
|
||||||
const val moviesbayAPI = "https://moviesbay.live"
|
const val moviesbayAPI = "https://moviesbay.live"
|
||||||
const val rStreamAPI = "https://fsa.remotestre.am"
|
const val rStreamAPI = "https://fsa.remotestre.am"
|
||||||
|
const val flixonAPI = "https://flixon.ru"
|
||||||
|
const val animeKaizokuAPI = "https://animekaizoku.com"
|
||||||
|
|
||||||
fun getType(t: String?): TvType {
|
fun getType(t: String?): TvType {
|
||||||
return when (t) {
|
return when (t) {
|
||||||
|
@ -350,13 +354,7 @@ open class SoraStream : TmdbProvider() {
|
||||||
// )
|
// )
|
||||||
// },
|
// },
|
||||||
{
|
{
|
||||||
if (res.season != null && res.isAnime) invokeZoro(
|
if (res.isAnime) invokeAnimes(res.id, res.title, res.season, res.episode, subtitleCallback, callback)
|
||||||
res.id,
|
|
||||||
res.season,
|
|
||||||
res.episode,
|
|
||||||
subtitleCallback,
|
|
||||||
callback
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
if (res.season != null && res.isAnime) invokeCrunchyroll(
|
if (res.season != null && res.isAnime) invokeCrunchyroll(
|
||||||
|
@ -516,7 +514,10 @@ open class SoraStream : TmdbProvider() {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
invokeRStream(res.id, res.season, res.episode, callback)
|
invokeRStream(res.id, res.season, res.episode, callback)
|
||||||
}
|
},
|
||||||
|
{
|
||||||
|
invokeFlixon(res.id, res.imdbId, res.season, res.episode, callback)
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
|
|
@ -3,6 +3,7 @@ package com.hexated
|
||||||
import com.hexated.SoraStream.Companion.filmxyAPI
|
import com.hexated.SoraStream.Companion.filmxyAPI
|
||||||
import com.hexated.SoraStream.Companion.gdbot
|
import com.hexated.SoraStream.Companion.gdbot
|
||||||
import com.hexated.SoraStream.Companion.tvMoviesAPI
|
import com.hexated.SoraStream.Companion.tvMoviesAPI
|
||||||
|
import com.lagradost.cloudstream3.APIHolder
|
||||||
import com.lagradost.cloudstream3.app
|
import com.lagradost.cloudstream3.app
|
||||||
import com.lagradost.cloudstream3.base64Decode
|
import com.lagradost.cloudstream3.base64Decode
|
||||||
import com.lagradost.cloudstream3.base64Encode
|
import com.lagradost.cloudstream3.base64Encode
|
||||||
|
@ -12,6 +13,7 @@ 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.SubtitleHelper
|
||||||
import com.lagradost.cloudstream3.utils.getQualityFromName
|
import com.lagradost.cloudstream3.utils.getQualityFromName
|
||||||
|
import com.lagradost.nicehttp.NiceResponse
|
||||||
import com.lagradost.nicehttp.RequestBodyTypes
|
import com.lagradost.nicehttp.RequestBodyTypes
|
||||||
import com.lagradost.nicehttp.requestCreator
|
import com.lagradost.nicehttp.requestCreator
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
|
@ -256,13 +258,64 @@ suspend fun extractCovyn(url: String?): Pair<String?, String?>? {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getDirectGdrive(url: String): String {
|
fun getDirectGdrive(url: String): String {
|
||||||
return if(url.endsWith("share_link")) {
|
return if (url.contains("&export=download")) {
|
||||||
"https://drive.google.com/uc?id=${url.substringAfter("/d/").substringBefore("/")}&export=download"
|
|
||||||
} else {
|
|
||||||
url
|
url
|
||||||
|
} else {
|
||||||
|
"https://drive.google.com/uc?id=${
|
||||||
|
url.substringAfter("/d/").substringBefore("/")
|
||||||
|
}&export=download"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun bypassOuo(url: String?) : String? {
|
||||||
|
var res = session.get(url ?: return null)
|
||||||
|
(1..2).forEach { _ ->
|
||||||
|
val document = res.document
|
||||||
|
val nextUrl = document.select("form").attr("action")
|
||||||
|
val data = document.select("form input").mapNotNull {
|
||||||
|
it.attr("name") to it.attr("value")
|
||||||
|
}.toMap().toMutableMap()
|
||||||
|
val captchaKey = document.select("script[src*=https://www.google.com/recaptcha/api.js?render=]")
|
||||||
|
.attr("src").substringAfter("render=")
|
||||||
|
val token = APIHolder.getCaptchaToken(url, captchaKey)
|
||||||
|
data["x-token"] = token ?: ""
|
||||||
|
res = session.post(
|
||||||
|
nextUrl,
|
||||||
|
data = data,
|
||||||
|
headers = mapOf("content-type" to "application/x-www-form-urlencoded"),
|
||||||
|
allowRedirects = false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.headers["location"]
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun fetchingKaizoku(
|
||||||
|
domain: String,
|
||||||
|
postId: String,
|
||||||
|
data: List<String>,
|
||||||
|
ref: String
|
||||||
|
): NiceResponse {
|
||||||
|
return app.post(
|
||||||
|
"$domain/wp-admin/admin-ajax.php",
|
||||||
|
data = mapOf(
|
||||||
|
"action" to "DDL",
|
||||||
|
"post_id" to postId,
|
||||||
|
"div_id" to data.first(),
|
||||||
|
"tab_id" to data[1],
|
||||||
|
"num" to data[2],
|
||||||
|
"folder" to data.last()
|
||||||
|
),
|
||||||
|
headers = mapOf("X-Requested-With" to "XMLHttpRequest"),
|
||||||
|
referer = ref
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun String.splitData(): List<String> {
|
||||||
|
return this.substringAfterLast("DDL(").substringBefore(")").split(",")
|
||||||
|
.map { it.replace("'", "").trim() }
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun bypassFdAds(url: String?): String? {
|
suspend fun bypassFdAds(url: String?): String? {
|
||||||
val directUrl = app.get(url ?: return null, verify = false).document.select("a#link").attr("href")
|
val directUrl = app.get(url ?: return null, verify = false).document.select("a#link").attr("href")
|
||||||
.substringAfter("/go/")
|
.substringAfter("/go/")
|
||||||
|
@ -399,7 +452,7 @@ fun Document.findTvMoviesIframe(): String? {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun String?.fixTitle(): String? {
|
fun String?.fixTitle(): String? {
|
||||||
return this?.replace(Regex("[!%:']|( &)"), "")?.replace(" ", "-")?.lowercase()
|
return this?.replace(Regex("[!%:'?]|( &)"), "")?.replace(" ", "-")?.lowercase()
|
||||||
?.replace("-–-", "-")
|
?.replace("-–-", "-")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue