Youtube использует подпись для некоторых видео, когда use_cipher_signature = true
в словаре, возвращаемом через http://www.youtube.com/get_video_info?&video_id=Video_Id
Пример id: _JQH3G0cCtY
Шифрованная подпись – это фактически скремблированная подпись, которую любой может отлаживать несколькими наборами работающих подписей. Но Youtube продолжает менять скремблирующий алгоритм. Я видел несколько загрузчиков видео Youtube, которые работают плавно, не затрагивая эту меняющуюся игру. Я думаю, что они проверяют игрока и извлекают скрипт декодирования из файла игрока, и, следовательно, он удерживает их.
Мне нужна некоторая помощь в отношении фактической техники для использования в этом случае. Я знаю о программе «youtube-dl» – программе python для загрузки видео. Поскольку я плохо разбираюсь в python, я думаю, что они используют тот же подход.
Также есть JS-файл с пользовательским скриптом, доступный здесь: http://userscripts.org/scripts/show/25105 , который делает то же самое.
Любая помощь по разумному подходу к расшифровке шифрованного кода в PHP или JS будет оценена по достоинству.
Структура Url и код шифрования продолжают меняться на Youtube. В настоящее время наилучший подход к декодированию сигнатуры шифрования объясняется ниже:
Шифрованная подпись в Youtube – это просто «скремблированная» подпись, которую вы должны переставить в соответствии с Алгоритмом, присутствующим в файле проигрывателя (проигрыватель HTML5 или Flash Player).
Например, http://www.youtube.com/watch?v=UxxajLWwzqY
в настоящее время использует следующий файл игрока HTML5: //s.ytimg.com/yts/jsbin/html5player-vfltdb6U3.js
в этом файле вы можете легко найти код расшифровки подписи, выполнив поиск 'sig'. Здесь в этом случае Алго:
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 };
Выше – код расшифровки.
Но имейте в виду, что он продолжает меняться, когда они меняют файл плеера, поэтому вам нужно продолжать использовать файл игрока.
Также для загрузки видео с помощью шифрованной подписи вам необходимо позаботиться о отправке одинаковых файлов cookie, используя один и тот же заголовок пользовательского агента, отправив запрос с того же IP-адреса и отправив запрос вскоре после извлечения. Все это было или было необходимо в какой-то момент
Если вас интересует алгоритм шифрования шифрования, посетите CipherAPI
Еще один классный API: API TYstream
Ye old s.ytimg.com/yts/jsbin/html5player-vfltdb6U3.js
теперь 404, и новый URL-адрес, который, по моему мнению, выглядит скорее как hxxps://s.ytimg.com/yts/jsbin/player-en_US-vfl_cdzrt/base.js
если вы ищете JavaScript, вы найдете немного кода, который выглядит следующим образом:
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(":",";");.............. }
Функция xr
вышеприведенным кодом, выглядит так:
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("") }
После этого я начинаю немного проигрывать с помощью javascript и могу сделать с собой немного помощи, но об этом в проекте кода вы попадаете в troube.
Я перевел на Swift 3 ответ Ахилеша для людей iOS:
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 }
Но я думаю, что этого алгоритма недостаточно, он расшифровывает подпись по определенному правилу. Фактически, согласно этому сценарию perl (youtubedown от Jamie Zawinski) алгоритм меняется каждый раз, и скрипт собирает список правил и алгоритмов в течение дней !. До сих пор в шифрах использовались только три команды, поэтому мы можем представить их компактно:
# - r = reverse the string; # - sN = slice from character N to the end; # - wN = swap 0th and Nth character.
Я думаю, что лучший способ – реализовать что-то вроде:
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 }
по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 }
Применение:
Чтобы привести пример после ответа Ахилеша :
let signature = "D3D3434498D70C3080D9B084E48350F6519A9E9A71094.25F300BB180DDDD918EE0EBEDD174EE5D874EFEFF" let decryptedSign = decryptChiper("w61 w5 r s2 w69 s2 r", signature: signature ) print(decryptedSign)
Выход :
33D3494498D70C3E80D9B084E48350F6519A9E9A71094.25F300BB180DDDDD18EE0EBEDD174EE5D874E