feat(Subtitles): SubSource subtitles provider (#1199)

This commit is contained in:
KingLucius 2024-07-15 18:15:59 +03:00 committed by GitHub
parent 694193fa3e
commit a157115cfa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 161 additions and 1 deletions

View file

@ -22,6 +22,7 @@ abstract class AccountManager(private val defIndex: Int) : AuthAPI {
val addic7ed = Addic7ed()
val subDlApi = SubDlApi(0)
val localListApi = LocalList()
val subSourceApi = SubSourceApi()
// used to login via app intent
val OAuth2Apis
@ -51,7 +52,8 @@ abstract class AccountManager(private val defIndex: Int) : AuthAPI {
get() = listOf(
openSubtitlesApi,
addic7ed,
subDlApi
subDlApi,
subSourceApi
)
const val appString = "cloudstreamapp"

View file

@ -0,0 +1,158 @@
package com.lagradost.cloudstream3.syncproviders.providers
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.TvType
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.subtitles.AbstractSubProvider
import com.lagradost.cloudstream3.subtitles.AbstractSubtitleEntities
import com.lagradost.cloudstream3.subtitles.SubtitleResource
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
import com.lagradost.cloudstream3.utils.AppUtils.toJson
import com.lagradost.cloudstream3.utils.SubtitleHelper
class SubSourceApi : AbstractSubProvider {
override val idPrefix = "subsource"
val name = "SubSource"
companion object {
const val APIURL = "https://api.subsource.net/api"
const val DOWNLOADENDPOINT = "https://api.subsource.net/api/downloadSub"
}
override suspend fun search(query: AbstractSubtitleEntities.SubtitleSearch): List<AbstractSubtitleEntities.SubtitleEntity>? {
//Only supports Imdb Id search for now
if (query.imdbId == null) return null
val queryLang = SubtitleHelper.fromTwoLettersToLanguage(query.lang!!)
val type = if ((query.seasonNumber ?: 0) > 0) TvType.TvSeries else TvType.Movie
val searchRes = app.post(
url = "$APIURL/searchMovie",
data = mapOf(
"query" to query.imdbId!!
)
).parsedSafe<ApiSearch>() ?: return null
val postData = if (type == TvType.TvSeries) {
mapOf(
"langs" to "[]",
"movieName" to searchRes.found.first().linkName,
"season" to "season-${query.seasonNumber}"
)
} else {
mapOf(
"langs" to "[]",
"movieName" to searchRes.found.first().linkName,
)
}
val getMovieRes = app.post(
url = "$APIURL/getMovie",
data = postData
).parsedSafe<ApiResponse>().let {
// api doesn't has episode number or lang filtering
if (type == TvType.Movie) {
it?.subs?.filter { sub ->
sub.lang == queryLang
}
} else {
it?.subs?.filter { sub ->
sub.releaseName!!.contains(
String.format(
"E%02d",
query.epNumber
)
) && sub.lang == queryLang
}
}
} ?: return null
return getMovieRes.map { subtitle ->
AbstractSubtitleEntities.SubtitleEntity(
idPrefix = this.idPrefix,
name = subtitle.releaseName!!,
lang = subtitle.lang!!,
data = SubData(
movie = subtitle.linkName!!,
lang = subtitle.lang,
id = subtitle.subId.toString(),
).toJson(),
type = type,
source = this.name,
epNumber = query.epNumber,
seasonNumber = query.seasonNumber,
isHearingImpaired = subtitle.hi == 1,
)
}
}
override suspend fun SubtitleResource.getResources(data: AbstractSubtitleEntities.SubtitleEntity) {
val parsedSub = parseJson<SubData>(data.data)
val subRes = app.post(
url = "$APIURL/getSub",
data = mapOf(
"movie" to parsedSub.movie,
"lang" to data.lang,
"id" to parsedSub.id
)
).parsedSafe<SubTitleLink>() ?: return
this.addZipUrl(
"$DOWNLOADENDPOINT/${subRes.sub.downloadToken}"
) { name, _ ->
name
}
}
data class ApiSearch(
@JsonProperty("success") val success: Boolean,
@JsonProperty("found") val found: List<Found>,
)
data class Found(
@JsonProperty("id") val id: Long,
@JsonProperty("title") val title: String,
@JsonProperty("seasons") val seasons: Long,
@JsonProperty("type") val type: String,
@JsonProperty("releaseYear") val releaseYear: Long,
@JsonProperty("linkName") val linkName: String,
)
data class ApiResponse(
@JsonProperty("success") val success: Boolean,
@JsonProperty("movie") val movie: Movie,
@JsonProperty("subs") val subs: List<Sub>,
)
data class Movie(
@JsonProperty("id") val id: Long? = null,
@JsonProperty("type") val type: String? = null,
@JsonProperty("year") val year: Long? = null,
@JsonProperty("fullName") val fullName: String? = null,
)
data class Sub(
@JsonProperty("hi") val hi: Int? = null,
@JsonProperty("fullLink") val fullLink: String? = null,
@JsonProperty("linkName") val linkName: String? = null,
@JsonProperty("lang") val lang: String? = null,
@JsonProperty("releaseName") val releaseName: String? = null,
@JsonProperty("subId") val subId: Long? = null,
)
data class SubData(
@JsonProperty("movie") val movie: String,
@JsonProperty("lang") val lang: String,
@JsonProperty("id") val id: String,
)
data class SubTitleLink(
@JsonProperty("sub") val sub: SubToken,
)
data class SubToken(
@JsonProperty("downloadToken") val downloadToken: String,
)
}