unimay: Ukrainian DUB Anime ^_^
This commit is contained in:
parent
65a1c79b25
commit
13be499110
6 changed files with 304 additions and 0 deletions
25
UnimayProvider/build.gradle.kts
Normal file
25
UnimayProvider/build.gradle.kts
Normal file
|
@ -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%"
|
||||||
|
}
|
2
UnimayProvider/src/main/AndroidManifest.xml
Normal file
2
UnimayProvider/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest package="com.lagradost"/>
|
160
UnimayProvider/src/main/kotlin/com/lagradost/UnimayProvider.kt
Normal file
160
UnimayProvider/src/main/kotlin/com/lagradost/UnimayProvider.kt
Normal file
|
@ -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>()!!.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<SearchResponse> {
|
||||||
|
return app.get("$findUrl$query&page=1").parsedSafe<Releases>()!!.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<SearchModel>()!!
|
||||||
|
// 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<SearchModel>()!!
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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())
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
package com.lagradost.models
|
||||||
|
|
||||||
|
data class Releases(
|
||||||
|
|
||||||
|
val titleCount : Int,
|
||||||
|
val releases : List<Release>
|
||||||
|
)
|
||||||
|
|
||||||
|
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
|
||||||
|
)
|
|
@ -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<String>,
|
||||||
|
val playlist : List<Playlist>,
|
||||||
|
val playlistSize : Int,
|
||||||
|
val actors : List<Actors>,
|
||||||
|
val translators : List<Translators>,
|
||||||
|
val soundmans : List<Soundmans>,
|
||||||
|
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
|
||||||
|
)
|
Loading…
Reference in a new issue