feat(multisrc/pt): New source: AnimeSync (#1967)

This commit is contained in:
Claudemirovsky
2023-07-29 11:47:11 +00:00
committed by GitHub
parent db6c9eb905
commit bbceac567c
8 changed files with 143 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -0,0 +1,116 @@
package eu.kanade.tachiyomi.animeextension.pt.animesync
import eu.kanade.tachiyomi.animeextension.pt.animesync.extractors.BloggerExtractor
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.multisrc.dooplay.DooPlay
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.runBlocking
import okhttp3.Headers
import okhttp3.Response
import org.jsoup.nodes.Element
class AnimeSync : DooPlay(
"pt-BR",
"AnimeSync",
"https://animesync.org",
) {
// ============================== Popular ===============================
override fun popularAnimeSelector() = "div.imdbRating > article > a"
override fun popularAnimeRequest(page: Int) = GET("$baseUrl/animes")
// =============================== Search ===============================
override fun searchAnimeSelector() = "div.items > article.item"
override fun searchAnimeFromElement(element: Element) = popularAnimeFromElement(element)
// ============================== Filters ===============================
override fun genresListRequest() = GET("$baseUrl/generos/")
override fun genresListSelector() = "ul.generos li > a"
// ============================ Video Links =============================
override val prefQualityValues = arrayOf("360p", "720p", "1080p")
override val prefQualityEntries = prefQualityValues
override fun videoListParse(response: Response): List<Video> {
val document = response.asJsoup()
val players = document.select("ul#playeroptionsul li")
return players.parallelMap {
runCatching { getPlayerVideos(it) }.getOrElse { emptyList() }
}.flatten()
}
private fun getPlayerVideos(player: Element): List<Video> {
val url = getPlayerUrl(player)
return when {
url.contains("/jwplayer/") -> {
val doc = client.newCall(GET(url, headers)).execute()
.use { it.asJsoup() }
val source = doc.selectFirst("source") ?: return emptyList()
val quality = source.attr("size").ifEmpty { "360" } + "p"
val videoUrl = source.attr("src")
listOf(Video(videoUrl, "JWPlayer - $quality", videoUrl, headers))
}
url.contains("/player2/") -> {
val doc = client.newCall(GET(url, headers)).execute()
.use { it.asJsoup() }
doc.selectFirst("script:containsData(sources:)")
?.data()
?.substringAfter("sources: [")
?.substringBefore("]")
?.split("{")
?.drop(1)
.orEmpty()
.map {
val quality = it.substringAfter("label\":\"").substringBefore('"')
val videoUrl = it.substringAfter("file\":\"").substringBefore('"')
Video(videoUrl, "Player 2 - $quality", videoUrl, headers)
}
}
url.contains("/player/") -> {
BloggerExtractor(client).videosFromUrl(url, headers)
}
url.contains("csst.online") -> {
val doc = client.newCall(GET(url, headers)).execute()
.use { it.asJsoup() }
doc.selectFirst("script:containsData(isMobile):containsData(file:)")
?.data()
?.substringAfter("file:\"")
?.substringBefore('"')
?.split(",")
.orEmpty()
.map {
val quality = it.substringAfter("[").substringBefore("]")
val videoUrl = it.substringAfter("]")
val videoHeaders = Headers.Builder().add("Referer", videoUrl).build()
Video(videoUrl, "CSST - $quality", videoUrl, videoHeaders)
}
}
else -> emptyList()
}
}
private fun getPlayerUrl(player: Element): String {
val type = player.attr("data-type")
val id = player.attr("data-post")
val num = player.attr("data-nume")
return client.newCall(GET("$baseUrl/wp-json/dooplayer/v2/$id/$type/$num"))
.execute()
.body.string()
.substringAfter("\"embed_url\":\"")
.substringBefore("\",")
.replace("\\", "")
}
// ============================= Utilities ==============================
private inline fun <A, B> Iterable<A>.parallelMap(crossinline f: suspend (A) -> B): List<B> =
runBlocking {
map { async(Dispatchers.Default) { f(it) } }.awaitAll()
}
}

View File

@ -0,0 +1,26 @@
package eu.kanade.tachiyomi.animeextension.pt.animesync.extractors
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET
import okhttp3.Headers
import okhttp3.OkHttpClient
class BloggerExtractor(private val client: OkHttpClient) {
fun videosFromUrl(url: String, headers: Headers): List<Video> {
return client.newCall(GET(url)).execute()
.use { it.body.string() }
.substringAfter("\"streams\":[")
.substringBefore("]")
.split("},")
.map {
val url = it.substringAfter("{\"play_url\":\"").substringBefore('"')
val format = it.substringAfter("\"format_id\":").substringBefore("}")
val quality = when (format) {
"18" -> "360p"
"22" -> "720p"
else -> "Unknown"
}
Video(url, "Blogger - $quality", url, headers = headers)
}
}
}

View File

@ -14,6 +14,7 @@ class DooPlayGenerator : ThemeSourceGenerator {
SingleLang("AnimeOnline360", "https://animeonline360.me", "en", isNsfw = false), SingleLang("AnimeOnline360", "https://animeonline360.me", "en", isNsfw = false),
SingleLang("AnimeOnline.Ninja", "https://www1.animeonline.ninja", "es", className = "AnimeOnlineNinja", isNsfw = false, overrideVersionCode = 28), SingleLang("AnimeOnline.Ninja", "https://www1.animeonline.ninja", "es", className = "AnimeOnlineNinja", isNsfw = false, overrideVersionCode = 28),
SingleLang("AnimePlayer", "https://animeplayer.com.br", "pt-BR", isNsfw = true), SingleLang("AnimePlayer", "https://animeplayer.com.br", "pt-BR", isNsfw = true),
SingleLang("AnimeSync", "https://animesync.org", "pt-BR", isNsfw = true),
SingleLang("AnimesFox BR", "https://animesfox.net", "pt-BR", isNsfw = false, overrideVersionCode = 2), SingleLang("AnimesFox BR", "https://animesfox.net", "pt-BR", isNsfw = false, overrideVersionCode = 2),
SingleLang("Animes Grátis", "https://animesgratis.org", "pt-BR", className = "AnimesGratis", isNsfw = false, overrideVersionCode = 1), SingleLang("Animes Grátis", "https://animesgratis.org", "pt-BR", className = "AnimesGratis", isNsfw = false, overrideVersionCode = 1),
SingleLang("Animes House", "https://animeshouse.net", "pt-BR", isNsfw = false, overrideVersionCode = 5), SingleLang("Animes House", "https://animeshouse.net", "pt-BR", isNsfw = false, overrideVersionCode = 5),