Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove Ktor dependency #829

Merged
merged 10 commits into from
Dec 16, 2024
1 change: 0 additions & 1 deletion .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,3 @@ updates:
- dependency-name: "com.comscore:*"
- dependency-name: "com.google.guava:*" # Guava is updated together with AndroidX Media3
- dependency-name: "com.tagcommander.lib:*"
- dependency-name: "io.ktor:*" # We don't want to update to Ktor 3 yet
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,6 @@ class PillarboxAndroidLibraryPublishingPlugin : Plugin<Project> {
packageListUrl.set(URI("https://kotlinlang.org/api/kotlinx.serialization/package-list"))
}

// TODO Enable this once the following issue is fixed: https://github.com/Kotlin/dokka/issues/3889
// externalDocumentationLinks.register("ktor") {
// url.set(URI("https://api.ktor.io"))
// packageListUrl.set(URI("https://api.ktor.io/package-list"))
// }

// This is currently broken in Dokka for Android modules. See: https://github.com/Kotlin/dokka/issues/2876
sourceLink {
val version = VersionConfig().versionName(default = name)
Expand Down
10 changes: 2 additions & 8 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ kotlinx-coroutines = "1.9.0"
kotlinx-datetime = "0.6.1"
kotlinx-kover = "0.8.3"
kotlinx-serialization = "1.7.3"
ktor = "2.3.13"
mockk = "1.13.13"
okhttp = "4.12.0"
okio = "3.9.1"
robolectric = "4.14.1"
srg-data-provider = "0.10.1"
tag-commander-core = "5.4.3"
Expand Down Expand Up @@ -78,13 +78,6 @@ kotlinx-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.
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" }
ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" }
ktor-client-okhttp = { module = "io.ktor:ktor-client-okhttp", version.ref = "ktor" }
ktor-client-content-negotiation = { module = "io.ktor:ktor-client-content-negotiation", version.ref = "ktor" }
ktor-http = { module = "io.ktor:ktor-http", version.ref = "ktor" }
ktor-serialization = { module = "io.ktor:ktor-serialization", version.ref = "ktor" }
ktor-serialization-kotlinx-json = { module = "io.ktor:ktor-serialization-kotlinx-json", version.ref = "ktor" }
ktor-utils = { module = "io.ktor:ktor-utils", version.ref = "ktor" }
robolectric = { module = "org.robolectric:robolectric", version.ref = "robolectric" }
robolectric-annotations = { module = "org.robolectric:annotations", version.ref = "robolectric" }
robolectric-shadows-framework = { module = "org.robolectric:shadows-framework", version.ref = "robolectric" }
Expand Down Expand Up @@ -115,6 +108,7 @@ androidx-media3-test-utils = { module = "androidx.media3:media3-test-utils", ver
androidx-media3-test-utils-robolectric = { module = "androidx.media3:media3-test-utils-robolectric", version.ref = "androidx-media3" }
okhttp = { group = "com.squareup.okhttp3", name = "okhttp", version.ref = "okhttp" }
okhttp-logging-interceptor = { group = "com.squareup.okhttp3", name = "logging-interceptor", version.ref = "okhttp" }
okio = { group = "com.squareup.okio", name = "okio", version.ref = "okio" }
tagcommander-core = { group = "com.tagcommander.lib", name = "core", version.ref = "tag-commander-core" }
tagcommander-serverside = { group = "com.tagcommander.lib", name = "ServerSide", version.ref = "tag-commander-server-side" }
comscore = { group = "com.comscore", name = "android-analytics", version.ref = "comscore" }
Expand Down
7 changes: 1 addition & 6 deletions pillarbox-core-business/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,7 @@ dependencies {
api(libs.kotlinx.datetime)
api(libs.kotlinx.serialization.core)
implementation(libs.kotlinx.serialization.json)
api(libs.ktor.client.core)
implementation(libs.ktor.client.okhttp)
implementation(libs.ktor.http)
implementation(libs.ktor.serialization.kotlinx.json)
implementation(libs.ktor.utils)
implementation(libs.okhttp)
api(libs.okhttp)
api(libs.tagcommander.core)

testImplementation(project(":pillarbox-player-testutils"))
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ 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.player.network.HttpResultException
import java.io.IOException

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import androidx.media3.datasource.DataSource
import androidx.media3.datasource.DataSpec
import androidx.media3.datasource.DefaultHttpDataSource
import ch.srgssr.pillarbox.player.utils.DebugLogger
import kotlinx.coroutines.runBlocking

/**
* A [DataSource] that injects an Akamai token into URLs containing the query parameter `withToken=true`.
Expand All @@ -24,9 +23,7 @@ class AkamaiTokenDataSource private constructor(
if (hasNeedAkamaiToken(outputUri)) {
DebugLogger.debug("Akamai", "open ${dataSpec.uri}")
val cleanUri = removeTokenQueryParameter(outputUri)
outputUri = runBlocking {
tokenProvider.tokenizeUri(cleanUri)
}
outputUri = tokenProvider.tokenizeUri(cleanUri)
return dataSource.open(dataSpec.buildUpon().setUri(outputUri).build())
}
return dataSource.open(dataSpec)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,19 @@ package ch.srgssr.pillarbox.core.business.akamai

import android.net.Uri
import android.net.UrlQuerySanitizer
import ch.srgssr.pillarbox.player.network.PillarboxHttpClient
import io.ktor.client.HttpClient
import io.ktor.client.call.body
import io.ktor.client.request.get
import io.ktor.client.request.parameter
import io.ktor.http.appendEncodedPathSegments
import ch.srgssr.pillarbox.player.network.PillarboxOkHttp
import ch.srgssr.pillarbox.player.network.RequestSender.send
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import okhttp3.OkHttpClient
import okhttp3.Request

/**
* The [AkamaiTokenProvider] is responsible for fetching an Akamai token from `TOKEN_SERVICE_URL` and appending it to URIs.
*
* @param httpClient The HTTP client used to make requests to the token service. Defaults to a [PillarboxHttpClient] instance.
* @param okHttpClient The OkHttp client used to make requests to the token service. Defaults to a [PillarboxOkHttp] instance.
*/
class AkamaiTokenProvider(private val httpClient: HttpClient = PillarboxHttpClient()) {
MGaetan89 marked this conversation as resolved.
Show resolved Hide resolved
class AkamaiTokenProvider(private val okHttpClient: OkHttpClient = PillarboxOkHttp()) {

/**
* Requests and appends an Akamai token to the provided URI.
Expand All @@ -30,7 +28,7 @@ class AkamaiTokenProvider(private val httpClient: HttpClient = PillarboxHttpClie
* @param uri The URI to be tokenized.
* @return The tokenized [Uri] if successful, otherwise the original [uri].
*/
suspend fun tokenizeUri(uri: Uri): Uri {
fun tokenizeUri(uri: Uri): Uri {
val acl = getAcl(uri)
val token = acl?.let {
val tokenResult = getToken(it)
Expand All @@ -39,15 +37,12 @@ class AkamaiTokenProvider(private val httpClient: HttpClient = PillarboxHttpClie
return token?.let { appendTokenToUri(uri, it) } ?: uri
}

private suspend fun getToken(acl: String): Result<Token> {
return runCatching {
httpClient.get(TOKEN_SERVICE_URL) {
url {
appendEncodedPathSegments("akahd/token")
parameter("acl", acl)
}
}.body<TokenResponse>().token
}
private fun getToken(acl: String): Result<Token> {
return Request.Builder()
.url(TOKEN_SERVICE_URL.format(acl))
.build()
.send<TokenResponse>(okHttpClient)
.map { it.token }
}

/**
Expand Down Expand Up @@ -76,7 +71,7 @@ class AkamaiTokenProvider(private val httpClient: HttpClient = PillarboxHttpClie
internal data class TokenResponse(val token: Token)

internal companion object {
private const val TOKEN_SERVICE_URL = "https://tp.srgssr.ch/"
private const val TOKEN_SERVICE_URL = "https://tp.srgssr.ch/akahd/token?acl=%s"

internal fun getAcl(uri: Uri): String? {
val path = uri.path
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@
package ch.srgssr.pillarbox.core.business.integrationlayer

import ch.srgssr.pillarbox.core.business.integrationlayer.service.IlHost
import io.ktor.http.URLBuilder
import io.ktor.http.appendEncodedPathSegments
import java.net.URL
import java.net.URLEncoder

/**
* Service used to get a scaled image URL. This only works for SRG images.
Expand All @@ -21,14 +20,8 @@ internal class ImageScalingService(
fun getScaledImageUrl(
imageUrl: String,
): String {
return URLBuilder(baseUrl.toString())
.appendEncodedPathSegments("images/")
.apply {
parameters.append("imageUrl", imageUrl)
parameters.append("format", "webp")
parameters.append("width", "480")
}
.build()
.toString()
val encodedImageUrl = URLEncoder.encode(imageUrl, Charsets.UTF_8.name())

return "${baseUrl}images/?imageUrl=$encodedImageUrl&format=webp&width=480"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,24 @@ package ch.srgssr.pillarbox.core.business.integrationlayer.service

import android.net.Uri
import ch.srgssr.pillarbox.core.business.integrationlayer.data.MediaComposition
import ch.srgssr.pillarbox.player.network.PillarboxHttpClient
import io.ktor.client.HttpClient
import io.ktor.client.call.body
import io.ktor.client.request.get
import java.net.URL
import ch.srgssr.pillarbox.player.network.PillarboxOkHttp
import ch.srgssr.pillarbox.player.network.RequestSender.send
import okhttp3.OkHttpClient
import okhttp3.Request

/**
* A service for fetching a [MediaComposition] over HTTP.
*
* @param httpClient The Ktor [HttpClient] instance used for making HTTP requests.
* @param okHttpClient The OkHttp client instance used for making HTTP requests.
*/
class HttpMediaCompositionService(
private val httpClient: HttpClient = PillarboxHttpClient(),
MGaetan89 marked this conversation as resolved.
Show resolved Hide resolved
private val okHttpClient: OkHttpClient = PillarboxOkHttp(),
) : MediaCompositionService {

override suspend fun fetchMediaComposition(uri: Uri): Result<MediaComposition> {
return runCatching {
httpClient.get(URL(uri.toString()))
.body()
}
return Request.Builder()
.url(uri.toString())
.build()
.send(okHttpClient)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import androidx.media3.common.MimeTypes
import androidx.media3.datasource.DataSource.Factory
import androidx.media3.exoplayer.source.DefaultMediaSourceFactory
import androidx.media3.exoplayer.source.MergingMediaSource
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.DataParsingException
Expand All @@ -32,10 +31,10 @@ import ch.srgssr.pillarbox.core.business.tracker.comscore.ComScoreTracker
import ch.srgssr.pillarbox.player.PillarboxDsl
import ch.srgssr.pillarbox.player.asset.Asset
import ch.srgssr.pillarbox.player.asset.AssetLoader
import ch.srgssr.pillarbox.player.network.HttpResultException
import ch.srgssr.pillarbox.player.tracker.FactoryData
import ch.srgssr.pillarbox.player.tracker.MediaItemTracker
import ch.srgssr.pillarbox.player.tracker.MutableMediaItemTrackerData
import io.ktor.client.plugins.ClientRequestException
import kotlinx.serialization.SerializationException
import java.io.IOException

Expand Down Expand Up @@ -121,17 +120,9 @@ class SRGAssetLoader internal constructor(
checkNotNull(mediaItem.localConfiguration)
val result = mediaCompositionService.fetchMediaComposition(mediaItem.localConfiguration!!.uri).getOrElse {
when (it) {
is ClientRequestException -> {
throw HttpResultException(it)
}

is SerializationException -> {
throw DataParsingException(it)
}

else -> {
throw IOException(it.message)
}
is HttpResultException -> throw it
is SerializationException -> throw DataParsingException(it)
else -> throw IOException(it.message)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ import ch.srgssr.pillarbox.player.PillarboxDsl
import ch.srgssr.pillarbox.player.network.PillarboxOkHttp
import ch.srgssr.pillarbox.player.tracker.MediaItemTracker
import ch.srgssr.pillarbox.player.tracker.MutableMediaItemTrackerData
import io.ktor.client.HttpClient
import kotlinx.coroutines.Dispatchers
import okhttp3.OkHttpClient

/**
* Configuration class for [SRGAssetLoader].
Expand Down Expand Up @@ -84,15 +84,15 @@ class SRGAssetLoaderConfig internal constructor(context: Context) {
}

/**
* Sets the HTTP client used by the [MediaCompositionService] and [AkamaiTokenProvider].
* Sets the OkHttp client used by the [MediaCompositionService] and [AkamaiTokenProvider].
*
* Note that this will override any existing [MediaCompositionService] set using [mediaCompositionService].
*
* @param httpClient The HTTP client.
* @param okHttpClient The OkHttp client.
*/
fun httpClient(httpClient: HttpClient) {
mediaCompositionService = HttpMediaCompositionService(httpClient)
akamaiTokenProvider = AkamaiTokenProvider(httpClient)
fun httpClient(okHttpClient: OkHttpClient) {
mediaCompositionService = HttpMediaCompositionService(okHttpClient)
akamaiTokenProvider = AkamaiTokenProvider(okHttpClient)
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ 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.player.network.HttpResultException
import org.junit.runner.RunWith
import java.io.IOException
import kotlin.test.BeforeTest
Expand Down Expand Up @@ -60,7 +61,7 @@ class SRGErrorMessageProviderTest {

@Test
fun `getErrorMessage HttpResultException`() {
val exception = HttpResultException("HTTP request failed")
val exception = HttpResultException(503, "HTTP request failed")
val (errorCode, errorMessage) = errorMessageProvider.getErrorMessage(playbackException(exception))

assertEquals(0, errorCode)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ package ch.srgssr.pillarbox.core.business
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.MediaComposition
import ch.srgssr.pillarbox.player.network.PillarboxHttpClient.jsonSerializer
import ch.srgssr.pillarbox.player.network.jsonSerializer
import kotlinx.serialization.SerializationException
import kotlin.test.Test
import kotlin.test.assertEquals
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import android.net.Uri
import ch.srgssr.pillarbox.core.business.integrationlayer.data.MediaComposition
import ch.srgssr.pillarbox.core.business.integrationlayer.service.HttpMediaCompositionService
import ch.srgssr.pillarbox.core.business.integrationlayer.service.MediaCompositionService
import ch.srgssr.pillarbox.player.network.PillarboxHttpClient
import ch.srgssr.pillarbox.player.network.jsonSerializer

internal class LocalMediaCompositionWithFallbackService(
context: Context,
Expand All @@ -19,7 +19,7 @@ internal class LocalMediaCompositionWithFallbackService(

init {
val json = context.assets.open("media-compositions.json").bufferedReader().use { it.readText() }
mediaCompositions = PillarboxHttpClient.jsonSerializer.decodeFromString(json)
mediaCompositions = jsonSerializer.decodeFromString(json)
}

override suspend fun fetchMediaComposition(uri: Uri): Result<MediaComposition> {
Expand Down
1 change: 0 additions & 1 deletion pillarbox-demo/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,6 @@ dependencies {
implementation(libs.kotlinx.coroutines.core)
implementation(libs.kotlinx.datetime)
implementation(libs.kotlinx.serialization.core)
implementation(libs.ktor.client.okhttp)
implementation(libs.okhttp)
implementation(libs.srg.data)
implementation(libs.srg.dataprovider.retrofit)
Expand Down
8 changes: 1 addition & 7 deletions pillarbox-player/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,6 @@ dependencies {
api(libs.kotlinx.coroutines.core)
api(libs.kotlinx.serialization.core)
implementation(libs.kotlinx.serialization.json)
implementation(libs.ktor.client.content.negotiation)
api(libs.ktor.client.core)
implementation(libs.ktor.client.okhttp)
implementation(libs.ktor.http)
implementation(libs.ktor.serialization)
implementation(libs.ktor.serialization.kotlinx.json)
implementation(libs.ktor.utils)
api(libs.okhttp)
implementation(libs.okhttp.logging.interceptor)

Expand All @@ -70,6 +63,7 @@ dependencies {
testImplementation(libs.kotlinx.coroutines.test)
testImplementation(libs.mockk)
testImplementation(libs.mockk.dsl)
testImplementation(libs.okio)
testRuntimeOnly(libs.robolectric)
testImplementation(libs.robolectric.annotations)
testImplementation(libs.robolectric.shadows.framework)
Expand Down
Loading
Loading