Skip to content

Commit 3c152e0

Browse files
authored
Support showing content ratings for TmdbProvider (#705)
* Support showing content ratings for TmdbProvider
1 parent d0aed5e commit 3c152e0

File tree

7 files changed

+213
-5
lines changed

7 files changed

+213
-5
lines changed

app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt

Lines changed: 161 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1193,6 +1193,7 @@ interface LoadResponse {
11931193
var syncData: MutableMap<String, String>
11941194
var posterHeaders: Map<String, String>?
11951195
var backgroundPosterUrl: String?
1196+
var contentRating: String?
11961197

11971198
companion object {
11981199
private val malIdPrefix = malApi.idPrefix
@@ -1511,7 +1512,37 @@ data class TorrentLoadResponse(
15111512
override var syncData: MutableMap<String, String> = mutableMapOf(),
15121513
override var posterHeaders: Map<String, String>? = null,
15131514
override var backgroundPosterUrl: String? = null,
1514-
) : LoadResponse
1515+
override var contentRating: String? = null,
1516+
) : LoadResponse {
1517+
/**
1518+
* Secondary constructor for backwards compatibility without contentRating.
1519+
* Remove this constructor after there is a new stable release and extensions are updated to support contentRating.
1520+
*/
1521+
constructor(
1522+
name: String,
1523+
url: String,
1524+
apiName: String,
1525+
magnet: String?,
1526+
torrent: String?,
1527+
plot: String?,
1528+
type: TvType = TvType.Torrent,
1529+
posterUrl: String? = null,
1530+
year: Int? = null,
1531+
rating: Int? = null,
1532+
tags: List<String>? = null,
1533+
duration: Int? = null,
1534+
trailers: MutableList<TrailerData> = mutableListOf(),
1535+
recommendations: List<SearchResponse>? = null,
1536+
actors: List<ActorData>? = null,
1537+
comingSoon: Boolean = false,
1538+
syncData: MutableMap<String, String> = mutableMapOf(),
1539+
posterHeaders: Map<String, String>? = null,
1540+
backgroundPosterUrl: String? = null,
1541+
) : this(
1542+
name, url, apiName, magnet, torrent, plot, type, posterUrl, year, rating, tags, duration, trailers,
1543+
recommendations, actors, comingSoon, syncData, posterHeaders, backgroundPosterUrl, null
1544+
)
1545+
}
15151546

15161547
data class AnimeLoadResponse(
15171548
var engName: String? = null,
@@ -1542,6 +1573,7 @@ data class AnimeLoadResponse(
15421573
override var nextAiring: NextAiring? = null,
15431574
override var seasonNames: List<SeasonData>? = null,
15441575
override var backgroundPosterUrl: String? = null,
1576+
override var contentRating: String? = null,
15451577
) : LoadResponse, EpisodeResponse {
15461578
override fun getLatestEpisodes(): Map<DubStatus, Int?> {
15471579
return episodes.map { (status, episodes) ->
@@ -1559,6 +1591,41 @@ data class AnimeLoadResponse(
15591591
episodes.count { ((it.season ?: Int.MIN_VALUE) < season) && it.season != 0 }
15601592
} + episode
15611593
}
1594+
1595+
/**
1596+
* Secondary constructor for backwards compatibility without contentRating.
1597+
* Remove this constructor after there is a new stable release and extensions are updated to support contentRating.
1598+
*/
1599+
constructor(
1600+
engName: String? = null,
1601+
japName: String? = null,
1602+
name: String,
1603+
url: String,
1604+
apiName: String,
1605+
type: TvType,
1606+
posterUrl: String? = null,
1607+
year: Int? = null,
1608+
episodes: MutableMap<DubStatus, List<Episode>> = mutableMapOf(),
1609+
showStatus: ShowStatus? = null,
1610+
plot: String? = null,
1611+
tags: List<String>? = null,
1612+
synonyms: List<String>? = null,
1613+
rating: Int? = null,
1614+
duration: Int? = null,
1615+
trailers: MutableList<TrailerData> = mutableListOf(),
1616+
recommendations: List<SearchResponse>? = null,
1617+
actors: List<ActorData>? = null,
1618+
comingSoon: Boolean = false,
1619+
syncData: MutableMap<String, String> = mutableMapOf(),
1620+
posterHeaders: Map<String, String>? = null,
1621+
nextAiring: NextAiring? = null,
1622+
seasonNames: List<SeasonData>? = null,
1623+
backgroundPosterUrl: String? = null,
1624+
) : this(
1625+
engName, japName, name, url, apiName, type, posterUrl, year, episodes, showStatus, plot, tags,
1626+
synonyms, rating, duration, trailers, recommendations, actors, comingSoon, syncData, posterHeaders,
1627+
nextAiring, seasonNames, backgroundPosterUrl, null
1628+
)
15621629
}
15631630

15641631
/**
@@ -1610,7 +1677,36 @@ data class LiveStreamLoadResponse(
16101677
override var syncData: MutableMap<String, String> = mutableMapOf(),
16111678
override var posterHeaders: Map<String, String>? = null,
16121679
override var backgroundPosterUrl: String? = null,
1613-
) : LoadResponse
1680+
override var contentRating: String? = null,
1681+
) : LoadResponse {
1682+
/**
1683+
* Secondary constructor for backwards compatibility without contentRating.
1684+
* Remove this constructor after there is a new stable release and extensions are updated to support contentRating.
1685+
*/
1686+
constructor(
1687+
name: String,
1688+
url: String,
1689+
apiName: String,
1690+
dataUrl: String,
1691+
posterUrl: String? = null,
1692+
year: Int? = null,
1693+
plot: String? = null,
1694+
type: TvType = TvType.Live,
1695+
rating: Int? = null,
1696+
tags: List<String>? = null,
1697+
duration: Int? = null,
1698+
trailers: MutableList<TrailerData> = mutableListOf(),
1699+
recommendations: List<SearchResponse>? = null,
1700+
actors: List<ActorData>? = null,
1701+
comingSoon: Boolean = false,
1702+
syncData: MutableMap<String, String> = mutableMapOf(),
1703+
posterHeaders: Map<String, String>? = null,
1704+
backgroundPosterUrl: String? = null,
1705+
) : this(
1706+
name, url, apiName, dataUrl, posterUrl, year, plot, type, rating, tags, duration, trailers,
1707+
recommendations, actors, comingSoon, syncData, posterHeaders, backgroundPosterUrl, null
1708+
)
1709+
}
16141710

16151711
data class MovieLoadResponse(
16161712
override var name: String,
@@ -1633,7 +1729,36 @@ data class MovieLoadResponse(
16331729
override var syncData: MutableMap<String, String> = mutableMapOf(),
16341730
override var posterHeaders: Map<String, String>? = null,
16351731
override var backgroundPosterUrl: String? = null,
1636-
) : LoadResponse
1732+
override var contentRating: String? = null,
1733+
) : LoadResponse {
1734+
/**
1735+
* Secondary constructor for backwards compatibility without contentRating.
1736+
* Remove this constructor after there is a new stable release and extensions are updated to support contentRating.
1737+
*/
1738+
constructor(
1739+
name: String,
1740+
url: String,
1741+
apiName: String,
1742+
type: TvType,
1743+
dataUrl: String,
1744+
posterUrl: String? = null,
1745+
year: Int? = null,
1746+
plot: String? = null,
1747+
rating: Int? = null,
1748+
tags: List<String>? = null,
1749+
duration: Int? = null,
1750+
trailers: MutableList<TrailerData> = mutableListOf(),
1751+
recommendations: List<SearchResponse>? = null,
1752+
actors: List<ActorData>? = null,
1753+
comingSoon: Boolean = false,
1754+
syncData: MutableMap<String, String> = mutableMapOf(),
1755+
posterHeaders: Map<String, String>? = null,
1756+
backgroundPosterUrl: String? = null,
1757+
) : this(
1758+
name, url, apiName, type, dataUrl, posterUrl, year, plot, rating, tags, duration, trailers,
1759+
recommendations, actors, comingSoon, syncData, posterHeaders, backgroundPosterUrl,null
1760+
)
1761+
}
16371762

16381763
suspend fun <T> MainAPI.newMovieLoadResponse(
16391764
name: String,
@@ -1757,6 +1882,7 @@ data class TvSeriesLoadResponse(
17571882
override var nextAiring: NextAiring? = null,
17581883
override var seasonNames: List<SeasonData>? = null,
17591884
override var backgroundPosterUrl: String? = null,
1885+
override var contentRating: String? = null,
17601886
) : LoadResponse, EpisodeResponse {
17611887
override fun getLatestEpisodes(): Map<DubStatus, Int?> {
17621888
val maxSeason =
@@ -1773,6 +1899,38 @@ data class TvSeriesLoadResponse(
17731899
(it.season ?: Int.MIN_VALUE) < season && it.season != 0
17741900
} + episode
17751901
}
1902+
1903+
/**
1904+
* Secondary constructor for backwards compatibility without contentRating.
1905+
* Remove this constructor after there is a new stable release and extensions are updated to support contentRating.
1906+
*/
1907+
constructor(
1908+
name: String,
1909+
url: String,
1910+
apiName: String,
1911+
type: TvType,
1912+
episodes: List<Episode>,
1913+
posterUrl: String? = null,
1914+
year: Int? = null,
1915+
plot: String? = null,
1916+
showStatus: ShowStatus? = null,
1917+
rating: Int? = null,
1918+
tags: List<String>? = null,
1919+
duration: Int? = null,
1920+
trailers: MutableList<TrailerData> = mutableListOf(),
1921+
recommendations: List<SearchResponse>? = null,
1922+
actors: List<ActorData>? = null,
1923+
comingSoon: Boolean = false,
1924+
syncData: MutableMap<String, String> = mutableMapOf(),
1925+
posterHeaders: Map<String, String>? = null,
1926+
nextAiring: NextAiring? = null,
1927+
seasonNames: List<SeasonData>? = null,
1928+
backgroundPosterUrl: String? = null,
1929+
) : this(
1930+
name, url, apiName, type, episodes, posterUrl, year, plot, showStatus, rating, tags, duration,
1931+
trailers, recommendations, actors, comingSoon, syncData, posterHeaders, nextAiring, seasonNames,
1932+
backgroundPosterUrl, null
1933+
)
17761934
}
17771935

17781936
suspend fun MainAPI.newTvSeriesLoadResponse(

app/src/main/java/com/lagradost/cloudstream3/metaproviders/TmdbProvider.kt

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,8 @@ open class TmdbProvider : MainAPI() {
151151
recommendations = (this@toLoadResponse.recommendations
152152
?: this@toLoadResponse.similar)?.results?.map { it.toSearchResponse() }
153153
addActors(credits?.cast?.toList().toActors())
154+
155+
contentRating = fetchContentRating(id, "US")
154156
}
155157
}
156158

@@ -193,6 +195,8 @@ open class TmdbProvider : MainAPI() {
193195
recommendations = (this@toLoadResponse.recommendations
194196
?: this@toLoadResponse.similar)?.results?.map { it.toSearchResponse() }
195197
addActors(credits?.cast?.toList().toActors())
198+
199+
contentRating = fetchContentRating(id, "US")
196200
}
197201
}
198202

@@ -264,6 +268,26 @@ open class TmdbProvider : MainAPI() {
264268
return null
265269
}
266270

271+
open suspend fun fetchContentRating(id: Int?, country: String): String? {
272+
id ?: return null
273+
274+
val contentRatings = tmdb.tvService().content_ratings(id).awaitResponse().body()?.results
275+
return if (!contentRatings.isNullOrEmpty()) {
276+
contentRatings.firstOrNull { it: ContentRating ->
277+
it.iso_3166_1 == country
278+
}?.rating
279+
} else {
280+
val releaseDates = tmdb.moviesService().releaseDates(id).awaitResponse().body()?.results
281+
val certification = releaseDates?.firstOrNull { it: ReleaseDatesResult ->
282+
it.iso_3166_1 == country
283+
}?.release_dates?.firstOrNull { it: ReleaseDate ->
284+
!it.certification.isNullOrBlank()
285+
}?.certification
286+
287+
certification
288+
}
289+
}
290+
267291
// Possible to add recommendations and such here.
268292
override suspend fun load(url: String): LoadResponse? {
269293
// https://www.themoviedb.org/movie/7445-brothers

app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragmentPhone.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -677,6 +677,7 @@ open class ResultFragmentPhone : FullScreenPlayer() {
677677
resultMetaYear.setText(d.yearText)
678678
resultMetaDuration.setText(d.durationText)
679679
resultMetaRating.setText(d.ratingText)
680+
resultMetaContentRating.setText(d.contentRatingText)
680681
resultCastText.setText(d.actorsText)
681682
resultNextAiring.setText(d.nextAiringEpisode)
682683
resultNextAiringTime.setText(d.nextAiringDate)
@@ -701,6 +702,11 @@ open class ResultFragmentPhone : FullScreenPlayer() {
701702
resultCastItems.isGone = d.actors.isNullOrEmpty()
702703
(resultCastItems.adapter as? ActorAdaptor)?.updateList(d.actors ?: emptyList())
703704

705+
if (d.contentRatingText == null) {
706+
// If there is no rating to display, we don't want an empty gap
707+
resultMetaContentRating.width = 0
708+
}
709+
704710
if (syncModel.addSyncs(d.syncData)) {
705711
syncModel.updateMetaAndUser()
706712
syncModel.updateSynced()

app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragmentTv.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -826,6 +826,7 @@ class ResultFragmentTv : Fragment() {
826826
resultMetaYear.setText(d.yearText)
827827
resultMetaDuration.setText(d.durationText)
828828
resultMetaRating.setText(d.ratingText)
829+
resultMetaContentRating.setText(d.contentRatingText)
829830
resultCastText.setText(d.actorsText)
830831
resultNextAiring.setText(d.nextAiringEpisode)
831832
resultNextAiringTime.setText(d.nextAiringDate)
@@ -865,6 +866,11 @@ class ResultFragmentTv : Fragment() {
865866
(resultCastItems.adapter as? ActorAdaptor)?.updateList(
866867
d.actors ?: emptyList()
867868
)
869+
870+
if (d.contentRatingText == null) {
871+
// If there is no rating to display, we don't want an empty gap
872+
resultMetaContentRating.width = 0
873+
}
868874
}
869875

870876
is Resource.Loading -> {

app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultViewModel2.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ data class ResultData(
118118
val plotText: UiText,
119119
val apiName: UiText,
120120
val ratingText: UiText?,
121+
val contentRatingText: UiText?,
121122
val vpnText: UiText?,
122123
val metaText: UiText?,
123124
val durationText: UiText?,
@@ -249,6 +250,7 @@ fun LoadResponse.toResultData(repo: APIRepository): ResultData {
249250
apiName = txt(apiName),
250251
ratingText = rating?.div(1000f)
251252
?.let { if (it <= 0.1f) null else txt(R.string.rating_format, it) },
253+
contentRatingText = txt(contentRating),
252254
vpnText = txt(
253255
when (repo.vpnStatus) {
254256
VPNStatus.None -> null

app/src/main/res/layout/fragment_result.xml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -360,10 +360,16 @@
360360

361361
<com.google.android.material.button.MaterialButton
362362
android:id="@+id/result_meta_site"
363-
style="@style/SmallBlackButton"
364363
android:layout_gravity="center_vertical"
364+
style="@style/SmallBlackButton"
365365
tools:text="Gogoanime" />
366366

367+
<com.google.android.material.button.MaterialButton
368+
android:id="@+id/result_meta_content_rating"
369+
android:layout_gravity="center_vertical"
370+
style="@style/SmallBlackButton"
371+
tools:text="PG-13" />
372+
367373
<TextView
368374
android:id="@+id/result_meta_type"
369375
style="@style/ResultInfoText"

app/src/main/res/layout/fragment_result_tv.xml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -391,10 +391,16 @@ https://developer.android.com/design/ui/tv/samples/jet-fit
391391

392392
<com.google.android.material.button.MaterialButton
393393
android:id="@+id/result_meta_site"
394-
style="@style/SmallWhiteButton"
395394
android:layout_gravity="center_vertical"
395+
style="@style/SmallWhiteButton"
396396
tools:text="Gogoanime" />
397397

398+
<com.google.android.material.button.MaterialButton
399+
android:id="@+id/result_meta_content_rating"
400+
android:layout_gravity="center_vertical"
401+
style="@style/SmallWhiteButton"
402+
tools:text="PG-13" />
403+
398404
<TextView
399405
android:id="@+id/result_meta_type"
400406
style="@style/ResultInfoText"

0 commit comments

Comments
 (0)