fix(it/streamingcommunity): Fix empty videolist and change base domain (#3103)

Co-authored-by: Secozzi <49240133+Secozzi@users.noreply.github.com>
This commit is contained in:
Dark25 2024-03-29 17:08:36 +01:00 committed by GitHub
parent 59bfabf170
commit c2096dd1be
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 69 additions and 52 deletions

View File

@ -1,7 +1,7 @@
ext { ext {
extName = 'StreamingCommunity' extName = 'StreamingCommunity'
extClass = '.StreamingCommunity' extClass = '.StreamingCommunity'
extVersionCode = 3 extVersionCode = 4
} }
apply from: "$rootDir/common.gradle" apply from: "$rootDir/common.gradle"

View File

@ -17,6 +17,7 @@ import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
@ -29,14 +30,14 @@ class StreamingCommunity : ConfigurableAnimeSource, AnimeHttpSource() {
override val name = "StreamingCommunity" override val name = "StreamingCommunity"
// TODO: Check frequency of url changes to potentially override val baseUrl = "https://streamingcommunity.forum"
// add back overridable baseurl preference
override val baseUrl = "https://streamingcommunity.report"
override val lang = "it" override val lang = "it"
override val supportsLatest = true override val supportsLatest = true
override val client: OkHttpClient = network.client
private val json: Json by injectLazy() private val json: Json by injectLazy()
private val preferences: SharedPreferences by lazy { private val preferences: SharedPreferences by lazy {
@ -240,7 +241,7 @@ class StreamingCommunity : ConfigurableAnimeSource, AnimeHttpSource() {
SEpisode.create().apply { SEpisode.create().apply {
name = "Stagione ${season.number} episodio ${episode.number} - ${episode.name}" name = "Stagione ${season.number} episodio ${episode.number} - ${episode.name}"
episode_number = episode.number.toFloat() episode_number = episode.number.toFloat()
url = "${data.title.id}?e=${episode.id}" url = "${data.title.id}?episode_id=${episode.id}&next_episode=1"
}, },
) )
} }
@ -252,58 +253,65 @@ class StreamingCommunity : ConfigurableAnimeSource, AnimeHttpSource() {
// ============================ Video Links ============================= // ============================ Video Links =============================
override fun videoListRequest(episode: SEpisode): Request = GET("$baseUrl/watch/${episode.url}", headers) override suspend fun getVideoList(episode: SEpisode): List<Video> {
override fun videoListParse(response: Response): List<Video> {
val data = json.decodeFromString<VideoResponse>(response.asJsoup().getData())
val videoList = mutableListOf<Video>() val videoList = mutableListOf<Video>()
val doc =
val embedUrl = data.props.embedUrl client
val embedHeaders = headers.newBuilder() .newCall(
.add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8") GET("$baseUrl/iframe/${episode.url}", headers),
.add("Host", baseUrl.toHttpUrl().host) ).execute()
.add("Referer", response.request.url.toString()) .asJsoup()
.build() val iframeUrl =
doc.selectFirst("iframe[src]")?.attr("abs:src")
val embedded = client.newCall( ?: error("Failed to extract iframe")
GET(embedUrl, headers = embedHeaders), val iframeHeaders =
).execute().asJsoup() headers
.newBuilder()
val iframeUrl = embedded.selectFirst("iframe[src]")?.attr("abs:src") ?: error("Failed to load iframe")
val iframeHeaders = headers.newBuilder()
.add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8") .add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8")
.add("Host", iframeUrl.toHttpUrl().host) .add("Host", iframeUrl.toHttpUrl().host)
.add("Referer", "$baseUrl/") .add("Referer", "$baseUrl/")
.build() .build()
val iframe = client.newCall( val iframe =
client
.newCall(
GET(iframeUrl, headers = iframeHeaders), GET(iframeUrl, headers = iframeHeaders),
).execute().asJsoup() ).execute()
val script = iframe.selectFirst("script:containsData(masterPlaylistParams)")!!.data() .asJsoup()
val script = iframe.selectFirst("script:containsData(masterPlaylist)")!!.data().replace("\n", "\t")
var playlistUrl = PLAYLIST_URL_REGEX.find(script)!!.groupValues[1]
val filename = playlistUrl.substringAfterLast("/")
if (!filename.endsWith(".m3u8")) {
playlistUrl = playlistUrl.replace(filename, filename + ".m3u8")
}
val playlistUrl = Regex("""masterPlaylistUrl.*?'(.*?)'""").find(script)!!.groupValues[1] val expires = EXPIRES_REGEX.find(script)!!.groupValues[1]
val expires = Regex("""'expires': ?'(\d+)'""").find(script)!!.groupValues[1] val token = TOKEN_REGEX.find(script)!!.groupValues[1]
val canCast = Regex("""'canCast': ?'(\d*)'""").find(script)!!.groupValues[1]
val token = Regex("""'token': ?'([\w-]+)'""").find(script)!!.groupValues[1]
// Get subtitles // Get subtitles
val masterPlUrl = "$playlistUrl?token=$token&expires=$expires&canCast=$canCast&n=1" val masterPlUrl = "$playlistUrl?token=$token&expires=$expires&n=1"
val masterPl = client.newCall(GET(masterPlUrl)).execute().body.string() val masterPl =
val subList = Regex("""#EXT-X-MEDIA:TYPE=SUBTITLES.*?NAME="(.*?)".*?URI="(.*?)"""").findAll(masterPl).map { client
.newCall(GET(masterPlUrl))
.execute()
.body
.string()
val subList =
SUBTITLES_REGEX.findAll(masterPl)
.map {
Track(it.groupValues[2], it.groupValues[1]) Track(it.groupValues[2], it.groupValues[1])
}.toList() }.toList()
TOKEN_QUALITY_REGEX.findAll(script).forEach { match ->
Regex("""'token(\d+p?)': ?'([\w-]+)'""").findAll(script).forEach { match ->
val quality = match.groupValues[1] val quality = match.groupValues[1]
val videoUrl = buildString { val videoUrl =
buildString {
append(playlistUrl) append(playlistUrl)
append("?type=video&rendition=") append("?type=video&rendition=")
append(quality) append(quality)
append("&token=") append("&token=")
append(match.groupValues[2]) append(match.groupValues[2])
append("&expires=$expires") append("&expires=$expires")
append("&canCast=$canCast")
append("&n=1") append("&n=1")
} }
videoList.add(Video(videoUrl, quality, videoUrl, subtitleTracks = subList)) videoList.add(Video(videoUrl, quality, videoUrl, subtitleTracks = subList))
@ -314,6 +322,10 @@ class StreamingCommunity : ConfigurableAnimeSource, AnimeHttpSource() {
return videoList.sort() return videoList.sort()
} }
override fun videoListRequest(episode: SEpisode): Request = throw Exception("Not used")
override fun videoListParse(response: Response): List<Video> = throw Exception("Not used")
// ============================= Utilities ============================== // ============================= Utilities ==============================
private fun Document.getData(): String { private fun Document.getData(): String {
@ -344,6 +356,11 @@ class StreamingCommunity : ConfigurableAnimeSource, AnimeHttpSource() {
} }
companion object { companion object {
private val PLAYLIST_URL_REGEX = Regex("""url: ?'(.*?)'""")
private val EXPIRES_REGEX = Regex("""'expires': ?'(\d+)'""")
private val TOKEN_REGEX = Regex("""'token': ?'([\w-]+)'""")
private val TOKEN_QUALITY_REGEX = Regex("""'token(\d+p?)': ?'([\w-]+)'""")
private val SUBTITLES_REGEX = Regex("""#EXT-X-MEDIA:TYPE=SUBTITLES.*?NAME="(.*?)".*?URI="(.*?)"""")
private const val PREF_QUALITY_KEY = "preferred_quality" private const val PREF_QUALITY_KEY = "preferred_quality"
private const val PREF_QUALITY_DEFAULT = "720" private const val PREF_QUALITY_DEFAULT = "720"
} }