Skip to content

Commit

Permalink
fix: play song without login
Browse files Browse the repository at this point in the history
reversed cna function for n and signature function, transpiled into kotlin
  • Loading branch information
Malopieds committed Oct 28, 2024
1 parent afb3268 commit 9b7f0dc
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -703,9 +703,8 @@ class MusicService : MediaLibraryService(),
)
}
scope.launch(Dispatchers.IO) { recoverSong(mediaId, playerResponse) }

songUrlCache[mediaId] = format.url!! to playerResponse.streamingData!!.expiresInSeconds * 1000L
dataSpec.withUri(format.url!!.toUri()).subrange(dataSpec.uriPositionOffset, CHUNK_LENGTH)
songUrlCache[mediaId] = format.findUrl() to playerResponse.streamingData!!.expiresInSeconds * 1000L
dataSpec.withUri(format.findUrl().toUri()).subrange(dataSpec.uriPositionOffset, CHUNK_LENGTH)
}
}

Expand Down
14 changes: 14 additions & 0 deletions innertube/src/main/java/com/zionhuang/innertube/InnerTube.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import com.zionhuang.innertube.models.Context
import com.zionhuang.innertube.models.YouTubeClient
import com.zionhuang.innertube.models.YouTubeLocale
import com.zionhuang.innertube.models.body.*
import com.zionhuang.innertube.utils.nSigDecode
import com.zionhuang.innertube.utils.parseCookieString
import com.zionhuang.innertube.utils.sha1
import com.zionhuang.innertube.utils.sigDecode
import io.ktor.client.*
import io.ktor.client.engine.okhttp.*
import io.ktor.client.plugins.*
Expand Down Expand Up @@ -244,4 +246,16 @@ class InnerTube {
ytClient(client, setLogin = true)
setBody(AccountMenuBody(client.toContext(locale, visitorData)))
}

fun decodeCipher(cipher: String): String? {
val params = parseQueryString(cipher)
val signature = params["s"] ?: return null
val signatureParam = params["sp"] ?: return null
val url = params["url"]?.let { URLBuilder(it) } ?: return null
val n = url.parameters["n"]
url.parameters["n"] = nSigDecode(n.toString())
url.parameters[signatureParam] = sigDecode(signature)
url.parameters["c"] = "ANDROID_MUSIC"
return url.toString()
}
}
5 changes: 3 additions & 2 deletions innertube/src/main/java/com/zionhuang/innertube/YouTube.kt
Original file line number Diff line number Diff line change
Expand Up @@ -425,8 +425,9 @@ object YouTube {
return@runCatching playerResponse
}
}
playerResponse = innerTube.player(IOS, videoId, playlistId).body<PlayerResponse>()
if (playerResponse.playabilityStatus.status == "OK") {
playerResponse = innerTube.player(WEB_REMIX, videoId, playlistId).body<PlayerResponse>()
if (playerResponse.playabilityStatus.status == "OK" && playerResponse.streamingData?.adaptiveFormats?.any
{ it.url != null || it.signatureCipher != null } == true) {
return@runCatching playerResponse
}
val safePlayerResponse = innerTube.player(TVHTML5, videoId, playlistId).body<PlayerResponse>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,16 @@ data class PlayerBody(
val videoId: String,
val playlistId: String?,
val contentCheckOk: Boolean = true,
)
val cpn: String? = "wzf9Y0nqz6AUe2Vr", // need some random cpn to get same algorithm for sig
val playbackContext: PlaybackContext? = PlaybackContext(ContentPlaybackContext(20019L)),
) {
@Serializable
data class PlaybackContext(
val contentPlaybackContext: ContentPlaybackContext?,
)

@Serializable
data class ContentPlaybackContext(
val signatureTimestamp: Long?,
)
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.zionhuang.innertube.models.response

import com.zionhuang.innertube.InnerTube
import com.zionhuang.innertube.models.ResponseContext
import com.zionhuang.innertube.models.Thumbnails
import kotlinx.serialization.Serializable
Expand Down Expand Up @@ -57,9 +58,12 @@ data class PlayerResponse(
val audioChannels: Int?,
val loudnessDb: Double?,
val lastModified: Long?,
val signatureCipher: String?,
) {
val isAudio: Boolean
get() = width == null

fun findUrl() = url ?: signatureCipher?.let { InnerTube().decodeCipher(it) }!!
}
}

Expand Down
66 changes: 66 additions & 0 deletions innertube/src/main/java/com/zionhuang/innertube/utils/Utils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,69 @@ fun String.parseTime(): Int? {
}
return null
}

fun nSigDecode(n: String): String {
val step1 =
buildString {
append(n[8])
append(n.substring(2, 8))
append(n[1])
append(n.substring(9))
}

val step2 =
buildString {
append(step1.substring(7))
append((step1[0] + step1.substring(1, 3).reversed() + step1[3]).reversed())
append(step1.substring(4, 7))
}

val step3 = step2.substring(7) + step2.substring(0, 7)

val step4 =
buildString {
append(step3[step3.length - 4])
append(step3.substring(3, 7))
append(step3[2])
append(step3.substring(8, 11))
append(step3[7])
append(step3.takeLast(3))
append(step3[1])
}

val step5 = (step4.substring(0, 2) + step4.last() + step4.substring(3, step4.length - 1) + step4[2]).reversed()

val keyString = "cbrrC5"
val charset = ('A'..'Z') + ('a'..'z') + ('0'..'9') + listOf('-', '_')
val mutableKeyList = keyString.toMutableList()

val transformedChars = CharArray(step5.length)

for (index in step5.indices) {
val currentChar = step5[index]
val indexInCharset =
(charset.indexOf(currentChar) - charset.indexOf(mutableKeyList[index % mutableKeyList.size]) + index + charset.size - index) %
charset.size
transformedChars[index] = charset[indexInCharset]
mutableKeyList[index % mutableKeyList.size] = transformedChars[index]
}

val step6 = String(transformedChars)
return step6.dropLast(3).reversed() + step6.takeLast(3)
}

fun sigDecode(input: String): String {
val middleSection = input.substring(3, input.length - 3)
val rearranged = (middleSection.take(35) + input[0] + middleSection.drop(36)).reversed()
val result =
buildString {
append("A")
append(rearranged.substring(0, 15))
append(input[input.length - 2])
append(rearranged.substring(16, 34))
append(input[input.length - 3])
append(rearranged.substring(35))
append(input[38])
}
return result
}

0 comments on commit 9b7f0dc

Please sign in to comment.