Best approach to decode Youtube cipher signature using PHP or JS

前端 未结 3 545
滥情空心
滥情空心 2020-12-04 17:17

Youtube is using cipher signature for some of the videos when the use_cipher_signature = true in the dictionary returned through http://www.youtube.com/get_vid

相关标签:
3条回答
  • 2020-12-04 17:34

    Url structure and cipher code keeps on changing by Youtube. Presently, the best approach to decode the cipher signature is explained below:

    Ciphered signature in Youtube are just 'scrambled' signature that you have to rearrange them according to the Algorithm present in the player file (HTML5 player or Flash player).

    For example http://www.youtube.com/watch?v=UxxajLWwzqY is presently using the following HTML5 player file : //s.ytimg.com/yts/jsbin/html5player-vfltdb6U3.js

    in this file you can easily search for signature decipher code by searching for 'sig'. Here in this case the Algo is:

    function bz(a) {
        a = a.split("");
        a = cz(a, 61);
        a = cz(a, 5);
        a = a.reverse();
        a = a.slice(2);
        a = cz(a, 69);
        a = a.slice(2);
        a = a.reverse();
        return a.join("")
    }
    
    function cz(a, b) {
        var c = a[0];
        a[0] = a[b % a.length];
        a[b] = c;
        return a
    };
    

    Above is the deciphering code.

    But be aware, it keeps on changing when they change the player file, so you have to keep a tap on the player file being used.

    Also to download videos with cipher signature you have to take care of the sending the same cookies, using the same user-agent header, sending the request from the same IP address, and sending the request shortly after extraction. All these are or were required at some point

    If interested in cipher decryption algo, please visit CipherAPI

    Another cool API: TYstream API

    0 讨论(0)
  • 2020-12-04 17:34

    I've translated to Swift 3 the Akhilesh's answer for the iOS people:

    func decryptSignature(signature:String)->String {
        return bz(signature)
    }
    func bz(_ a:String)->String {
        var arrayA = Array(a.characters)
        arrayA = cz(arrayA, 61)
        arrayA = cz(arrayA, 5)
        arrayA = arrayA.reversed()
        arrayA = Array(arrayA[2..<arrayA.count])
        arrayA = cz(arrayA, 69)
        arrayA = Array(arrayA[2..<arrayA.count])
        arrayA = arrayA.reversed()
        return String(arrayA)
    }
    func cz(_ a:Array<Character>, _ b:Int)->Array<Character> {
        var arrayA = a
        let c = a[0]
        arrayA[0] = a[b % a.count];
        arrayA[b] = c
        return arrayA
    }
    

    But I think that this algorithm isn't enough, it decrypt the signature following a specific rule. In fact , according with this perl script (youtubedown from Jamie Zawinski) the algorithm change everytime and the script collect a list of rules and algorithms during days!. So far, only three commands are used in the ciphers, so we can represent them compactly:

    # - r  = reverse the string;
    # - sN = slice from character N to the end;
    # - wN = swap 0th and Nth character.
    

    I think that the best way is to realize something like:

    func decryptChiper(_ commands:String, signature:String)->String {
        var a = Array(signature.characters)
        let cmdArray:[String]! = commands.components(separatedBy: " ")
        for cmd in cmdArray {
            var value:Int!
            if cmd.characters.count>1 {
                let secondChar = cmd.index(cmd.startIndex, offsetBy: 1)
                value = Int(cmd.substring(from:secondChar))
            }
    
            switch cmd[cmd.startIndex] {
            case "r": a = a.reversed()
            case "s":
                if let sliceFrom = value {
                    a = Array(a[sliceFrom..<a.count])
                }
            case "w":
                if let swapValue = value {
                    a = swap(a,swapValue)
                }
            default:break
            }
        }
        return String(a)
    }
    
    func swap(_ a:Array<Character>, _ b:Int)->Array<Character> {
        var arrayA = a
        let c = a[0]
        arrayA[0] = a[b % a.count];
        arrayA[b] = c
        return arrayA
    }
    

    Usage:

    To make an example following that Akhilesh answer:

    let signature = "D3D3434498D70C3080D9B084E48350F6519A9E9A71094.25F300BB180DDDD918EE0EBEDD174EE5D874EFEFF"
    let decryptedSign = decryptChiper("w61 w5 r s2 w69 s2 r", signature: signature )
    print(decryptedSign)
    

    Output:

    33D3494498D70C3E80D9B084E48350F6519A9E9A71094.25F300BB180DDDDD18EE0EBEDD174EE5D874E
    
    0 讨论(0)
  • 2020-12-04 17:47

    Ye old s.ytimg.com/yts/jsbin/html5player-vfltdb6U3.js is now 404 and the new URL i think looks a bit more like hxxps://s.ytimg.com/yts/jsbin/player-en_US-vfl_cdzrt/base.js

    if you search the JavaScript you will find a bit of code that looks like this

    function(a,b,c)
    {
    a=new Mr(a);
    a.set("alr","yes");a.set("keepalive","yes");a.set("ratebypass","yes");a.set("mime",(0,window.encodeURIComponent)(b.mimeType.split(";")[0]));c&&a.set("signature",xr(c));return a},Jt=function(a,b){var c=Yr(b,"id"),c=c.replace(":",";");..............
    }
    

    The xr function that the above code calls looks like this

    xr=function(a)
    {
    a=a.split("");
    wr.rF(a,54);
    wr.fs(a,75);
    wr.N0(a,1);
    wr.rF(a,52);
    wr.N0(a,3);
    wr.fs(a,31);
    wr.rF(a,16);
    wr.fs(a,38);
    return a.join("")
    }
    

    After that i start to get a bit lost with the javascript and could do with a bit of help myself but talking about this on the code project gets you in troube.

    0 讨论(0)
提交回复
热议问题