diff --git a/UnimayProvider/build.gradle.kts b/UnimayProvider/build.gradle.kts new file mode 100644 index 0000000..a9097e3 --- /dev/null +++ b/UnimayProvider/build.gradle.kts @@ -0,0 +1,25 @@ +// use an integer for version numbers +version = 1 + +cloudstream { + language = "uk" + // All of these properties are optional, you can safely remove them + + description = "Unimay Media є однією з провідних команд, що спеціалізується на локалізації та озвученні аніме для україномовної аудиторії." + 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", + "AnimeMovie", + ) + + iconUrl = "https://www.google.com/s2/favicons?domain=unimay.media&sz=%size%" +} \ No newline at end of file diff --git a/UnimayProvider/src/main/AndroidManifest.xml b/UnimayProvider/src/main/AndroidManifest.xml new file mode 100644 index 0000000..29aec9d --- /dev/null +++ b/UnimayProvider/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/UnimayProvider/src/main/kotlin/com/lagradost/UnimayProvider.kt b/UnimayProvider/src/main/kotlin/com/lagradost/UnimayProvider.kt new file mode 100644 index 0000000..716feaa --- /dev/null +++ b/UnimayProvider/src/main/kotlin/com/lagradost/UnimayProvider.kt @@ -0,0 +1,160 @@ +package com.lagradost + +import com.lagradost.cloudstream3.DubStatus +import com.lagradost.cloudstream3.Episode +import com.lagradost.cloudstream3.HomePageResponse +import com.lagradost.cloudstream3.LoadResponse +import com.lagradost.cloudstream3.LoadResponse.Companion.addAniListId +import com.lagradost.cloudstream3.MainAPI +import com.lagradost.cloudstream3.MainPageRequest +import com.lagradost.cloudstream3.SearchResponse +import com.lagradost.cloudstream3.ShowStatus +import com.lagradost.cloudstream3.SubtitleFile +import com.lagradost.cloudstream3.TvType +import com.lagradost.cloudstream3.addDubStatus +import com.lagradost.cloudstream3.addEpisodes +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.mainPageOf +import com.lagradost.cloudstream3.newAnimeLoadResponse +import com.lagradost.cloudstream3.newAnimeSearchResponse +import com.lagradost.cloudstream3.newHomePageResponse +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.M3u8Helper +import com.lagradost.cloudstream3.utils.Qualities +import com.lagradost.models.Releases +import com.lagradost.models.SearchModel + +class UnimayProvider : MainAPI() { + + // Basic Info + override var mainUrl = "https://www.unimay.media" + override var name = "Unimay" + override val hasMainPage = true + override var lang = "uk" + override val hasDownloadSupport = true + override val supportedTypes = setOf( + TvType.Anime, + TvType.AnimeMovie, + ) + + private val apiUrl = "https://api.unimay.media" + private val findUrl = "$apiUrl/api/release/search/?title=" + private val imagesUrl = "$apiUrl/storage/images/" + + // Sections + override val mainPage = mainPageOf( + "$apiUrl/api/release/all?page=" to "Останні релізи", + ) + + // Done + override suspend fun getMainPage( + page: Int, + request: MainPageRequest + ): HomePageResponse { + val homeList = app.get("${request.data}$page").parsedSafe()!!.releases.map{ + newAnimeSearchResponse(it.name, "$apiUrl/api/release/${it.code}", TvType.Anime) { + this.posterUrl = "$imagesUrl${it.imageId}" + addDubStatus("${it.playlistSize}/${it.episodes}", it.playlistSize) + } + } + + return newHomePageResponse(request.name, homeList) + } + + override suspend fun search(query: String): List { + return app.get("$findUrl$query&page=1").parsedSafe()!!.releases.map{ + newAnimeSearchResponse(it.name, "$apiUrl/api/release/${it.code}", TvType.Anime) { + this.posterUrl = "$imagesUrl${it.imageId}" + addDubStatus("${it.playlistSize}/${it.episodes}", it.playlistSize) + } + } + } + + // Detailed information + override suspend fun load(url: String): LoadResponse { + val anime = app.get("$apiUrl/api/release/${url.substringAfterLast("/")}").parsedSafe()!! + // val anime = Gson().fromJson(app.get("$apiUrl/api/release/${url.substringAfterLast("/")}").text, SearchModel::class.java) + + val showStatus = when(anime.statusCode){ + 0 -> ShowStatus.Ongoing + else -> ShowStatus.Completed + + } + + val tvType = when(anime.type){ + "Фільм" -> TvType.AnimeMovie + "Телесеріал" -> TvType.Anime + else -> TvType.Anime + } + + + val episodes = anime.playlist.map{ + Episode( + "${anime.code}, ${it.number}", + it.title, + episode = it.number, + posterUrl = if(it.previewId != null) { "$imagesUrl${it.previewId}" } else null, + ) + } + + return newAnimeLoadResponse( + anime.name, + "$mainUrl/projects/${anime.code}", + tvType, + ) { + this.engName = anime.engName + this.posterUrl = "$imagesUrl${anime.posterId}" + this.tags = anime.genres + this.plot = anime.description + this.showStatus = showStatus + this.duration = anime.episodeLength + addEpisodes(DubStatus.Dubbed, episodes) + this.year = anime.year + addAniListId(anime.aniListId) + } + } + + // It works when I click to view the series + override suspend fun loadLinks( + data: String, + isCasting: Boolean, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit + ): Boolean { + // anime_id, episode number + val dataList = data.split(", ") + // Log.d("CakesTwix-Debug", dataList.toString()) + + val anime = app.get("$apiUrl/api/release/${dataList[0]}").parsedSafe()!! + // val anime = Gson().fromJson(app.get("$apiUrl/api/release/${dataList[0]}").text, SearchModel::class.java) + val episode = anime.playlist.first { it.number == dataList[1].toInt() } + + if (episode.playlist != null) { + M3u8Helper.generateM3u8( + source = "Unimay", + streamUrl = episode.playlist, + referer = "https://www.unimay.media" + ).forEach(callback) + return true + } + + if (episode.sd != null) { + callback(ExtractorLink(episode.sd,"Unimay", episode.sd, "https://www.unimay.media", + Qualities.P480.value, false)) + } + if (episode.hd != null) { + callback(ExtractorLink(episode.hd,"Unimay", episode.hd, "https://www.unimay.media", + Qualities.P720.value, false)) + } + if (episode.fhd != null) { + callback(ExtractorLink(episode.fhd,"Unimay", episode.fhd, "https://www.unimay.media", + Qualities.P1080.value, false)) + } + if (episode.qhd != null) { + callback(ExtractorLink(episode.qhd,"Unimay", episode.qhd, "https://www.unimay.media", + Qualities.P2160.value, false)) + } + + return true + } +} diff --git a/UnimayProvider/src/main/kotlin/com/lagradost/UnimayProviderPlugin.kt b/UnimayProvider/src/main/kotlin/com/lagradost/UnimayProviderPlugin.kt new file mode 100644 index 0000000..87368ab --- /dev/null +++ b/UnimayProvider/src/main/kotlin/com/lagradost/UnimayProviderPlugin.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 UnimayProviderPlugin: Plugin() { + override fun load(context: Context) { + // All providers should be added in this manner. Please don't edit the providers list directly. + registerMainAPI(UnimayProvider()) + } +} \ No newline at end of file diff --git a/UnimayProvider/src/main/kotlin/com/lagradost/models/Releases.kt b/UnimayProvider/src/main/kotlin/com/lagradost/models/Releases.kt new file mode 100644 index 0000000..d60d691 --- /dev/null +++ b/UnimayProvider/src/main/kotlin/com/lagradost/models/Releases.kt @@ -0,0 +1,23 @@ +package com.lagradost.models + +data class Releases( + + val titleCount : Int, + val releases : List +) + +data class Release ( + + val id : Int, + val imageId : Int, + val episodes : Int, + val playlistSize : Int, + val episodeLength : Int, + val year : Int, + val restricted : Boolean, + val code : String, + val description : String, + val name : String, + val season : String, + val statusCode : Int +) diff --git a/UnimayProvider/src/main/kotlin/com/lagradost/models/Search.kt b/UnimayProvider/src/main/kotlin/com/lagradost/models/Search.kt new file mode 100644 index 0000000..406aba2 --- /dev/null +++ b/UnimayProvider/src/main/kotlin/com/lagradost/models/Search.kt @@ -0,0 +1,81 @@ +package com.lagradost.models + +data class SearchModel ( + + val id : Int, + val aniListId : Int, + val episodes : Int, + val episodeLength : Int, + val year : Int, + val restricted : Boolean, + val active : Boolean, + val announce : String, + val code : String, + val tgCode : String, + val cdnCode : String, + val description : String, + val lastUpdate : Long, + val name : String, + val engName : String, + val trailer : String, + // https://api.unimay.media/api/release/suzume-locking-up-the-doors + // val trailerPlaylist : String?, + val timestamp : Long, + val season : String, + val type : String, + val posterId : Int, + val imageId : Int, + val genres : List, + val playlist : List, + val playlistSize : Int, + val actors : List, + val translators : List, + val soundmans : List, + val genresInString : String, + val statusCode : Int +) + +data class Actors ( + + val id : Int, + val firstName : String, + val lastName : String, + val nickName : String, + val city : String, + val avtarId : Int +) + +data class Playlist ( + + val id : Int, + val number : Int, + val title : String, + val preview : String?, + val previewId : Int?, + val sd : String?, + val hd : String?, + val fhd : String?, + val qhd : String?, + val playlist : String?, + val hidden : Boolean +) + +data class Soundmans ( + + val id : Int, + val firstName : String, + val lastName : String, + val nickName : String, + val city : String, + val avtarId : Int +) + +data class Translators ( + + val id : Int, + val firstName : String, + val lastName : String, + val nickName : String, + val city : String, + val avtarId : Int +) \ No newline at end of file