当字典中的use_cipher_signature = true
返回时,Youtube正在为某些视频使用密码签名
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中解码密码的理智方法的帮助都将受到赞赏。
答案 0 :(得分:22)
网址结构和密码不断改变Youtube。目前,解密密码签名的最佳方法解释如下:
Youtube中的加密签名只是“加密”签名,您必须根据播放器文件(HTML5播放器或Flash播放器)中的算法重新排列它们。
例如http://www.youtube.com/watch?v=UxxajLWwzqY
目前正在使用以下HTML5播放器文件://s.ytimg.com/yts/jsbin/html5player-vfltdb6U3.js
在此文件中,您可以通过搜索“sig”轻松搜索签名解密代码。在这种情况下,Algo是:
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
};
以上是解密代码。
但请注意,它会在更改播放器文件时不断更改,因此您必须点击正在使用的播放器文件。
另外,要下载带有密码签名的视频,您必须使用相同的用户代理标头,发送相同的IP地址请求以及提取后不久发送请求来处理相同的cookie。所有这些在某些时候都是必需的
如果对密码解密算法感兴趣,请访问CipherAPI
另一个很酷的API:TYstream API
答案 1 :(得分:2)
旧的s.ytimg.com/yts/jsbin/html5player-vfltdb6U3.js
现在是404,我觉得新的网址看起来更像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并且可以自己做一些帮助,但在代码项目中谈论这个问题会让你陷入困境。
答案 2 :(得分:1)
我已经为iOS人员翻译了 Swift 3 Akhilesh的答案:
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
}
但我认为这个算法不够,它会根据特定规则解密签名。实际上,根据this perl脚本(来自Jamie Zawinski的youtubedown),算法每次都会更改,并且脚本会在几天内收集规则和算法列表!到目前为止,密码中只使用了三个命令,因此我们可以紧凑地表示它们:
# - 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
}
用法:
在Akhilesh回答之后做一个例子:
let signature = "D3D3434498D70C3080D9B084E48350F6519A9E9A71094.25F300BB180DDDD918EE0EBEDD174EE5D874EFEFF"
let decryptedSign = decryptChiper("w61 w5 r s2 w69 s2 r", signature: signature )
print(decryptedSign)
输出:
33D3494498D70C3E80D9B084E48350F6519A9E9A71094.25F300BB180DDDDD18EE0EBEDD174EE5D874E