New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add rick roll support #3
Comments
Found a mention of signatureCipher in base.js : RC = function (a) {
var b = g.M(a, qta) || a.signatureCipher;
a = { AT: false, zx: "", xz: "", s: "" };
if (!b) return a;
b = dw(b);
a.AT = true;
a.zx = b.url;
a.xz = b.sp;
a.s = b.s;
return a;
}; Which is then called here : e = RC(n);
e = tG(e.zx || n.url || "", e.xz, e.s); The definition of tG = function (a, b, c) {
b = void 0 === b ? "" : b;
c = void 0 === c ? "" : c;
a = new g.oD(a, true);
a.set("alr", "yes");
c && ((c = Gta(decodeURIComponent(c))), a.set(b, encodeURIComponent(c)));
return a;
};
g.oD.prototype.set = function (a, b) {
this.j[a] !== b && ((this.j[a] = b), (this.url = ""));
}; The definition of Gta = function (a) {
a = a.split("");
nD.uC(a, 61);
nD.ei(a, 50);
nD.Ua(a, 3);
nD.uC(a, 53);
nD.ei(a, 72);
nD.uC(a, 24);
nD.ei(a, 72);
nD.uC(a, 17);
nD.Ua(a, 1);
return a.join("");
};
var nD = {
Ua: function (a, b) {
a.splice(0, b);
},
ei: function (a) {
a.reverse();
},
uC: function (a, b) {
var c = a[0];
a[0] = a[b % a.length];
a[b % a.length] = c;
},
}; |
With all the above I wrote this script : var g = {};
g.ne = function (a) {
return encodeURIComponent(String(a));
};
Xh = function (a, b, c) {
if (Array.isArray(b))
for (var d = 0; d < b.length; d++) Xh(a, String(b[d]), c);
else null != b && c.push(a + ("" === b ? "" : "=" + g.ne(b)));
};
g.$h = function (a) {
var b = [],
c;
for (c in a) Xh(c, a[c], b);
return b.join("&");
};
var oe = function (a) {
return decodeURIComponent(a.replace(/\+/g, " "));
};
var Ana = /^[\w.]*$/,
yna = { q: !0, search_query: !0 },
xna = String(bw);
var wna = function (a) {
return a && a.match(Ana) ? a : oe(a);
};
var bw = function (a, b) {
b = a.split(b);
for (var c = {}, d = 0, e = b.length; d < e; d++) {
var f = b[d].split("=");
if ((1 == f.length && f[0]) || 2 == f.length)
try {
var h = wna(f[0] || ""),
l = wna(f[1] || "");
h in c
? Array.isArray(c[h])
? g.vb(c[h], l)
: (c[h] = [c[h], l])
: (c[h] = l);
} catch (q) {
var m = q,
n = f[0],
p = String(bw);
m.args = [
{
key: n,
value: f[1],
query: a,
method: xna == p ? "unchanged" : p,
},
];
yna.hasOwnProperty(n) || console.log(m);
throw q;
}
}
return c;
};
dw = function (a) {
"?" == a.charAt(0) && (a = a.substr(1));
return bw(a, "&");
};
RC = function (a) {
var b = a.signatureCipher;
a = { AT: !1, zx: "", xz: "", s: "" };
if (!b) return a;
b = dw(b);
a.AT = !0;
a.zx = b.url;
a.xz = b.sp;
a.s = b.s;
return a;
};
var nD = {
Ua: function (a, b) {
a.splice(0, b);
},
ei: function (a) {
a.reverse();
},
uC: function (a, b) {
var c = a[0];
a[0] = a[b % a.length];
a[b % a.length] = c;
},
};
Gta = function (a) {
a = a.split("");
nD.uC(a, 61);
nD.ei(a, 50);
nD.Ua(a, 3);
nD.uC(a, 53);
nD.ei(a, 72);
nD.uC(a, 24);
nD.ei(a, 72);
nD.uC(a, 17);
nD.Ua(a, 1);
return a.join("");
};
var CD = {
Qk: function (a, b) {
var c = a[0];
a[0] = a[b % a.length];
a[b % a.length] = c;
},
BW: function (a) {
a.reverse();
},
CJ: function (a, b) {
a.splice(0, b);
},
};
Nta = function (a) {
a = a.split("");
CD.Qk(a, 17);
CD.CJ(a, 1);
CD.BW(a, 68);
CD.Qk(a, 65);
return a.join("");
};
g.oD = function (a, b) {
this.u = a;
this.D = void 0 === b ? false : b;
this.C = this.path = this.B = "";
this.j = {};
this.url = "";
this.alr = "";
};
g.oD.prototype.set = function (a, b) {
this.j[a] !== b && ((this.j[a] = b), (this.url = ""));
};
tG = function (a, b, c) {
b = void 0 === b ? "" : b;
c = void 0 === c ? "" : c;
a = new g.oD(a, true);
console.log({ a });
a.set("alr", "yes");
c && ((c = Nta(decodeURIComponent(c))), a.set(b, encodeURIComponent(c)));
return a;
};
g.t = function (a) {
var b =
"undefined" != typeof Symbol && Symbol.iterator && a[Symbol.iterator];
if (b) return b.call(a);
if ("number" == typeof a.length) return { next: baa(a) };
throw Error(String(a) + " is not an iterable or ArrayLike");
};
baa = function (a) {
var b = 0;
return function () {
return b < a.length ? { done: !1, value: a[b++] } : { done: !0 };
};
};
var GP = RC({
signatureCipher: 's=8%3DIoUisF9qiH88GKc%3DHbSju0aSjmCdE1iEd_YIoA1R8-0AEiA3fDP2ZjVpjlgxaPokvdgdU6EXMc97ULktYa3MxWjjKIAhIgRw8JQ0qOM&sp=sig&url=https://rr2---sn-f5o5-jhod.googlevideo.com/videoplayback%3Fexpire%3D1677998710%26ei%3DFuYDZOvcF5rA1wbqpY-QAg%26ip%3D105.66.0.249%26id%3Do-AL9i4R7ZWDbkqGFcpqCjR64ZM9jhfSeNUHS2aDbJObwp%26itag%3D396%26aitags%3D133%252C134%252C135%252C136%252C137%252C160%252C242%252C243%252C244%252C247%252C248%252C278%252C394%252C395%252C396%252C397%252C398%252C399%26source%3Dyoutube%26requiressl%3Dyes%26mh%3D7c%26mm%3D31%252C29%26mn%3Dsn-f5o5-jhod%252Csn-h5q7knes%26ms%3Dau%252Crdu%26mv%3Dm%26mvi%3D2%26pl%3D24%26initcwndbps%3D277500%26vprv%3D1%26mime%3Dvideo%252Fmp4%26ns%3DB5uSVdIbFLxYS_fhKnn8WxIL%26gir%3Dyes%26clen%3D5953258%26dur%3D212.040%26lmt%3D1674230525337110%26mt%3D1677976618%26fvip%3D4%26keepalive%3Dyes%26fexp%3D24007246%26c%3DWEB%26txp%3D4537434%26n%3DHGV37DW5jPmqkk_%26sparams%3Dexpire%252Cei%252Cip%252Cid%252Caitags%252Csource%252Crequiressl%252Cvprv%252Cmime%252Cns%252Cgir%252Cclen%252Cdur%252Clmt%26lsparams%3Dmh%252Cmm%252Cmn%252Cms%252Cmv%252Cmvi%252Cpl%252Cinitcwndbps%26lsig%3DAG3C_xAwRQIhAIAFJFr1v__Yzrvr6cZ5xvpqP3F2VJtTAFFi0CdOeapGAiBV65ILOFQ1nshXJqO0X0aj0y6XNyr7ke2rK_CreaoQMg%253D%253D'
});
let e = tG(GP.zx || "", GP.xz, GP.s);
console.log({ e });
console.log(GP.zx + '&sig=' + e.j.sig); The resulting URL still produces a 403. After comparing it with a real URL, I realized that the The real URL also includes extra parameters, but it successfully loaded the video after I removed them so the issue isn't there. I also tested by removing |
I compared these results with some of the articles out there and found that this is indeed the right approach, even though the resulting URL fails with 403. As I was reading this I noticed that the decryption function not only has a different name, but the algorithm itself is different from mine. I did some tests and it turns out that Youtube changes it on each page load apparently. After grabbing the base.js file from the page where I found the above signature and trying the new algorithm (I updated the code above to use
The trickiest part is going to involve parsing the decryption sequence. |
Still not sure why Youtube does this for certain videos only. So far I noticed that it does it for songs, but maybe the rule extends to all copyrighted content. |
The source code for https://www.youtube.com/watch?v=dQw4w9WgXcQ doesn't contain the
"itag":18,url:
string. Instead, video URLs are encoded in a signatureCipher field :The text was updated successfully, but these errors were encountered: