diff --git a/UFDubProvider/build.gradle.kts b/UFDubProvider/build.gradle.kts new file mode 100644 index 0000000..e35ba64 --- /dev/null +++ b/UFDubProvider/build.gradle.kts @@ -0,0 +1,27 @@ +// use an integer for version numbers +version = 1 + + +cloudstream { + language = "uk" + // All of these properties are optional, you can safely remove them + + description = "UFDUB.com - Це команда любителів, що озвучують з душею те, що бажають глядачі й учасники проєкту! \uD83E\uDDE1" + authors = listOf("CakesTwix") + + /** + * Status int as the following: + * 0: Down + * 1: Ok + * 2: Slow + * 3: Beta only + * */ + status = 1 // will be 3 if unspecified + tvTypes = listOf( + "Anime", + "TvSeries", + "Movie", + ) + + iconUrl = "https://www.google.com/s2/favicons?domain=ufdub.com&sz=%size%" +} \ No newline at end of file diff --git a/UFDubProvider/src/main/AndroidManifest.xml b/UFDubProvider/src/main/AndroidManifest.xml new file mode 100644 index 0000000..29aec9d --- /dev/null +++ b/UFDubProvider/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/UFDubProvider/src/main/kotlin/com/lagradost/UFDubProvider.kt b/UFDubProvider/src/main/kotlin/com/lagradost/UFDubProvider.kt new file mode 100644 index 0000000..a8fc8fd --- /dev/null +++ b/UFDubProvider/src/main/kotlin/com/lagradost/UFDubProvider.kt @@ -0,0 +1,165 @@ +package com.lagradost + +import android.net.Uri +import android.util.Log +import com.lagradost.cloudstream3.* +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.M3u8Helper +import com.lagradost.cloudstream3.utils.Qualities +import org.jsoup.nodes.Element + +class UFDubProvider : MainAPI() { + + // Basic Info + override var mainUrl = "https://ufdub.com" + override var name = "UFDub" + override val hasMainPage = true + override var lang = "uk" + override val hasDownloadSupport = true + override val supportedTypes = setOf( + TvType.AnimeMovie, + TvType.Anime, + TvType.AsianDrama, + TvType.Movie, + TvType.Cartoon, + TvType.TvSeries + ) + + // Sections + override val mainPage = mainPageOf( + "$mainUrl/anime/page/" to "Аніме", + "$mainUrl/serial/page/" to "Серіали", + "$mainUrl/film/page/" to "Фільми", + "$mainUrl/cartoon/page/" to "Мультфільми", + "$mainUrl/cartoon-fiml/page/" to "Мультсеріали", + "$mainUrl/dorama/page/" to "Дорами", + + ) + + override suspend fun getMainPage( + page: Int, + request: MainPageRequest + ): HomePageResponse { + val document = app.get(request.data + page).document + document.select(".section").remove() + + val home = document.select(".short").map { + it.toSearchResponse() + } + return newHomePageResponse(request.name, home) + } + + private fun Element.toSearchResponse(): SearchResponse { + val title = this.select(".short-t").text() + val href = this.select(".short-t").attr("href").toString() + val posterUrl = mainUrl + this.select(".img-box img").attr("src") + + return newMovieSearchResponse(title, href, TvType.Anime) { + this.posterUrl = posterUrl + } + + } + + override suspend fun search(query: String): List { + val document = app.post( + url = mainUrl, + data = mapOf( + "do" to "search", + "subaction" to "search", + "story" to query.replace(" ", "+") + ) + ).document + + return document.select("article.story").map { + it.toSearchResponse() + } + } + + // Detailed information + override suspend fun load(url: String): LoadResponse { + val document = app.get(url).document + + val someInfo = document.select("div.full-desc") + + // Parse info + val title = document.select("h1.top-title").text() + val poster = mainUrl + document.select("div.f-poster img").attr("src") + var tags = emptyList() + val year = someInfo.select("strong:contains(Рік випуску аніме:)").next().html().toIntOrNull() + + // TODO: Check type by url + val tvType = TvType.Anime + val description = document.select("div.full-text p").text() + // val author = someInfo.select("strong:contains(Студія:)").next().html() + val rating = document.selectFirst(".lexington-box > div:last-child span")?.text().toRatingInt() + + val recommendations = document.select(".horizontal ul").map { + it.toSearchResponse() + } + + someInfo.select(".full-info div.fi-col-item") + .forEach { + ele -> + when (ele.select("span").text()) { + //"Студія:" -> tags = ele.select("a").text().split(" / ") + "Жанр:" -> ele.select("a").map { tags = tags.plus(it.text()) } + } + } + + // Parse episodes + var episodes: List = emptyList() + // Get Player URL + val playerURl = document.select("input[value*=https://video.ufdub.com]").attr("value") + + // Parse only player + val player = app.get(playerURl).document.select("script").html() + + // Parse all episodes + val regexUFDubEpisodes = """https:\/\/ufdub.com\/video\/VIDEOS\.php\?(.*?)'""".toRegex() + val matchResult = regexUFDubEpisodes.findAll(player) + + for (item: MatchResult in matchResult) { + val parsedUrl = Uri.parse(item.value) + episodes = episodes.plus( + Episode( + item.value.dropLast(1), // Drop ' + parsedUrl.getQueryParameter("Seriya")!!, + ) + ) + } + + return newTvSeriesLoadResponse(title, url, tvType, episodes) { + this.posterUrl = poster + this.year = year + this.plot = description + this.tags = tags + this.rating = rating + this.recommendations = recommendations + } + } + + + // It works when I click to view the series + override suspend fun loadLinks( + data: String, // (First) link, index | (Two) index, url title + isCasting: Boolean, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit + ): Boolean { + + val m3u8Url = app.get(data).url + + // Add as source + callback(ExtractorLink(m3u8Url,"UFDub", m3u8Url, "https://dl.dropboxusercontent.com", + Qualities.Unknown.value, false)) + return true + } + + private fun decode(input: String): String{ + // Decoded string, thanks to Secozzi + val hexRegex = Regex("\\\\u([0-9a-fA-F]{4})") + return hexRegex.replace(input) { matchResult -> + Integer.parseInt(matchResult.groupValues[1], 16).toChar().toString() + } + } +} \ No newline at end of file diff --git a/UFDubProvider/src/main/kotlin/com/lagradost/UFDubProviderPlugin.kt b/UFDubProvider/src/main/kotlin/com/lagradost/UFDubProviderPlugin.kt new file mode 100644 index 0000000..fbda8c0 --- /dev/null +++ b/UFDubProvider/src/main/kotlin/com/lagradost/UFDubProviderPlugin.kt @@ -0,0 +1,13 @@ +package com.lagradost + +import com.lagradost.cloudstream3.plugins.CloudstreamPlugin +import com.lagradost.cloudstream3.plugins.Plugin +import android.content.Context + +@CloudstreamPlugin +class UFDubProviderPlugin: Plugin() { + override fun load(context: Context) { + // All providers should be added in this manner. Please don't edit the providers list directly. + registerMainAPI(UFDubProvider()) + } +} \ No newline at end of file