[vlc-commits] youtube.lua: descramble signatures by parsing javascript code
Pierre Ynard
git at videolan.org
Mon Dec 9 19:39:37 CET 2013
vlc/vlc-2.0 | branch: master | Pierre Ynard <linkfanel at yahoo.fr> | Sat Sep 7 19:52:04 2013 +0200| [acfe29afa106ffff993bdf4b5b4281fab3e9df26] | committer: Felix Paul Kühne
youtube.lua: descramble signatures by parsing javascript code
This should be more resilient to updates.
Fixes #9217
(cherry picked from commit 95690e162601bc1253c7cb2099cd8a3e2da64aff)
Signed-off-by: Felix Paul Kühne <fkuehne at videolan.org>
> http://git.videolan.org/gitweb.cgi/vlc/vlc-2.0.git/?a=commit;h=acfe29afa106ffff993bdf4b5b4281fab3e9df26
---
share/lua/playlist/youtube.lua | 107 ++++++++++++++++++++++++++++++++++++----
1 file changed, 98 insertions(+), 9 deletions(-)
diff --git a/share/lua/playlist/youtube.lua b/share/lua/playlist/youtube.lua
index 4effd37..5778adb 100644
--- a/share/lua/playlist/youtube.lua
+++ b/share/lua/playlist/youtube.lua
@@ -67,6 +67,83 @@ function get_fmt( fmt_list )
return fmt
end
+-- Descramble the URL signature using the javascript code that does that
+-- in the web page
+function js_descramble( sig, js_url )
+ -- Fetch javascript code
+ local js = vlc.stream( js_url )
+ if not js then
+ return sig
+ end
+ local lines = {}
+
+ -- Look for the descrambler function's name
+ local descrambler = nil
+ while not descrambler do
+ local line = js:readline()
+ if not line then
+ vlc.msg.err( "Couldn't process youtube video URL, please check for updates to this script" )
+ return sig
+ end
+ -- Buffer lines for later, so we don't have to make a second
+ -- HTTP request later
+ table.insert( lines, line )
+ -- c&&(b.signature=ij(c));
+ descrambler = string.match( line, "%.signature=(.-)%(" )
+ end
+
+ -- Fetch the code of the descrambler function. Example:
+ -- function ij(a){a=a.split("");a=a.reverse();a=jj(a,12);a=jj(a,32);a=a.reverse();a=jj(a,34);a=a.slice(3);a=jj(a,35);a=jj(a,42);a=a.slice(2);return a.join("")}
+ local rules = nil
+ while not rules do
+ local line
+ if #lines > 0 then
+ line = table.remove( lines )
+ else
+ line = js:readline()
+ if not line then
+ vlc.msg.err( "Couldn't process youtube video URL, please check for updates to this script" )
+ return sig
+ end
+ end
+ rules = string.match( line, "function "..descrambler.."%([^)]*%){(.-)}" )
+ end
+
+ -- Parse descrambling rules one by one and apply them on the
+ -- signature as we go
+ for rule in string.gmatch( rules, "[^;]+" ) do
+ -- a=a.reverse();
+ if string.match( rule, "%.reverse%(" ) then
+ sig = string.reverse( sig )
+ else
+
+ -- a=a.slice(3);
+ local len = string.match( rule, "%.slice%((%d+)%)" )
+ if len then
+ sig = string.sub( sig, len + 1 )
+ else
+
+ -- a=jj(a,32);
+ -- This is known to be a function swapping the first and nth
+ -- characters:
+ -- function jj(a,b){var c=a[0];a[0]=a[b%a.length];a[b]=c;return a}
+ local idx = string.match( rule, "=..%([^,]+,(%d+)%)" )
+ if idx then
+ idx = tonumber( idx )
+ if not idx then idx = 0 end
+ if idx > 1 then
+ sig = string.gsub( sig, "^(.)("..string.rep( ".", idx - 1 )..")(.)(.*)$", "%3%2%1%4" )
+ elseif idx == 1 then
+ sig = string.gsub( sig, "^(.)(.)", "%2%1" )
+ end
+ end end end
+
+ -- Simply ignore other statements, in particular initial split
+ -- and final join and return statements
+ end
+ return sig
+end
+
function descramble81( sig )
sig = string.reverse( sig )
local s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11,s12,s13 =
@@ -74,21 +151,27 @@ function descramble81( sig )
return s3..s2..s5..s4..s1..s6..s13..s8..s7..s10..s9..s12..s11
end
-local descramblers = { [81] = descramble81 }
+local descramblers = {
+ --[81] = descramble81
+ }
-function descramble( sig )
+function descramble( sig, js_url )
vlc.msg.dbg( "Found "..string.len( sig ).."-character scrambled signature for youtube video URL, attempting to descramble... " )
- local descrambler = descramblers[string.len( sig )]
- if descrambler then
- sig = descrambler( sig )
+ if js_url then
+ sig = js_descramble( sig, js_url )
else
- vlc.msg.err( "Couldn't process youtube video URL, please check for updates to this script" )
+ local descrambler = descramblers[string.len( sig )]
+ if descrambler then
+ sig = descrambler( sig )
+ else
+ vlc.msg.err( "Couldn't process youtube video URL, please check for updates to this script" )
+ end
end
return sig
end
-- Parse and pick our video URL
-function pick_url( url_map, fmt )
+function pick_url( url_map, fmt, js_url )
local path = nil
for stream in string.gmatch( url_map, "[^,]+" ) do
-- Apparently formats are listed in quality order,
@@ -104,7 +187,7 @@ function pick_url( url_map, fmt )
-- Scrambled signature
sig = string.match( stream, "s=([^&,]+)" )
if sig then
- sig = descramble( sig )
+ sig = descramble( sig, js_url )
end
end
local signature = ""
@@ -176,6 +259,12 @@ function parse()
-- JSON parameters, also formerly known as "swfConfig",
-- "SWF_ARGS", "swfArgs", "PLAYER_CONFIG", "playerConfig" ...
if string.match( line, "ytplayer%.config" ) then
+
+ local js_url = string.match( line, "\"js\": \"(.-)\"" )
+ if js_url then
+ js_url = string.gsub( js_url, "\\/", "/" )
+ end
+
if not fmt then
fmt_list = string.match( line, "\"fmt_list\": \"(.-)\"" )
if fmt_list then
@@ -188,7 +277,7 @@ function parse()
if url_map then
-- FIXME: do this properly
url_map = string.gsub( url_map, "\\u0026", "&" )
- path = pick_url( url_map, fmt )
+ path = pick_url( url_map, fmt, js_url )
end
if not path then
More information about the vlc-commits
mailing list