Skip to content

Commit

Permalink
Support showing content ratings for TmdbProvider (#705)
Browse files Browse the repository at this point in the history
* Support showing content ratings for TmdbProvider
  • Loading branch information
Luna712 authored Dec 9, 2023
1 parent d0aed5e commit 3c152e0
Show file tree
Hide file tree
Showing 7 changed files with 213 additions and 5 deletions.
164 changes: 161 additions & 3 deletions app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt
Original file line number Diff line number Diff line change
Expand Up @@ -1193,6 +1193,7 @@ interface LoadResponse {
var syncData: MutableMap<String, String>
var posterHeaders: Map<String, String>?
var backgroundPosterUrl: String?
var contentRating: String?

companion object {
private val malIdPrefix = malApi.idPrefix
Expand Down Expand Up @@ -1511,7 +1512,37 @@ data class TorrentLoadResponse(
override var syncData: MutableMap<String, String> = mutableMapOf(),
override var posterHeaders: Map<String, String>? = null,
override var backgroundPosterUrl: String? = null,
) : LoadResponse
override var contentRating: String? = null,
) : LoadResponse {
/**
* Secondary constructor for backwards compatibility without contentRating.
* Remove this constructor after there is a new stable release and extensions are updated to support contentRating.
*/
constructor(
name: String,
url: String,
apiName: String,
magnet: String?,
torrent: String?,
plot: String?,
type: TvType = TvType.Torrent,
posterUrl: String? = null,
year: Int? = null,
rating: Int? = null,
tags: List<String>? = null,
duration: Int? = null,
trailers: MutableList<TrailerData> = mutableListOf(),
recommendations: List<SearchResponse>? = null,
actors: List<ActorData>? = null,
comingSoon: Boolean = false,
syncData: MutableMap<String, String> = mutableMapOf(),
posterHeaders: Map<String, String>? = null,
backgroundPosterUrl: String? = null,
) : this(
name, url, apiName, magnet, torrent, plot, type, posterUrl, year, rating, tags, duration, trailers,
recommendations, actors, comingSoon, syncData, posterHeaders, backgroundPosterUrl, null
)
}

data class AnimeLoadResponse(
var engName: String? = null,
Expand Down Expand Up @@ -1542,6 +1573,7 @@ data class AnimeLoadResponse(
override var nextAiring: NextAiring? = null,
override var seasonNames: List<SeasonData>? = null,
override var backgroundPosterUrl: String? = null,
override var contentRating: String? = null,
) : LoadResponse, EpisodeResponse {
override fun getLatestEpisodes(): Map<DubStatus, Int?> {
return episodes.map { (status, episodes) ->
Expand All @@ -1559,6 +1591,41 @@ data class AnimeLoadResponse(
episodes.count { ((it.season ?: Int.MIN_VALUE) < season) && it.season != 0 }
} + episode
}

/**
* Secondary constructor for backwards compatibility without contentRating.
* Remove this constructor after there is a new stable release and extensions are updated to support contentRating.
*/
constructor(
engName: String? = null,
japName: String? = null,
name: String,
url: String,
apiName: String,
type: TvType,
posterUrl: String? = null,
year: Int? = null,
episodes: MutableMap<DubStatus, List<Episode>> = mutableMapOf(),
showStatus: ShowStatus? = null,
plot: String? = null,
tags: List<String>? = null,
synonyms: List<String>? = null,
rating: Int? = null,
duration: Int? = null,
trailers: MutableList<TrailerData> = mutableListOf(),
recommendations: List<SearchResponse>? = null,
actors: List<ActorData>? = null,
comingSoon: Boolean = false,
syncData: MutableMap<String, String> = mutableMapOf(),
posterHeaders: Map<String, String>? = null,
nextAiring: NextAiring? = null,
seasonNames: List<SeasonData>? = null,
backgroundPosterUrl: String? = null,
) : this(
engName, japName, name, url, apiName, type, posterUrl, year, episodes, showStatus, plot, tags,
synonyms, rating, duration, trailers, recommendations, actors, comingSoon, syncData, posterHeaders,
nextAiring, seasonNames, backgroundPosterUrl, null
)
}

/**
Expand Down Expand Up @@ -1610,7 +1677,36 @@ data class LiveStreamLoadResponse(
override var syncData: MutableMap<String, String> = mutableMapOf(),
override var posterHeaders: Map<String, String>? = null,
override var backgroundPosterUrl: String? = null,
) : LoadResponse
override var contentRating: String? = null,
) : LoadResponse {
/**
* Secondary constructor for backwards compatibility without contentRating.
* Remove this constructor after there is a new stable release and extensions are updated to support contentRating.
*/
constructor(
name: String,
url: String,
apiName: String,
dataUrl: String,
posterUrl: String? = null,
year: Int? = null,
plot: String? = null,
type: TvType = TvType.Live,
rating: Int? = null,
tags: List<String>? = null,
duration: Int? = null,
trailers: MutableList<TrailerData> = mutableListOf(),
recommendations: List<SearchResponse>? = null,
actors: List<ActorData>? = null,
comingSoon: Boolean = false,
syncData: MutableMap<String, String> = mutableMapOf(),
posterHeaders: Map<String, String>? = null,
backgroundPosterUrl: String? = null,
) : this(
name, url, apiName, dataUrl, posterUrl, year, plot, type, rating, tags, duration, trailers,
recommendations, actors, comingSoon, syncData, posterHeaders, backgroundPosterUrl, null
)
}

data class MovieLoadResponse(
override var name: String,
Expand All @@ -1633,7 +1729,36 @@ data class MovieLoadResponse(
override var syncData: MutableMap<String, String> = mutableMapOf(),
override var posterHeaders: Map<String, String>? = null,
override var backgroundPosterUrl: String? = null,
) : LoadResponse
override var contentRating: String? = null,
) : LoadResponse {
/**
* Secondary constructor for backwards compatibility without contentRating.
* Remove this constructor after there is a new stable release and extensions are updated to support contentRating.
*/
constructor(
name: String,
url: String,
apiName: String,
type: TvType,
dataUrl: String,
posterUrl: String? = null,
year: Int? = null,
plot: String? = null,
rating: Int? = null,
tags: List<String>? = null,
duration: Int? = null,
trailers: MutableList<TrailerData> = mutableListOf(),
recommendations: List<SearchResponse>? = null,
actors: List<ActorData>? = null,
comingSoon: Boolean = false,
syncData: MutableMap<String, String> = mutableMapOf(),
posterHeaders: Map<String, String>? = null,
backgroundPosterUrl: String? = null,
) : this(
name, url, apiName, type, dataUrl, posterUrl, year, plot, rating, tags, duration, trailers,
recommendations, actors, comingSoon, syncData, posterHeaders, backgroundPosterUrl,null
)
}

suspend fun <T> MainAPI.newMovieLoadResponse(
name: String,
Expand Down Expand Up @@ -1757,6 +1882,7 @@ data class TvSeriesLoadResponse(
override var nextAiring: NextAiring? = null,
override var seasonNames: List<SeasonData>? = null,
override var backgroundPosterUrl: String? = null,
override var contentRating: String? = null,
) : LoadResponse, EpisodeResponse {
override fun getLatestEpisodes(): Map<DubStatus, Int?> {
val maxSeason =
Expand All @@ -1773,6 +1899,38 @@ data class TvSeriesLoadResponse(
(it.season ?: Int.MIN_VALUE) < season && it.season != 0
} + episode
}

/**
* Secondary constructor for backwards compatibility without contentRating.
* Remove this constructor after there is a new stable release and extensions are updated to support contentRating.
*/
constructor(
name: String,
url: String,
apiName: String,
type: TvType,
episodes: List<Episode>,
posterUrl: String? = null,
year: Int? = null,
plot: String? = null,
showStatus: ShowStatus? = null,
rating: Int? = null,
tags: List<String>? = null,
duration: Int? = null,
trailers: MutableList<TrailerData> = mutableListOf(),
recommendations: List<SearchResponse>? = null,
actors: List<ActorData>? = null,
comingSoon: Boolean = false,
syncData: MutableMap<String, String> = mutableMapOf(),
posterHeaders: Map<String, String>? = null,
nextAiring: NextAiring? = null,
seasonNames: List<SeasonData>? = null,
backgroundPosterUrl: String? = null,
) : this(
name, url, apiName, type, episodes, posterUrl, year, plot, showStatus, rating, tags, duration,
trailers, recommendations, actors, comingSoon, syncData, posterHeaders, nextAiring, seasonNames,
backgroundPosterUrl, null
)
}

suspend fun MainAPI.newTvSeriesLoadResponse(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@ open class TmdbProvider : MainAPI() {
recommendations = (this@toLoadResponse.recommendations
?: this@toLoadResponse.similar)?.results?.map { it.toSearchResponse() }
addActors(credits?.cast?.toList().toActors())

contentRating = fetchContentRating(id, "US")
}
}

Expand Down Expand Up @@ -193,6 +195,8 @@ open class TmdbProvider : MainAPI() {
recommendations = (this@toLoadResponse.recommendations
?: this@toLoadResponse.similar)?.results?.map { it.toSearchResponse() }
addActors(credits?.cast?.toList().toActors())

contentRating = fetchContentRating(id, "US")
}
}

Expand Down Expand Up @@ -264,6 +268,26 @@ open class TmdbProvider : MainAPI() {
return null
}

open suspend fun fetchContentRating(id: Int?, country: String): String? {
id ?: return null

val contentRatings = tmdb.tvService().content_ratings(id).awaitResponse().body()?.results
return if (!contentRatings.isNullOrEmpty()) {
contentRatings.firstOrNull { it: ContentRating ->
it.iso_3166_1 == country
}?.rating
} else {
val releaseDates = tmdb.moviesService().releaseDates(id).awaitResponse().body()?.results
val certification = releaseDates?.firstOrNull { it: ReleaseDatesResult ->
it.iso_3166_1 == country
}?.release_dates?.firstOrNull { it: ReleaseDate ->
!it.certification.isNullOrBlank()
}?.certification

certification
}
}

// Possible to add recommendations and such here.
override suspend fun load(url: String): LoadResponse? {
// https://www.themoviedb.org/movie/7445-brothers
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -677,6 +677,7 @@ open class ResultFragmentPhone : FullScreenPlayer() {
resultMetaYear.setText(d.yearText)
resultMetaDuration.setText(d.durationText)
resultMetaRating.setText(d.ratingText)
resultMetaContentRating.setText(d.contentRatingText)
resultCastText.setText(d.actorsText)
resultNextAiring.setText(d.nextAiringEpisode)
resultNextAiringTime.setText(d.nextAiringDate)
Expand All @@ -701,6 +702,11 @@ open class ResultFragmentPhone : FullScreenPlayer() {
resultCastItems.isGone = d.actors.isNullOrEmpty()
(resultCastItems.adapter as? ActorAdaptor)?.updateList(d.actors ?: emptyList())

if (d.contentRatingText == null) {
// If there is no rating to display, we don't want an empty gap
resultMetaContentRating.width = 0
}

if (syncModel.addSyncs(d.syncData)) {
syncModel.updateMetaAndUser()
syncModel.updateSynced()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -826,6 +826,7 @@ class ResultFragmentTv : Fragment() {
resultMetaYear.setText(d.yearText)
resultMetaDuration.setText(d.durationText)
resultMetaRating.setText(d.ratingText)
resultMetaContentRating.setText(d.contentRatingText)
resultCastText.setText(d.actorsText)
resultNextAiring.setText(d.nextAiringEpisode)
resultNextAiringTime.setText(d.nextAiringDate)
Expand Down Expand Up @@ -865,6 +866,11 @@ class ResultFragmentTv : Fragment() {
(resultCastItems.adapter as? ActorAdaptor)?.updateList(
d.actors ?: emptyList()
)

if (d.contentRatingText == null) {
// If there is no rating to display, we don't want an empty gap
resultMetaContentRating.width = 0
}
}

is Resource.Loading -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ data class ResultData(
val plotText: UiText,
val apiName: UiText,
val ratingText: UiText?,
val contentRatingText: UiText?,
val vpnText: UiText?,
val metaText: UiText?,
val durationText: UiText?,
Expand Down Expand Up @@ -249,6 +250,7 @@ fun LoadResponse.toResultData(repo: APIRepository): ResultData {
apiName = txt(apiName),
ratingText = rating?.div(1000f)
?.let { if (it <= 0.1f) null else txt(R.string.rating_format, it) },
contentRatingText = txt(contentRating),
vpnText = txt(
when (repo.vpnStatus) {
VPNStatus.None -> null
Expand Down
8 changes: 7 additions & 1 deletion app/src/main/res/layout/fragment_result.xml
Original file line number Diff line number Diff line change
Expand Up @@ -360,10 +360,16 @@

<com.google.android.material.button.MaterialButton
android:id="@+id/result_meta_site"
style="@style/SmallBlackButton"
android:layout_gravity="center_vertical"
style="@style/SmallBlackButton"
tools:text="Gogoanime" />

<com.google.android.material.button.MaterialButton
android:id="@+id/result_meta_content_rating"
android:layout_gravity="center_vertical"
style="@style/SmallBlackButton"
tools:text="PG-13" />

<TextView
android:id="@+id/result_meta_type"
style="@style/ResultInfoText"
Expand Down
8 changes: 7 additions & 1 deletion app/src/main/res/layout/fragment_result_tv.xml
Original file line number Diff line number Diff line change
Expand Up @@ -391,10 +391,16 @@ https://developer.android.com/design/ui/tv/samples/jet-fit

<com.google.android.material.button.MaterialButton
android:id="@+id/result_meta_site"
style="@style/SmallWhiteButton"
android:layout_gravity="center_vertical"
style="@style/SmallWhiteButton"
tools:text="Gogoanime" />

<com.google.android.material.button.MaterialButton
android:id="@+id/result_meta_content_rating"
android:layout_gravity="center_vertical"
style="@style/SmallWhiteButton"
tools:text="PG-13" />

<TextView
android:id="@+id/result_meta_type"
style="@style/ResultInfoText"
Expand Down

0 comments on commit 3c152e0

Please sign in to comment.