diff --git a/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt b/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt index e8ad476a..1bcdf422 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt @@ -1139,21 +1139,8 @@ interface LoadResponse { fun getDurationFromString(input: String?): Int? { val cleanInput = input?.trim()?.replace(" ", "") ?: return null - Regex("([0-9]*)h.*?([0-9]*)m").find(cleanInput)?.groupValues?.let { values -> - if (values.size == 3) { - val hours = values[1].toIntOrNull() - val minutes = values[2].toIntOrNull() - if (minutes != null && hours != null) { - return hours * 60 + minutes - } - } - } - Regex("([0-9]*)m").find(cleanInput)?.groupValues?.let { values -> - if (values.size == 2) { - return values[1].toIntOrNull() - } - } - Regex("(\\s\\d+\\shr)|(\\s\\d+\\shour)|(\\s\\d+\\smin)|(\\s\\d+\\ssec)").findAll(input).let { values -> + //Use first as sometimes the text passes on the 2 other Regex, but failed to provide accurate return value + Regex("(\\d+\\shr)|(\\d+\\shour)|(\\d+\\smin)|(\\d+\\ssec)").findAll(input).let { values -> var seconds = 0 values.forEach { val time_text = it.value @@ -1174,6 +1161,23 @@ fun getDurationFromString(input: String?): Int? { return seconds / 60 } } + Regex("([0-9]*)h.*?([0-9]*)m").find(cleanInput)?.groupValues?.let { values -> + if (values.size == 3) { + val hours = values[1].toIntOrNull() + val minutes = values[2].toIntOrNull() + if (minutes != null && hours != null) { + return hours * 60 + minutes + } + } + } + Regex("([0-9]*)m").find(cleanInput)?.groupValues?.let { values -> + if (values.size == 2) { + val return_value = values[1].toIntOrNull() + if (return_value != null) { + return return_value + } + } + } return null } diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/AccountManager.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/AccountManager.kt index 388e1774..be915baf 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/AccountManager.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/AccountManager.kt @@ -12,6 +12,7 @@ abstract class AccountManager(private val defIndex: Int) : AuthAPI { val aniListApi = AniListApi(0) val openSubtitlesApi = OpenSubtitlesApi(0) val indexSubtitlesApi = IndexSubtitleApi() + val addic7ed = Addic7ed() // used to login via app intent val OAuth2Apis @@ -37,7 +38,8 @@ abstract class AccountManager(private val defIndex: Int) : AuthAPI { val subtitleProviders get() = listOf( openSubtitlesApi, - indexSubtitlesApi // they got anti scraping measures in place :( + indexSubtitlesApi, // they got anti scraping measures in place :( + addic7ed ) const val appString = "cloudstreamapp" diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/Addic7ed.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/Addic7ed.kt new file mode 100644 index 00000000..507c5e2a --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/Addic7ed.kt @@ -0,0 +1,108 @@ +package com.lagradost.cloudstream3.syncproviders.providers + +import com.lagradost.cloudstream3.TvType +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.subtitles.AbstractSubApi +import com.lagradost.cloudstream3.subtitles.AbstractSubtitleEntities +import com.lagradost.cloudstream3.utils.SubtitleHelper + +class Addic7ed : AbstractSubApi { + override val name = "Addic7ed" + override val idPrefix = "addic7ed" + override val requiresLogin = false + override val icon: Nothing? = null + override val createAccountUrl: Nothing? = null + + override fun loginInfo(): Nothing? = null + + override fun logOut() {} + + companion object { + const val host = "https://www.addic7ed.com" + const val TAG = "ADDIC7ED" + } + + private fun fixUrl(url: String): String { + return if (url.startsWith("/")) host + url + else if (!url.startsWith("http")) "$host/$url" + else url + + } + + override suspend fun search(query: AbstractSubtitleEntities.SubtitleSearch): List { + val lang = query.lang + val queryLang = SubtitleHelper.fromTwoLettersToLanguage(lang.toString()) + val queryText = query.query.trim() + val epNum = query.epNumber ?: 0 + val seasonNum = query.seasonNumber ?: 0 + val yearNum = query.year ?: 0 + + fun cleanResources( + results: MutableList, + name: String, + link: String, + headers: Map, + isHearingImpaired: Boolean + ) { + results.add( + AbstractSubtitleEntities.SubtitleEntity( + idPrefix = idPrefix, + name = name, + lang = queryLang.toString(), + data = link, + source = this.name, + type = if (seasonNum > 0) TvType.TvSeries else TvType.Movie, + epNumber = epNum, + seasonNumber = seasonNum, + year = yearNum, + headers = headers, + isHearingImpaired = isHearingImpaired + ) + ) + } + + val title = queryText.substringBefore("(").trim() + val url = "$host/search.php?search=${title}&Submit=Search" + val hostDocument = app.get(url).document + var searchResult = "" + if (!hostDocument.select("span:contains($title)").isNullOrEmpty()) searchResult = url + else if (!hostDocument.select("table.tabel") + .isNullOrEmpty() + ) searchResult = hostDocument.select("a:contains($title)").attr("href").toString() + else { + val show = + hostDocument.selectFirst("#sl button")?.attr("onmouseup")?.substringAfter("(") + ?.substringBefore(",") + val doc = app.get( + "$host/ajax_loadShow.php?show=$show&season=$seasonNum&langs=&hd=undefined&hi=undefined", + referer = "$host/" + ).document + doc.select("#season tr:contains($queryLang)").mapNotNull { node -> + if (node.selectFirst("td")?.text() + ?.toIntOrNull() == seasonNum && node.select("td:eq(1)") + .text() + .toIntOrNull() == epNum + ) searchResult = fixUrl(node.select("a").attr("href")) + } + } + val results = mutableListOf() + val document = app.get( + url = fixUrl(searchResult), + ).document + + document.select(".tabel95 .tabel95 tr:contains($queryLang)").mapNotNull { node -> + val name = if (seasonNum > 0) "${document.select(".titulo").text().replace("Subtitle","").trim()}${ + node.parent()!!.select(".NewsTitle").text().substringAfter("Version").substringBefore(", Duration") + }" else "${document.select(".titulo").text().replace("Subtitle","").trim()}${node.parent()!!.select(".NewsTitle").text().substringAfter("Version").substringBefore(", Duration")}" + val link = fixUrl(node.select("a.buttonDownload").attr("href")) + val isHearingImpaired = + !node.parent()!!.select("tr:last-child [title=\"Hearing Impaired\"]").isNullOrEmpty() + cleanResources(results, name, link, mapOf("referer" to "$host/"), isHearingImpaired) + } + return results + } + + override suspend fun load(data: AbstractSubtitleEntities.SubtitleEntity): String { + return data.data + } +} \ No newline at end of file