vlc/vlc-2.0 | branch: master | Pierre Ynard <[email protected]> | 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 <[email protected]> > 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 _______________________________________________ vlc-commits mailing list [email protected] https://mailman.videolan.org/listinfo/vlc-commits
