diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a97145c3f81..01a35ed3ecf 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -28,6 +28,7 @@ juniversalchardet = "2.5.0" kotlinGradlePlugin = "2.3.20" kotlinxCollectionsImmutable = "0.4.0" kotlinxCoroutinesCore = "1.10.2" +kotlinxIOCore = "0.9.0" lifecycleKtx = "2.10.0" material = "1.14.0-beta01" media3 = "1.9.3" @@ -83,6 +84,7 @@ junit-ktx = { module = "androidx.test.ext:junit-ktx", version.ref = "junitKtx" } juniversalchardet = { module = "com.github.albfernandez:juniversalchardet", version.ref = "juniversalchardet" } kotlinx-collections-immutable = { module = "org.jetbrains.kotlinx:kotlinx-collections-immutable", version.ref = "kotlinxCollectionsImmutable" } kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinxCoroutinesCore" } +kotlinx-io-core = { module = "org.jetbrains.kotlinx:kotlinx-io-core", version.ref = "kotlinxIOCore" } lifecycle-livedata-ktx = { module = "androidx.lifecycle:lifecycle-livedata-ktx", version.ref = "lifecycleKtx" } lifecycle-viewmodel-ktx = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref = "lifecycleKtx" } material = { module = "com.google.android.material:material", version.ref = "material" } diff --git a/library/build.gradle.kts b/library/build.gradle.kts index 073e49e6483..82175a20ba6 100644 --- a/library/build.gradle.kts +++ b/library/build.gradle.kts @@ -57,6 +57,7 @@ kotlin { implementation(libs.nicehttp) // HTTP Lib implementation(libs.jackson.module.kotlin) // JSON Parser implementation(libs.kotlinx.coroutines.core) + implementation(libs.kotlinx.io.core) implementation(libs.fuzzywuzzy) // Match Extractors implementation(libs.jsoup) // HTML Parser implementation(libs.rhino) // Run JavaScript diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/HlsPlaylistParser.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/HlsPlaylistParser.kt index bea75aa581c..90368da04f0 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/HlsPlaylistParser.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/HlsPlaylistParser.kt @@ -1,3 +1,5 @@ +@file:OptIn(ExperimentalUuidApi::class) + /* * Copyright (C) 2016 The Android Open Source Project * @@ -19,12 +21,14 @@ */ package com.lagradost.cloudstream3.utils -import java.io.IOException import java.net.URI -import java.nio.ByteBuffer -import java.util.UUID +import kotlinx.io.Buffer +import kotlinx.io.IOException +import kotlinx.io.readByteArray import kotlin.io.encoding.Base64 import kotlin.io.encoding.ExperimentalEncodingApi +import kotlin.uuid.ExperimentalUuidApi +import kotlin.uuid.Uuid @Suppress("unused") object HlsPlaylistParser { @@ -187,13 +191,13 @@ object HlsPlaylistParser { data class SchemeData( /** - * The {@link UUID} of the DRM scheme, or {@link C#UUID_NIL} if the data is universal (i.e. + * The [Uuid] of the DRM scheme, or [C.UUID_NIL] if the data is universal (i.e. * applies to all schemes). */ - val uuid: UUID, + val uuid: Uuid, /** The URL of the server to which license requests should be made. May be null if unknown. */ val licenseServerUrl: String? = null, - /** The mimeType of {@link #data}. */ + /** The mimeType of [data]. */ val mimeType: String, /** The initialization data. May be null for scheme support checks only. */ val data: ByteArray @@ -535,29 +539,29 @@ object HlsPlaylistParser { object C { /** - * UUID for the ClearKey DRM scheme. + * [Uuid] for the ClearKey DRM scheme. * * * ClearKey is supported on Android devices running Android 5.0 (API Level 21) and up. */ - val CLEARKEY_UUID = UUID(-0x1d8e62a7567a4c37L, 0x781AB030AF78D30EL) + val CLEARKEY_UUID = Uuid.fromLongs(-0x1d8e62a7567a4c37L, 0x781AB030AF78D30EL) /** - * UUID for the Widevine DRM scheme. + * [Uuid] for the Widevine DRM scheme. * * * Widevine is supported on Android devices running Android 4.3 (API Level 18) and up. */ - val WIDEVINE_UUID = UUID(-0x121074568629b532L, -0x5c37d8232ae2de13L) + val WIDEVINE_UUID = Uuid.fromLongs(-0x121074568629b532L, -0x5c37d8232ae2de13L) /** - * UUID for the PlayReady DRM scheme. + * [Uuid] for the PlayReady DRM scheme. * * * PlayReady is supported on all AndroidTV devices. Note that most other Android devices do not * provide PlayReady support. */ - val PLAYREADY_UUID = UUID(-0x65fb0f8667bfbd7aL, -0x546d19a41f77a06bL) + val PLAYREADY_UUID = Uuid.fromLongs(-0x65fb0f8667bfbd7aL, -0x546d19a41f77a06bL) /** "cenc" scheme type name as defined in ISO/IEC 23001-7:2016. */ @@ -1067,7 +1071,7 @@ object HlsPlaylistParser { object PsshAtomUtil { fun buildPsshAtom( - systemId: UUID, keyIds: Array?, data: ByteArray? + systemId: Uuid, keyIds: Array?, data: ByteArray? ): ByteArray { val dataLength = data?.size ?: 0 var psshBoxLength: Int = @@ -1075,26 +1079,30 @@ object HlsPlaylistParser { if (keyIds != null) { psshBoxLength += 4 /* KID_count */ + (keyIds.size * 16) /* KIDs */ } - val psshBox: ByteBuffer = ByteBuffer.allocate(psshBoxLength) - psshBox.putInt(psshBoxLength) - psshBox.putInt(Mp4Box.TYPE_pssh) - psshBox.putInt(if (keyIds != null) 0x01000000 else 0 /* version=(buildV1Atom ? 1 : 0), flags=0 */) - psshBox.putLong(systemId.mostSignificantBits) - psshBox.putLong(systemId.leastSignificantBits) + val buffer = Buffer() + buffer.writeInt(psshBoxLength) + buffer.writeInt(Mp4Box.TYPE_pssh) + buffer.writeInt(if (keyIds != null) 0x01000000 else 0 /* version=(buildV1Atom ? 1 : 0), flags=0 */) + systemId.toLongs { mostSignificantBits, leastSignificantBits -> + buffer.writeLong(mostSignificantBits) + buffer.writeLong(leastSignificantBits) + } if (keyIds != null) { - psshBox.putInt(keyIds.size) + buffer.writeInt(keyIds.size) for (keyId in keyIds) { - psshBox.putLong(keyId.mostSignificantBits) - psshBox.putLong(keyId.leastSignificantBits) + keyId.toLongs { mostSignificantBits, leastSignificantBits -> + buffer.writeLong(mostSignificantBits) + buffer.writeLong(leastSignificantBits) + } } } if (data != null && data.size != 0) { - psshBox.putInt(data.size) - psshBox.put(data) + buffer.writeInt(data.size) + buffer.write(data) } else { - psshBox.putInt(0) + buffer.writeInt(0) } - return psshBox.array() + return buffer.readByteArray() } } @@ -1179,7 +1187,7 @@ object HlsPlaylistParser { if (KEYFORMAT_WIDEVINE_PSSH_BINARY == keyFormat) { val uriString = parseStringAttr(line, REGEX_URI, variableDefinitions) return SchemeData( - uuid = WIDEVINE_UUID, + uuid = C.WIDEVINE_UUID, mimeType = MimeTypes.VIDEO_MP4, data = Base64.Default.decode(uriString.substring(uriString.indexOf(','))) ) @@ -2078,4 +2086,4 @@ object HlsPlaylistParser { sessionKeyDrmInitData = sessionKeyDrmInitData ) } -} \ No newline at end of file +}