uakino: Import from cloudstream-extensions-multilingual
I didn't make the extension, I just added myself for modifications and fixes. Fixed compilation errors associated with JSON library. Added voice studio to the episode titles In the future we need to fix Naruto parsing. It's mistakenly thought to be a movie, but it's not.
This commit is contained in:
parent
23b11ebdd3
commit
3d781d88c0
7 changed files with 224 additions and 53 deletions
|
@ -1,24 +0,0 @@
|
||||||
// use an integer for version numbers
|
|
||||||
version = 1
|
|
||||||
|
|
||||||
|
|
||||||
cloudstream {
|
|
||||||
// All of these properties are optional, you can safely remove them
|
|
||||||
|
|
||||||
description = "Lorem Ipsum"
|
|
||||||
authors = listOf("Cloudburst")
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Status int as the following:
|
|
||||||
* 0: Down
|
|
||||||
* 1: Ok
|
|
||||||
* 2: Slow
|
|
||||||
* 3: Beta only
|
|
||||||
* */
|
|
||||||
status = 1 // will be 3 if unspecified
|
|
||||||
|
|
||||||
// List of video source types. Users are able to filter for extensions in a given category.
|
|
||||||
// You can find a list of avaliable types here:
|
|
||||||
// https://recloudstream.github.io/cloudstream/html/app/com.lagradost.cloudstream3/-tv-type/index.html
|
|
||||||
tvTypes = listOf("Others")
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
package com.example
|
|
||||||
|
|
||||||
import com.lagradost.cloudstream3.TvType
|
|
||||||
import com.lagradost.cloudstream3.MainAPI
|
|
||||||
import com.lagradost.cloudstream3.SearchResponse
|
|
||||||
|
|
||||||
class ExampleProvider : MainAPI() { // all providers must be an instance of MainAPI
|
|
||||||
override var mainUrl = "https://example.com/"
|
|
||||||
override var name = "Example provider"
|
|
||||||
override val supportedTypes = setOf(TvType.Movie)
|
|
||||||
|
|
||||||
override var lang = "en"
|
|
||||||
|
|
||||||
// enable this when your provider has a main page
|
|
||||||
override val hasMainPage = true
|
|
||||||
|
|
||||||
// this function gets called when you search for something
|
|
||||||
override suspend fun search(query: String): List<SearchResponse> {
|
|
||||||
return listOf<SearchResponse>()
|
|
||||||
}
|
|
||||||
}
|
|
27
UakinoProvider/build.gradle.kts
Normal file
27
UakinoProvider/build.gradle.kts
Normal file
|
@ -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 = "Дивитися фільми та серіали онлайн в HD якості. У нас можна дивитися кіно онлайн безкоштовно, у високій якості та з якісним українським дубляжем."
|
||||||
|
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=uakino.club&sz=%size%"
|
||||||
|
}
|
|
@ -1,2 +1,2 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest package="com.example"/>
|
<manifest package="com.lagradost"/>
|
188
UakinoProvider/src/main/kotlin/com/lagradost/UakinoProvider.kt
Normal file
188
UakinoProvider/src/main/kotlin/com/lagradost/UakinoProvider.kt
Normal file
|
@ -0,0 +1,188 @@
|
||||||
|
package com.lagradost
|
||||||
|
|
||||||
|
import com.lagradost.cloudstream3.*
|
||||||
|
import com.lagradost.cloudstream3.LoadResponse.Companion.addActors
|
||||||
|
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
|
||||||
|
import com.lagradost.cloudstream3.mvvm.safeApiCall
|
||||||
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
|
import com.lagradost.cloudstream3.utils.M3u8Helper
|
||||||
|
import org.jsoup.Jsoup
|
||||||
|
import org.jsoup.nodes.Element
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class UakinoProvider : MainAPI() {
|
||||||
|
|
||||||
|
// Basic Info
|
||||||
|
override var mainUrl = "https://uakino.club"
|
||||||
|
override var name = "Uakino"
|
||||||
|
override val hasMainPage = true
|
||||||
|
override var lang = "uk"
|
||||||
|
override val hasDownloadSupport = true
|
||||||
|
override val supportedTypes = setOf(
|
||||||
|
TvType.Movie,
|
||||||
|
TvType.TvSeries,
|
||||||
|
TvType.Anime
|
||||||
|
)
|
||||||
|
|
||||||
|
// Sections
|
||||||
|
override val mainPage = mainPageOf(
|
||||||
|
"$mainUrl/filmy/page/" to "Фільми",
|
||||||
|
"$mainUrl/seriesss/page/" to "Серіали",
|
||||||
|
"$mainUrl/seriesss/doramy/page/" to "Дорами",
|
||||||
|
"$mainUrl/animeukr/page/" to "Аніме",
|
||||||
|
"$mainUrl/cartoon/page/" to "Мультфільми",
|
||||||
|
"$mainUrl/cartoon/cartoonseries/page/" to "Мультсеріали",
|
||||||
|
)
|
||||||
|
|
||||||
|
override suspend fun getMainPage(
|
||||||
|
page: Int,
|
||||||
|
request: MainPageRequest
|
||||||
|
): HomePageResponse {
|
||||||
|
val document = app.get(request.data + page).document
|
||||||
|
val home = document.select("div.owl-item, div.movie-item").map {
|
||||||
|
it.toSearchResponse()
|
||||||
|
}
|
||||||
|
return newHomePageResponse(request.name, home)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Element.toSearchResponse(): SearchResponse {
|
||||||
|
val title = this.selectFirst("a.movie-title")?.text()?.trim().toString()
|
||||||
|
val href = this.selectFirst("a.movie-title")?.attr("href").toString()
|
||||||
|
val posterUrl = fixUrlNull(this.selectFirst("img")?.attr("src"))
|
||||||
|
return newMovieSearchResponse(title, href, TvType.Movie) {
|
||||||
|
this.posterUrl = posterUrl
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun search(query: String): List<SearchResponse> {
|
||||||
|
val document = app.post(
|
||||||
|
url = mainUrl,
|
||||||
|
data = mapOf(
|
||||||
|
"do" to "search",
|
||||||
|
"subaction" to "search",
|
||||||
|
"story" to query.replace(" ", "+")
|
||||||
|
)
|
||||||
|
).document
|
||||||
|
return document.select("div.movie-item.short-item").map {
|
||||||
|
it.toSearchResponse()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun load(url: String): LoadResponse {
|
||||||
|
val document = app.get(url).document
|
||||||
|
|
||||||
|
// Parse info
|
||||||
|
val title = document.selectFirst("h1 span.solototle")?.text()?.trim().toString()
|
||||||
|
val poster = fixUrl(document.selectFirst("div.film-poster img")?.attr("src").toString())
|
||||||
|
val tags = document.select("div.film-info > div:nth-child(4) a").map { it.text() }
|
||||||
|
val year = document.select("div.film-info > div:nth-child(2) a").text().toIntOrNull()
|
||||||
|
// TODO: Fix Naruto. Its series, not Movie Lol
|
||||||
|
// https://uakino.club/animeukr/6268-naruto-1-sezon.html
|
||||||
|
val tvType =
|
||||||
|
if (url.contains(Regex("(/anime-series)|(/seriesss)|(/cartoonseries)"))) TvType.TvSeries else TvType.Movie
|
||||||
|
val description = document.selectFirst("div[itemprop=description]")?.text()?.trim()
|
||||||
|
val trailer = document.selectFirst("iframe#pre")?.attr("data-src")
|
||||||
|
val rating = document.selectFirst("div.film-info > div:nth-child(8) div.fi-desc")?.text()
|
||||||
|
?.substringBefore("/").toRatingInt()
|
||||||
|
val actors = document.select("div.film-info > div:nth-child(6) a").map { it.text() }
|
||||||
|
|
||||||
|
val recommendations = document.select("div#full-slides div.owl-item").map {
|
||||||
|
it.toSearchResponse()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return to app
|
||||||
|
// Parse Episodes as Series
|
||||||
|
return if (tvType == TvType.TvSeries) {
|
||||||
|
val id = url.split("/").last().split("-").first()
|
||||||
|
val episodes =
|
||||||
|
app.get("$mainUrl/engine/ajax/playlists.php?news_id=$id&xfield=playlist&time=${Date().time}")
|
||||||
|
.parsedSafe<Responses>()?.response.let {
|
||||||
|
Jsoup.parse(it.toString()).select("ul > li").mapNotNull { eps ->
|
||||||
|
val href = fixUrl(eps.attr("data-file")) // ashdi.vip/...
|
||||||
|
val name = "${eps.text().trim()} (${eps.attr("data-voice")})" // Серія 1 (Озвучення)
|
||||||
|
if (href.isNotEmpty()) {
|
||||||
|
Episode(
|
||||||
|
href,
|
||||||
|
name,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
newTvSeriesLoadResponse(title, url, TvType.TvSeries, episodes) {
|
||||||
|
this.posterUrl = poster
|
||||||
|
this.year = year
|
||||||
|
this.plot = description
|
||||||
|
this.tags = tags
|
||||||
|
this.rating = rating
|
||||||
|
addActors(actors)
|
||||||
|
this.recommendations = recommendations
|
||||||
|
addTrailer(trailer)
|
||||||
|
}
|
||||||
|
} else { // Parse as Movie.
|
||||||
|
newMovieLoadResponse(title, url, TvType.Movie, url) {
|
||||||
|
this.posterUrl = poster
|
||||||
|
this.year = year
|
||||||
|
this.plot = description
|
||||||
|
this.tags = tags
|
||||||
|
this.rating = rating
|
||||||
|
addActors(actors)
|
||||||
|
this.recommendations = recommendations
|
||||||
|
addTrailer(trailer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun loadLinks(
|
||||||
|
data: String,
|
||||||
|
isCasting: Boolean,
|
||||||
|
subtitleCallback: (SubtitleFile) -> Unit,
|
||||||
|
callback: (ExtractorLink) -> Unit
|
||||||
|
): Boolean {
|
||||||
|
|
||||||
|
val links = ArrayList<String>()
|
||||||
|
|
||||||
|
if (data.startsWith("https://ashdi.vip")) {
|
||||||
|
links.add(data)
|
||||||
|
} else {
|
||||||
|
val iframeUrl = app.get(data).document.selectFirst("iframe#pre")?.attr("src")
|
||||||
|
if (iframeUrl.isNullOrEmpty()) {
|
||||||
|
val id = data.split("/").last().split("-").first()
|
||||||
|
app.get("$mainUrl/engine/ajax/playlists.php?news_id=$id&xfield=playlist&time=${Date().time}")
|
||||||
|
.parsedSafe<Responses>()?.response.let {
|
||||||
|
Jsoup.parse(it.toString()).select("ul > li").mapNotNull { mirror ->
|
||||||
|
links.add(fixUrl(mirror.attr("data-file")))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
links.add(iframeUrl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
links.apmap { link ->
|
||||||
|
safeApiCall {
|
||||||
|
app.get(link, referer = "$mainUrl/").document.select("script").map { script ->
|
||||||
|
if (script.data().contains("var player = new Playerjs({")) {
|
||||||
|
val m3uLink =
|
||||||
|
script.data().substringAfterLast("file:\"").substringBefore("\",")
|
||||||
|
M3u8Helper.generateM3u8(
|
||||||
|
source = this.name,
|
||||||
|
streamUrl = m3uLink,
|
||||||
|
referer = "https://ashdi.vip/"
|
||||||
|
).forEach(callback)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
data class Responses(
|
||||||
|
val success: Boolean?,
|
||||||
|
val response: String,
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
|
@ -1,13 +1,14 @@
|
||||||
package com.example
|
|
||||||
|
package com.lagradost
|
||||||
|
|
||||||
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
|
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
|
||||||
import com.lagradost.cloudstream3.plugins.Plugin
|
import com.lagradost.cloudstream3.plugins.Plugin
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
|
||||||
@CloudstreamPlugin
|
@CloudstreamPlugin
|
||||||
class TestPlugin: Plugin() {
|
class UakinoProviderPlugin: Plugin() {
|
||||||
override fun load(context: Context) {
|
override fun load(context: Context) {
|
||||||
// All providers should be added in this manner. Please don't edit the providers list directly.
|
// All providers should be added in this manner. Please don't edit the providers list directly.
|
||||||
registerMainAPI(ExampleProvider())
|
registerMainAPI(UakinoProvider())
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -37,15 +37,15 @@ subprojects {
|
||||||
cloudstream {
|
cloudstream {
|
||||||
// when running through github workflow, GITHUB_REPOSITORY should contain current repository name
|
// when running through github workflow, GITHUB_REPOSITORY should contain current repository name
|
||||||
// you can modify it to use other git hosting services, like gitlab
|
// you can modify it to use other git hosting services, like gitlab
|
||||||
setRepo(System.getenv("GITHUB_REPOSITORY") ?: "https://github.com/user/repo")
|
setRepo(System.getenv("GITHUB_REPOSITORY") ?: "https://github.com/CakesTwix/cloudstream-extensions-uk")
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion(30)
|
compileSdkVersion(33)
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdk = 21
|
minSdk = 21
|
||||||
targetSdk = 30
|
targetSdk = 33
|
||||||
}
|
}
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
|
@ -77,7 +77,7 @@ subprojects {
|
||||||
// https://github.com/recloudstream/cloudstream/blob/master/app/build.gradle
|
// https://github.com/recloudstream/cloudstream/blob/master/app/build.gradle
|
||||||
implementation(kotlin("stdlib")) // adds standard kotlin features, like listOf, mapOf etc
|
implementation(kotlin("stdlib")) // adds standard kotlin features, like listOf, mapOf etc
|
||||||
implementation("com.github.Blatzar:NiceHttp:0.3.2") // http library
|
implementation("com.github.Blatzar:NiceHttp:0.3.2") // http library
|
||||||
implementation("org.jsoup:jsoup:1.13.1") // html parser
|
implementation("org.jsoup:jsoup:1.15.1") // html parser
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue