Skip to content

Commit

Permalink
innertube: allow adding po tokens to player requests and streaming urls
Browse files Browse the repository at this point in the history
  • Loading branch information
gechoto authored and reocat committed Feb 5, 2025
1 parent 78ec3ba commit 25a25ca
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 13 deletions.
30 changes: 24 additions & 6 deletions app/src/main/java/com/dd3boh/outertune/utils/YTPlayerUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,14 @@ object YTPlayerUtils {
*/
val signatureTimestamp = getSignatureTimestampOrNull(videoId)

// --- TODO: GET WEB PO TOKENS HERE ---
val webPlayerPot = "" // TODO
val webStreamingPot = "" // TODO
// ---

val mainPlayerResponse =
YouTube.player(videoId, playlistId, MAIN_CLIENT, signatureTimestamp).getOrThrow()
YouTube.player(videoId, playlistId, MAIN_CLIENT, signatureTimestamp, webPlayerPot)
.getOrThrow()

val audioConfig = mainPlayerResponse.playerConfig?.audioConfig
val videoDetails = mainPlayerResponse.videoDetails
Expand All @@ -84,19 +90,27 @@ object YTPlayerUtils {
streamExpiresInSeconds = null

// decide which client to use
if (clientIndex == -1) {
// try with streams from main client first
val client =
if (clientIndex == -1) {
// try with streams from main client first
MAIN_CLIENT
} else {
// after main client use fallback clients
STREAM_FALLBACK_CLIENTS[clientIndex]
}

// get player response for streams
if (client == MAIN_CLIENT) {
streamPlayerResponse = mainPlayerResponse
} else {
// after main client use fallback clients
val client = STREAM_FALLBACK_CLIENTS[clientIndex]
if (client.loginRequired && YouTube.cookie == null) {
// skip client if it requires login but user is not logged in
continue
}

streamPlayerResponse =
YouTube.player(videoId, playlistId, client, signatureTimestamp).getOrNull()
YouTube.player(videoId, playlistId, client, signatureTimestamp, webPlayerPot)
.getOrNull()
}

// process current client response
Expand All @@ -111,6 +125,10 @@ object YTPlayerUtils {
streamUrl = findUrlOrNull(format, videoId) ?: continue
streamExpiresInSeconds = streamPlayerResponse.streamingData?.expiresInSeconds ?: continue

if (client.useWebPoTokens) {
streamUrl += "&pot=$webStreamingPot";
}

if (clientIndex == STREAM_FALLBACK_CLIENTS.size - 1) {
/** skip [validateStatus] for last client */
break
Expand Down
15 changes: 10 additions & 5 deletions innertube/src/main/java/com/zionhuang/innertube/InnerTube.kt
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ class InnerTube {
videoId: String,
playlistId: String?,
signatureTimestamp: Int?,
webPlayerPot: String?,
) = httpClient.post("player") {
// Skip network call for local content
if (isLocalContent(videoId)) {
Expand Down Expand Up @@ -184,12 +185,16 @@ class InnerTube {
},
videoId = videoId,
playlistId = playlistId,
playbackContext =
if (client.useSignatureTimestamp && signatureTimestamp != null) {
PlayerBody.PlaybackContext(PlayerBody.PlaybackContext.ContentPlaybackContext(
playbackContext = if (client.useSignatureTimestamp && signatureTimestamp != null) {
PlayerBody.PlaybackContext(
PlayerBody.PlaybackContext.ContentPlaybackContext(
signatureTimestamp
))
} else null
)
)
} else null,
serviceIntegrityDimensions = if (client.useWebPoTokens && webPlayerPot != null) {
PlayerBody.ServiceIntegrityDimensions(webPlayerPot)
} else null
)
)
}
Expand Down
4 changes: 2 additions & 2 deletions innertube/src/main/java/com/zionhuang/innertube/YouTube.kt
Original file line number Diff line number Diff line change
Expand Up @@ -658,8 +658,8 @@ object YouTube {
innerTube.deletePlaylist(WEB_REMIX, playlistId)
}

suspend fun player(videoId: String, playlistId: String? = null, client: YouTubeClient, signatureTimestamp: Int? = null): Result<PlayerResponse> = runCatching {
innerTube.player(client, videoId, playlistId, signatureTimestamp).body<PlayerResponse>()
suspend fun player(videoId: String, playlistId: String? = null, client: YouTubeClient, signatureTimestamp: Int? = null, webPlayerPot: String? = null): Result<PlayerResponse> = runCatching {
innerTube.player(client, videoId, playlistId, signatureTimestamp, webPlayerPot).body<PlayerResponse>()
}

suspend fun next(endpoint: WatchEndpoint, continuation: String? = null): Result<NextResult> = runCatching {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ data class YouTubeClient(
val loginSupported: Boolean = false,
val loginRequired: Boolean = false,
val useSignatureTimestamp: Boolean = false,
val useWebPoTokens: Boolean = false,
val isEmbedded: Boolean = false,
// val origin: String? = null,
// val referer: String? = null,
Expand Down Expand Up @@ -51,6 +52,7 @@ data class YouTubeClient(
userAgent = USER_AGENT_WEB,
loginSupported = true,
useSignatureTimestamp = true,
useWebPoTokens = true,
)

val WEB_CREATOR = YouTubeClient(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ data class PlayerBody(
val playlistId: String?,
val cpn: String? = "wzf9Y0nqz6AUe2Vr", // need some random cpn to get same algorithm for sig
val playbackContext: PlaybackContext? = null,
val serviceIntegrityDimensions: ServiceIntegrityDimensions? = null,
val contentCheckOk: Boolean = true,
val racyCheckOk: Boolean = true,
) {
Expand All @@ -22,4 +23,9 @@ data class PlayerBody(
val signatureTimestamp: Int
)
}

@Serializable
data class ServiceIntegrityDimensions(
val poToken: String
)
}

0 comments on commit 25a25ca

Please sign in to comment.