sora: added Animetosho

This commit is contained in:
hexated 2023-08-21 07:55:21 +07:00
parent 3d60b9c792
commit 83e2c399f6
5 changed files with 100 additions and 70 deletions

View file

@ -1,7 +1,7 @@
import org.jetbrains.kotlin.konan.properties.Properties
// use an integer for version numbers
version = 158
version = 159
android {
defaultConfig {

View file

@ -17,6 +17,7 @@ import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody.Companion.toRequestBody
import org.jsoup.Jsoup
import org.jsoup.nodes.Document
import org.jsoup.select.Elements
val session = Session(Requests().baseClient)
@ -968,10 +969,10 @@ object SoraExtractor : SoraStream() {
argamap(
{
invokeAniwatch(malId, episode, subtitleCallback, callback)
invokeAnimetosho(malId, season, episode, subtitleCallback, callback)
},
{
invokeBiliBili(aniId, episode, subtitleCallback, callback)
invokeAniwatch(malId, episode, subtitleCallback, callback)
},
{
if (season != null) invokeCrunchyroll(
@ -987,54 +988,55 @@ object SoraExtractor : SoraStream() {
)
}
private suspend fun invokeBiliBili(
aniId: Int? = null,
private suspend fun invokeAnimetosho(
malId: Int? = null,
season: Int? = null,
episode: Int? = null,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
val res = app.get(
"$biliBiliAPI/anime/episodes?id=${aniId ?: return}&source_id=bilibili",
referer = otakuzBaseUrl
fun Elements.getLinks(): List<Triple<String, String, Int>> {
return this.flatMap { ele ->
ele.select("div.links a:matches(KrakenFiles|GoFile)").map {
Triple(
it.attr("href"),
ele.select("div.size").text(),
getIndexQuality(ele.select("div.link a").text())
)
.parsedSafe<BiliBiliDetails>()?.episodes?.find {
it.episodeNumber == episode
} ?: return
}
}
}
val sources =
app.get(
"$biliBiliAPI/source?episode_id=${res.sourceEpisodeId}&source_media_id=${res.sourceMediaId}&source_id=${res.sourceId}",
referer = otakuzBaseUrl
)
.parsedSafe<BiliBiliSourcesResponse>()
val (seasonSLug, episodeSlug) = getEpisodeSlug(season, episode)
val jikan = app.get("$jikanAPI/anime/$malId/full").parsedSafe<JikanResponse>()?.data
val aniId = jikan?.external?.find { it.name == "AniDB" }?.url?.substringAfterLast("=")
val res = app.get("$animetoshoAPI/series/${jikan?.title?.createSlug()}.$aniId?filter[0][t]=nyaa_class&filter[0][v]=trusted").document
sources?.sources?.apmap { source ->
val quality =
app.get(
source.file ?: return@apmap null,
referer = otakuzBaseUrl
).document.selectFirst("Representation")
?.attr("height")
val servers = if (season == null) {
res.select("div.home_list_entry:has(div.links)").getLinks()
} else {
res.select("div.home_list_entry:has(div.link a:matches([\\.\\s]$episodeSlug[\\.\\s]|S${seasonSLug}E$episodeSlug))")
.getLinks()
}
servers.filter { it.third in arrayOf(Qualities.P1080.value,Qualities.P720.value) }.apmap {
loadExtractor(it.first, "$animetoshoAPI/", subtitleCallback) { link ->
callback.invoke(
ExtractorLink(
"BiliBili",
"BiliBili",
source.file,
"",
quality?.toIntOrNull() ?: Qualities.Unknown.value,
isDash = true
link.source,
"${link.name} [${it.second}]",
link.url,
link.referer,
when {
link.isM3u8 -> link.quality
else -> it.third
},
link.isM3u8,
link.headers,
link.extractorData
)
)
}
sources?.subtitles?.map { sub ->
subtitleCallback.invoke(
SubtitleFile(
SubtitleHelper.fromTwoLettersToLanguage(sub.lang ?: "") ?: sub.language
?: return@map null,
sub.file ?: return@map null
)
)
}
}
@ -2209,7 +2211,7 @@ object SoraExtractor : SoraStream() {
"$dahmerMoviesAPI/tvs/${title?.replace(":", " -")}/Season $season/"
}
val request = app.get(url)
val request = app.get(url, timeout = 120L)
if (!request.isSuccessful) return
val paths = request.document.select("a").map {
it.text() to it.attr("href")
@ -2239,6 +2241,33 @@ object SoraExtractor : SoraStream() {
}
suspend fun invoke2embed(
imdbId: String?,
season: Int?,
episode: Int?,
callback: (ExtractorLink) -> Unit
) {
val server = "https://stream.2embed.cc"
val url = if(season == null) {
"$twoEmbedAPI/embed/$imdbId"
} else {
"$twoEmbedAPI/embedtv/$imdbId&s=$season&e=$episode"
}
val iframesrc = app.get(url).document.selectFirst("iframe#iframesrc")?.attr("src")
val framesrc = app.get(fixUrl(iframesrc ?: return, twoEmbedAPI)).document.selectFirst("iframe#framesrc")?.attr("src")
val video = app.get(fixUrl(framesrc ?: return, "$server/e/")).text.let {
Regex("file:\\s*\"(.*?m3u8.*?)\"").find(it)?.groupValues?.getOrNull(1)
}
M3u8Helper.generateM3u8(
"2embed",
video ?: return,
"$server/",
).forEach(callback)
}
suspend fun invokePrimewire(
title: String? = null,
year: Int? = null,

View file

@ -177,32 +177,18 @@ data class IndexSearch(
@JsonProperty("data") val data: IndexData? = null,
)
data class BiliBiliEpisodes(
@JsonProperty("id") val id: Int? = null,
@JsonProperty("sourceId") val sourceId: String? = null,
@JsonProperty("sourceEpisodeId") val sourceEpisodeId: String? = null,
@JsonProperty("sourceMediaId") val sourceMediaId: String? = null,
@JsonProperty("episodeNumber") val episodeNumber: Int? = null,
data class JikanExternal(
@JsonProperty("name") val name: String? = null,
@JsonProperty("url") val url: String? = null,
)
data class BiliBiliDetails(
@JsonProperty("episodes") val episodes: ArrayList<BiliBiliEpisodes>? = arrayListOf(),
data class JikanData(
@JsonProperty("title") val title: String? = null,
@JsonProperty("external") val external: ArrayList<JikanExternal>? = arrayListOf(),
)
data class BiliBiliSubtitles(
@JsonProperty("file") val file: String? = null,
@JsonProperty("lang") val lang: String? = null,
@JsonProperty("language") val language: String? = null,
)
data class BiliBiliSources(
@JsonProperty("file") val file: String? = null,
@JsonProperty("type") val type: String? = null,
)
data class BiliBiliSourcesResponse(
@JsonProperty("sources") val sources: ArrayList<BiliBiliSources>? = arrayListOf(),
@JsonProperty("subtitles") val subtitles: ArrayList<BiliBiliSubtitles>? = arrayListOf(),
data class JikanResponse(
@JsonProperty("data") val data: JikanData? = null,
)
data class WatchOnlineItems(

View file

@ -1,6 +1,7 @@
package com.hexated
import com.fasterxml.jackson.annotation.JsonProperty
import com.hexated.SoraExtractor.invoke2embed
import com.hexated.SoraExtractor.invokeAnimes
import com.hexated.SoraExtractor.invokeAsk4Movies
import com.hexated.SoraExtractor.invokeBollyMaza
@ -80,11 +81,13 @@ open class SoraStream : TmdbProvider() {
const val anilistAPI = "https://graphql.anilist.co"
const val malsyncAPI = "https://api.malsync.moe"
const val consumetHelper = "https://api.consumet.org/anime/9anime/helper"
const val jikanAPI = "https://api.jikan.moe/v4"
private val apiKey =
base64DecodeAPI("ZTM=NTg=MjM=MjM=ODc=MzI=OGQ=MmE=Nzk=Nzk=ZjI=NTA=NDY=NDA=MzA=YjA=") // PLEASE DON'T STEAL
/** ALL SOURCES */
const val twoEmbedAPI = "https://www.2embed.cc"
const val vidSrcAPI = "https://v2.vidsrc.me"
const val dbgoAPI = "https://dbgo.fun"
const val movieHabAPI = "https://moviehab.com"
@ -113,7 +116,6 @@ open class SoraStream : TmdbProvider() {
const val smashyStreamAPI = "https://embed.smashystream.com"
const val watchSomuchAPI = "https://watchsomuch.tv" // sub only
const val ask4MoviesAPI = "https://ask4movie.nl"
const val biliBiliAPI = "https://api-vn.otakuz.live/server"
const val watchOnlineAPI = "https://watchonline.ag"
const val nineTvAPI = "https://moviesapi.club"
const val putlockerAPI = "https://ww7.putlocker.vip"
@ -132,6 +134,7 @@ open class SoraStream : TmdbProvider() {
const val primewireAPI = "https://real-primewire.club"
const val vidsrctoAPI = "https://vidsrc.to"
const val dramadayAPI = "https://dramaday.me"
const val animetoshoAPI = "https://animetosho.org"
// INDEX SITE
const val dahmerMoviesAPI = "https://edytjedhgmdhm.abfhaqrhbnf.workers.dev"
@ -739,7 +742,10 @@ open class SoraStream : TmdbProvider() {
subtitleCallback,
callback
)
}
},
{
if(!res.isAnime) invoke2embed(res.imdbId,res.season,res.episode,callback)
},
)
return true

View file

@ -1,5 +1,6 @@
package com.hexated
import com.hexated.SoraExtractor.invoke2embed
import com.hexated.SoraExtractor.invokeAnimes
import com.hexated.SoraExtractor.invokeAsk4Movies
import com.hexated.SoraExtractor.invokeDbgo
@ -355,7 +356,15 @@ class SoraStreamLite : SoraStream() {
subtitleCallback,
callback
)
}
},
{
if(!res.isAnime) invoke2embed(
res.imdbId,
res.season,
res.episode,
callback
)
},
)
return true