Skip to content

Commit

Permalink
Revisit BlockReasonException (#754)
Browse files Browse the repository at this point in the history
Co-authored-by: Gaëtan Muller <[email protected]>
  • Loading branch information
StaehliJ and MGaetan89 authored Oct 17, 2024
1 parent 4095e34 commit 44e14d7
Show file tree
Hide file tree
Showing 21 changed files with 492 additions and 125 deletions.
2 changes: 2 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ json = "20240303"
junit = "4.13.2"
kotlin = "2.0.21"
kotlinx-coroutines = "1.9.0"
kotlinx-datetime = "0.6.1"
kotlinx-kover = "0.8.3"
kotlinx-serialization = "1.7.3"
ktor = "3.0.0"
Expand Down Expand Up @@ -69,6 +70,7 @@ kotlin-gradle-plugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", v
kotlin-parcelize-runtime = { module = "org.jetbrains.kotlin:kotlin-parcelize-runtime", version.ref = "kotlin" }
kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin" }
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }
kotlinx-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "kotlinx-datetime" }
kotlinx-kover-gradle = { module = "org.jetbrains.kotlinx:kover-gradle-plugin", version.ref = "kotlinx-kover" }
kotlinx-serialization-core = { module = "org.jetbrains.kotlinx:kotlinx-serialization-core", version.ref = "kotlinx-serialization" }
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx-serialization" }
Expand Down
1 change: 1 addition & 0 deletions pillarbox-core-business/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ dependencies {
implementation(libs.guava)
runtimeOnly(libs.kotlinx.coroutines.android)
implementation(libs.kotlinx.coroutines.core)
api(libs.kotlinx.datetime)
api(libs.kotlinx.serialization.core)
implementation(libs.kotlinx.serialization.json)
implementation(libs.ktor.client.content.negotiation)
Expand Down
3 changes: 2 additions & 1 deletion pillarbox-core-business/docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ All exceptions thrown by [`PillarboxMediaSource`][pillarbox-media-source-source]
player.addListener(object : Player.Listener {
override fun onPlayerError(error: PlaybackException) {
when (val cause = error.cause) {
is BlockReasonException -> Log.d("Pillarbox", "Content blocked: ${cause.blockReason}")
is BlockReasonException.StartDate -> Log.d("Pillarbox", "Content is blocked until ${cause.instant}")
is BlockReasonException -> Log.d("Pillarbox", "Content is blocked", cause)
is ResourceNotFoundException -> Log.d("Pillarbox", "No resources found in the chapter")
else -> Log.d("Pillarbox", "An error occurred", cause)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import androidx.media3.datasource.DataSourceException
import ch.srgssr.pillarbox.core.business.exception.BlockReasonException
import ch.srgssr.pillarbox.core.business.exception.DataParsingException
import ch.srgssr.pillarbox.core.business.exception.ResourceNotFoundException
import ch.srgssr.pillarbox.core.business.extension.getString
import java.io.IOException

/**
Expand All @@ -23,7 +22,7 @@ class SRGErrorMessageProvider(private val context: Context) : ErrorMessageProvid
override fun getErrorMessage(throwable: PlaybackException): Pair<Int, String> {
return when (val cause = throwable.cause) {
is BlockReasonException -> {
Pair.create(0, context.getString(cause.blockReason))
Pair.create(0, context.getString(cause.messageResId))
}

is ResourceNotFoundException -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,95 @@
*/
package ch.srgssr.pillarbox.core.business.exception

import androidx.annotation.StringRes
import ch.srgssr.pillarbox.core.business.R
import ch.srgssr.pillarbox.core.business.integrationlayer.data.BlockReason
import ch.srgssr.pillarbox.core.business.integrationlayer.data.Chapter
import ch.srgssr.pillarbox.core.business.integrationlayer.data.Segment
import kotlinx.datetime.Instant
import java.io.IOException

/**
* Block reason exception
*
* @property blockReason the reason a [Chapter] or a [Segment] is blocked.
*/
class BlockReasonException(val blockReason: BlockReason) : IOException(blockReason.name) {
/*
* ExoPlaybackException bundles cause exception with class name and message.
* In order to recreate the cause of the throwable, it needs a throwable class with constructor(string).
*/
internal constructor(message: String) : this(parseMessage(message))

private companion object {
@Suppress("SwallowedException")
private fun parseMessage(message: String): BlockReason {
return try {
enumValueOf(message)
} catch (e: IllegalArgumentException) {
BlockReason.UNKNOWN
}
}
sealed class BlockReasonException(message: String) : IOException(message) {
/**
* The Android resource id of the message to display.
*/
@StringRes
open val messageResId: Int = R.string.blockReason_unknown

private constructor(blockReason: BlockReason) : this(blockReason.name)

/**
* [BlockReasonException] when [Chapter.blockReason] is [BlockReason.STARTDATE].
*
* @property instant The [Instant] when the content will be available.
*/
class StartDate(val instant: Instant?) : BlockReasonException(BlockReason.STARTDATE) {
override val messageResId: Int
get() = R.string.blockReason_startDate
}

/**
* [BlockReasonException] when [Chapter.blockReason] is [BlockReason.ENDDATE].
*
* @property instant The [Instant] since it is unavailable.
*/
class EndDate(val instant: Instant?) : BlockReasonException(BlockReason.ENDDATE) {
override val messageResId: Int
get() = R.string.blockReason_endDate
}

/**
* [BlockReasonException] when [Chapter.blockReason] is [BlockReason.LEGAL].
*/
class Legal : BlockReasonException(BlockReason.LEGAL) {
override val messageResId: Int
get() = R.string.blockReason_legal
}

/**
* [BlockReasonException] when [Chapter.blockReason] is [BlockReason.AGERATING18].
*/
class AgeRating18 : BlockReasonException(BlockReason.AGERATING18) {
override val messageResId: Int
get() = R.string.blockReason_ageRating18
}

/**
* [BlockReasonException] when [Chapter.blockReason] is [BlockReason.AGERATING12].
*/
class AgeRating12 : BlockReasonException(BlockReason.AGERATING12) {
override val messageResId: Int
get() = R.string.blockReason_ageRating12
}

/**
* [BlockReasonException] when [Chapter.blockReason] is [BlockReason.GEOBLOCK].
*/
class GeoBlock : BlockReasonException(BlockReason.GEOBLOCK) {
override val messageResId: Int
get() = R.string.blockReason_geoBlock
}

/**
* [BlockReasonException] when [Chapter.blockReason] is [BlockReason.COMMERCIAL].
*/
class Commercial : BlockReasonException(BlockReason.COMMERCIAL) {
override val messageResId: Int
get() = R.string.blockReason_commercial
}

/**
* [BlockReasonException] when [Chapter.blockReason] is [BlockReason.JOURNALISTIC].
*/
class Journalistic : BlockReasonException(BlockReason.JOURNALISTIC) {
override val messageResId: Int
get() = R.string.blockReason_journalistic
}

/**
* [BlockReasonException] when [Chapter.blockReason] is [BlockReason.UNKNOWN].
*/
class Unknown : BlockReasonException(BlockReason.UNKNOWN)
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright (c) SRG SSR. All rights reserved.
* License information is available from the LICENSE file.
*/
package ch.srgssr.pillarbox.core.business.extension

import ch.srgssr.pillarbox.core.business.exception.BlockReasonException
import ch.srgssr.pillarbox.core.business.exception.BlockReasonException.AgeRating12
import ch.srgssr.pillarbox.core.business.exception.BlockReasonException.AgeRating18
import ch.srgssr.pillarbox.core.business.exception.BlockReasonException.Commercial
import ch.srgssr.pillarbox.core.business.exception.BlockReasonException.EndDate
import ch.srgssr.pillarbox.core.business.exception.BlockReasonException.GeoBlock
import ch.srgssr.pillarbox.core.business.exception.BlockReasonException.Journalistic
import ch.srgssr.pillarbox.core.business.exception.BlockReasonException.Legal
import ch.srgssr.pillarbox.core.business.exception.BlockReasonException.StartDate
import ch.srgssr.pillarbox.core.business.exception.BlockReasonException.Unknown
import ch.srgssr.pillarbox.core.business.integrationlayer.data.BlockReason
import ch.srgssr.pillarbox.core.business.integrationlayer.data.Chapter

/**
* @return The [BlockReasonException] linked to [Chapter.blockReason] or `null` if there is no block reason.
*/
fun Chapter.getBlockReasonExceptionOrNull(): BlockReasonException? {
return when (blockReason) {
null -> null
BlockReason.STARTDATE -> StartDate(instant = validFrom)
BlockReason.ENDDATE -> EndDate(instant = validTo)
BlockReason.LEGAL -> Legal()
BlockReason.AGERATING18 -> AgeRating18()
BlockReason.AGERATING12 -> AgeRating12()
BlockReason.GEOBLOCK -> GeoBlock()
BlockReason.COMMERCIAL -> Commercial()
BlockReason.JOURNALISTIC -> Journalistic()
BlockReason.UNKNOWN -> Unknown()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/
package ch.srgssr.pillarbox.core.business.integrationlayer.data

import kotlinx.datetime.Instant
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

Expand All @@ -25,6 +26,8 @@ import kotlinx.serialization.Serializable
* @property comScoreAnalyticsLabels
* @property analyticsLabels
* @property timeIntervalList
* @property validFrom The [Instant] when the [Chapter] becomes valid.
* @property validTo The [Instant] until when the [Chapter] is valid.
* @constructor Create empty Chapter
*/
@Serializable
Expand All @@ -47,6 +50,8 @@ data class Chapter(
@SerialName("analyticsMetadata")
override val analyticsLabels: Map<String, String>? = null,
val timeIntervalList: List<TimeInterval>? = null,
val validFrom: Instant? = null,
val validTo: Instant? = null,
) : DataWithAnalytics {
/**
* If it is a full length chapter.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ import ch.srgssr.pillarbox.analytics.commandersact.CommandersAct
import ch.srgssr.pillarbox.core.business.HttpResultException
import ch.srgssr.pillarbox.core.business.akamai.AkamaiTokenDataSource
import ch.srgssr.pillarbox.core.business.akamai.AkamaiTokenProvider
import ch.srgssr.pillarbox.core.business.exception.BlockReasonException
import ch.srgssr.pillarbox.core.business.exception.DataParsingException
import ch.srgssr.pillarbox.core.business.exception.ResourceNotFoundException
import ch.srgssr.pillarbox.core.business.extension.getBlockReasonExceptionOrNull
import ch.srgssr.pillarbox.core.business.integrationlayer.ResourceSelector
import ch.srgssr.pillarbox.core.business.integrationlayer.data.Chapter
import ch.srgssr.pillarbox.core.business.integrationlayer.data.Drm
Expand Down Expand Up @@ -145,8 +145,8 @@ class SRGAssetLoader internal constructor(
}

val chapter = result.mainChapter
chapter.blockReason?.let {
throw BlockReasonException(it)
chapter.getBlockReasonExceptionOrNull()?.let {
throw it
}

val resource = resourceSelector.selectResourceFromChapter(chapter) ?: throw ResourceNotFoundException()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import ch.srgssr.pillarbox.core.business.exception.BlockReasonException
import ch.srgssr.pillarbox.core.business.exception.DataParsingException
import ch.srgssr.pillarbox.core.business.exception.ResourceNotFoundException
import ch.srgssr.pillarbox.core.business.integrationlayer.data.BlockReason
import org.junit.runner.RunWith
import java.io.IOException
import kotlin.test.BeforeTest
Expand All @@ -34,7 +33,7 @@ class SRGErrorMessageProviderTest {

@Test
fun `getErrorMessage BlockReasonException`() {
val exception = BlockReasonException(BlockReason.AGERATING12)
val exception = BlockReasonException.AgeRating12()
val (errorCode, errorMessage) = errorMessageProvider.getErrorMessage(playbackException(exception))

assertEquals(0, errorCode)
Expand Down
Loading

0 comments on commit 44e14d7

Please sign in to comment.