Skip to content
2 changes: 2 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ kotlinxAtomicfu = "0.33.0"
kotlinxCollectionsImmutable = "0.4.0"
kotlinxCoroutinesCore = "1.11.0"
kotlinxDatetime = "0.8.0"
kotlinxIOCore = "0.9.1"
kotlinxSerializationJson = "1.11.0"
ktor = "3.5.0"
lifecycleKtx = "2.10.0"
Expand Down Expand Up @@ -93,6 +94,7 @@ kotlinx-atomicfu = { module = "org.jetbrains.kotlinx:atomicfu", version.ref = "k
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-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "kotlinxDatetime" }
kotlinx-io-core = { module = "org.jetbrains.kotlinx:kotlinx-io-core", version.ref = "kotlinxIOCore" }
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" }
ktor-http = { module = "io.ktor:ktor-http", version.ref = "ktor" }
lifecycle-livedata-ktx = { module = "androidx.lifecycle:lifecycle-livedata-ktx", version.ref = "lifecycleKtx" }
Expand Down
1 change: 1 addition & 0 deletions library/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ kotlin {
implementation(libs.kotlinx.atomicfu)
implementation(libs.kotlinx.coroutines.core)
implementation(libs.kotlinx.datetime)
implementation(libs.kotlinx.io.core)
implementation(libs.kotlinx.serialization.json) // JSON Parser
implementation(libs.ktor.http)
implementation(libs.jsoup) // HTML Parser
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@file:OptIn(ExperimentalUuidApi::class)

/*
* Copyright (C) 2016 The Android Open Source Project
*
Expand All @@ -21,9 +23,11 @@ package com.lagradost.cloudstream3.utils

import com.lagradost.cloudstream3.base64DecodeArray
import io.ktor.http.Url
import java.io.IOException
import java.nio.ByteBuffer
import java.util.UUID
import kotlinx.io.Buffer
import kotlinx.io.IOException
import kotlinx.io.readByteArray
import kotlin.uuid.ExperimentalUuidApi
import kotlin.uuid.Uuid

@Suppress("unused")
object HlsPlaylistParser {
Expand Down Expand Up @@ -186,13 +190,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
Expand Down Expand Up @@ -454,14 +458,14 @@ object HlsPlaylistParser {
// "." or "..", remove the appropriate segments of the path.
if (i == segmentStart + 1 && url[segmentStart] == '.') {
// Given "abc/def/./ghi", remove "./" to get "abc/def/ghi".
url.delete(segmentStart, nextSegmentStart)
url.deleteRange(segmentStart, nextSegmentStart)
limit -= nextSegmentStart - segmentStart
i = segmentStart
} else if (i == segmentStart + 2 && url[segmentStart] == '.' && url[segmentStart + 1] == '.') {
// Given "abc/def/../ghi", remove "def/../" to get "abc/ghi".
val prevSegmentStart = url.lastIndexOf("/", segmentStart - 2) + 1
val removeFrom = if (prevSegmentStart > offset) prevSegmentStart else offset
url.delete(removeFrom, nextSegmentStart)
url.deleteRange(removeFrom, nextSegmentStart)
limit -= nextSegmentStart - removeFrom
segmentStart = prevSegmentStart
i = prevSegmentStart
Expand Down Expand Up @@ -534,29 +538,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. */
Expand Down Expand Up @@ -1066,34 +1070,38 @@ object HlsPlaylistParser {

object PsshAtomUtil {
fun buildPsshAtom(
systemId: UUID, keyIds: Array<UUID>?, data: ByteArray?
systemId: Uuid, keyIds: Array<Uuid>?, data: ByteArray?
): ByteArray {
val dataLength = data?.size ?: 0
var psshBoxLength: Int =
Mp4Box.FULL_HEADER_SIZE + 16 /* SystemId */ + 4 /* DataSize */ + dataLength
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()
}
}

Expand Down