fix(en/aniplay): Subtitles not working fix (#593)

* fixed yuki subtitles and code cleanup

* version bump
This commit is contained in:
Josef František Straka 2025-01-26 19:48:21 +01:00 committed by GitHub
parent 94e89303be
commit 64432b056f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 39 additions and 153 deletions

View file

@ -2,7 +2,7 @@ ext {
extName = 'AniPlay'
extClass = '.AniPlay'
themePkg = 'anilist'
overrideVersionCode = 8
overrideVersionCode = 9
}
apply from: "$rootDir/common.gradle"

View file

@ -20,6 +20,7 @@ import eu.kanade.tachiyomi.util.parallelFlatMap
import eu.kanade.tachiyomi.util.parseAs
import kotlinx.serialization.SerializationException
import kotlinx.serialization.encodeToString
import okhttp3.Headers
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.Request
@ -245,97 +246,18 @@ class AniPlay : AniListAnimeHttpSource(), ConfigurableAnimeSource {
val responseString = response.body.string()
val sourcesString = extractSourcesList(responseString) ?: return emptyList()
Log.i("AniPlay", "${extra.source} $language -> $sourcesString")
when (extra.source.lowercase()) {
"yuki" -> {
return processEpisodeDataYuki(
EpisodeDataYuki(
source = extra.source,
language = language,
response = sourcesString.parseAs<VideoSourceResponseYuki>(),
),
)
}
"pahe" -> {
return processEpisodeDataPahe(
EpisodeDataPahe(
source = extra.source,
language = language,
response = sourcesString.parseAs<VideoSourceResponsePahe>(),
),
)
}
else -> {
return processEpisodeData(
EpisodeData(
source = extra.source,
language = language,
response = sourcesString.parseAs<VideoSourceResponse>(),
),
)
}
}
}
private fun processEpisodeDataYuki(episodeData: EpisodeDataYuki): List<Video> {
val defaultSource = episodeData.response.sources?.firstOrNull()
if (defaultSource == null) {
Log.e("AniPlay", "defaultSource is null (${episodeData.response})")
try {
return processEpisodeData(
EpisodeData(
source = extra.source,
language = language,
response = sourcesString.parseAs<VideoSourceResponse>(),
),
)
} catch (e: Exception) {
Log.e("AniPlay", "processEpisodeData Error (\"${extra.source} - $language\"): $e")
return emptyList()
}
val subtitles = episodeData.response.tracks
?.filter { it.kind?.lowercase() == "captions" }
?.map { Track(it.file, it.label ?: "Unknown") }
?: emptyList()
val serverName = getServerName(episodeData.source)
val typeName = getTypeName(episodeData.language).let {
if (it == "Sub" && subtitles.isNotEmpty()) "SoftSub" else it
}
try {
return playlistUtils.extractFromHls(
playlistUrl = defaultSource.url,
videoNameGen = { quality -> "$serverName - $quality - $typeName" },
subtitleList = subtitles,
)
} catch (e: Exception) {
Log.e("AniPlay", "processEpisodeDataYuki extractFromHls Error (\"$serverName - $typeName\"): $e")
}
return emptyList()
}
private fun processEpisodeDataPahe(episodeData: EpisodeDataPahe): List<Video> {
val defaultSource = episodeData.response.sources?.firstOrNull {
it.quality in listOf("default", "auto")
} ?: return emptyList()
val subtitles = episodeData.response.subtitles
?.filter { it.lang?.lowercase() != "thumbnails" }
?.filter { it.url.isNullOrEmpty().not() }
?.map { Track(it.url ?: throw Exception("To be null or not to be"), it.lang ?: "Unk") }
?: emptyList()
val serverName = getServerName(episodeData.source)
val typeName = when {
subtitles.isNotEmpty() -> "SoftSub"
else -> getTypeName(episodeData.language)
}
try {
return playlistUtils.extractFromHls(
playlistUrl = defaultSource.url,
videoNameGen = { quality -> "$serverName - $quality - $typeName" },
subtitleList = subtitles,
)
} catch (e: Exception) {
Log.e("AniPlay", "processEpisodeDataPahe extractFromHls Error (\"$serverName - $typeName\"): $e")
}
return emptyList()
}
private fun processEpisodeData(episodeData: EpisodeData): List<Video> {
@ -345,7 +267,7 @@ class AniPlay : AniListAnimeHttpSource(), ConfigurableAnimeSource {
val subtitles = episodeData.response.subtitles
?.filter { it.lang?.lowercase() != "thumbnails" }
?.map { Track(it.url, it.lang ?: "Unk") }
?.map { Track(it.url ?: throw Exception("episodeData.response.subtitles.url is null ($it)"), it.lang ?: "Unk") }
?: emptyList()
val serverName = getServerName(episodeData.source)
@ -355,11 +277,26 @@ class AniPlay : AniListAnimeHttpSource(), ConfigurableAnimeSource {
}
try {
return playlistUtils.extractFromHls(
playlistUrl = defaultSource.url,
videoNameGen = { quality -> "$serverName - $quality - $typeName" },
subtitleList = subtitles,
)
if (episodeData.response.headers != null && episodeData.response.headers.Referer?.startsWith("https://") == true) {
return playlistUtils.extractFromHls(
playlistUrl = defaultSource.url,
videoNameGen = { quality -> "$serverName - $quality - $typeName" },
subtitleList = subtitles,
masterHeadersGen = { baseHeaders: Headers, _: String ->
baseHeaders.newBuilder().apply {
set("Accept", "*/*")
set("Origin", baseUrl)
set("Referer", episodeData.response.headers.Referer)
}.build()
},
)
} else {
return playlistUtils.extractFromHls(
playlistUrl = defaultSource.url,
videoNameGen = { quality -> "$serverName - $quality - $typeName" },
subtitleList = subtitles,
)
}
} catch (e: Exception) {
Log.e("AniPlay", "processEpisodeData extractFromHls Error (\"$serverName - $typeName\"): $e")
}

View file

@ -31,68 +31,12 @@ data class EpisodeData(
@Serializable
data class VideoSourceResponse(
val sources: List<Source>?,
val subtitles: List<Subtitle>?,
) {
@Serializable
data class Source(
val url: String,
val quality: String?,
)
@Serializable
data class Subtitle(
val url: String,
val lang: String?,
)
}
// Provider Yuki
@Serializable
data class EpisodeDataYuki(
val source: String,
val language: String,
val response: VideoSourceResponseYuki,
)
@Serializable
data class VideoSourceResponseYuki(
val sources: List<Source>?,
val tracks: List<Subtitle>?,
val anilistID: Int?,
val malID: Int?,
) {
@Serializable
data class Source(
val url: String,
val type: String?,
)
@Serializable
data class Subtitle(
val file: String,
val label: String?,
val kind: String?,
val default: Boolean?,
)
}
// Provider Pahe
@Serializable
data class EpisodeDataPahe(
val source: String,
val language: String,
val response: VideoSourceResponsePahe,
)
@Serializable
data class VideoSourceResponsePahe(
val sources: List<Source>?,
val audio: List<Audio>?,
val intro: Timestamp?,
val outro: Timestamp?,
val subtitles: List<Subtitle>?,
val headers: Headers?,
) {
@Serializable
data class Source(
@ -119,6 +63,11 @@ data class VideoSourceResponsePahe(
val url: String?,
val lang: String?,
)
@Serializable
data class Headers(
val Referer: String?,
)
}
// Extra