Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • videolan/vlc
  • chouquette/vlc
  • bakiewicz.marek122/vlc
  • devnexen/vlc
  • rohanrajpal/vlc
  • blurrrb/vlc
  • gsoc/gsoc2019/darkapex/vlc
  • b1ue/vlc
  • fkuehne/vlc
  • magsoft/vlc
  • chub/vlc
  • cramiro9/vlc
  • robUx4/vlc
  • rom1v/vlc
  • akshayaky/vlc
  • tmk907/vlc
  • akymaster/vlc
  • govind.sharma/vlc
  • psilokos/vlc
  • xjbeta/vlc
  • jahan/vlc
  • 1480c1/vlc
  • amanchande/vlc
  • aaqib/vlc
  • rist/vlc
  • apol/vlc
  • mindfreeze/vlc
  • alexandre-janniaux/vlc
  • sandsmark/vlc
  • jagannatharjun/vlc
  • gsoc/gsoc2020/matiaslgonzalez/vlc
  • gsoc/gsoc2020/jagannatharjun/vlc
  • mstorsjo/vlc
  • gsoc/gsoc2020/vedenta/vlc
  • gsoc/gsoc2020/arnav-ishaan/vlc
  • gsoc/gsoc2020/andreduong/vlc
  • fuzun/vlc
  • gsoc/gsoc2020/vatsin/vlc
  • gsoc/gsoc2020/sagid/vlc
  • yaron/vlc
  • Phoenix/vlc
  • Garf/vlc
  • ePiratWorkarounds/vlc
  • tguillem/vlc
  • jnqnfe/vlc
  • mdc/vlc
  • Vedaa/vlc
  • rasa/vlc
  • quink/vlc
  • yealo/vlc
  • aleksey_ak/vlc
  • ePirat/vlc
  • ilya.yanok/vlc
  • asenat/vlc
  • m/vlc
  • bunjee/vlc
  • BLumia/vlc
  • sagudev/vlc
  • hamedmonji30/vlc
  • nullgemm/vlc
  • DivyamAhuja/vlc
  • thesamesam/vlc
  • dag7/vlc
  • snehil101/vlc
  • haasn/vlc
  • jbk/vlc
  • ValZapod/vlc
  • mfkl/vlc
  • WangChuan/vlc
  • core1024/vlc
  • GhostVaibhav/vlc
  • dfuhrmann/vlc
  • davide.prade/vlc
  • tmatth/vlc
  • Courmisch/vlc
  • zouya/vlc
  • hpi/vlc
  • EwoutH/vlc
  • aleung27/vlc
  • hengwu0/vlc
  • saladin/vlc
  • ashuio/vlc
  • richselwood/vlc
  • verma16Ayush/vlc
  • chemicalflash/vlc
  • PoignardAzur/vlc
  • huangjieNT/vlc
  • Blake-Haydon/vlc
  • AnuthaDev/vlc
  • gsoc/gsoc2021/mpd/vlc
  • nicolas_lequec/vlc
  • sambassaly/vlc
  • thresh/vlc
  • bonniegong/vlc
  • myaashish/vlc
  • stavros.vagionitis/vlc
  • ileoo/vlc
  • louis-santucci/vlc
  • cchristiansen/vlc
  • sabyasachi07/vlc
  • AbduAmeen/vlc
  • ashishb0410/vlc
  • urbanhusky/vlc
  • davidepietrasanta/vlc
  • riksleutelstad/vlc
  • jeremyVignelles/vlc
  • komh/vlc
  • iamjithinjohn/vlc
  • JohannesKauffmann/vlc2
  • kunglao/vlc
  • natzberg/vlc
  • jill/vlc
  • cwendling/vlc
  • adufou/vlc
  • ErwanAirone/vlc
  • HasinduDilshan10/vlc
  • vagrantc/vlc
  • rafiv/macos-bigsur-icon
  • Aymeriic/vlc
  • saranshg20/vlc
  • metzlove24/vlc
  • linkfanel/vlc
  • Ds886/vlc
  • metehan-arslan/vlc
  • Skantes/vlc
  • kgsandundananjaya96/vlc
  • mitchcapper/vlc
  • advaitgupta/vlc
  • StefanBruens/vlc
  • ratajs/vlc
  • T.M.F.B.3761/vlc
  • m222059/vlc
  • casemerrick/vlc
  • joshuaword2alt/vlc
  • sjwaddy/vlc
  • dima/vlc
  • Ybalrid/vlc
  • umxprime/vlc
  • eschmidt/vlc
  • vannieuwenhuysenmichelle/vlc
  • badcf00d/vlc
  • wesinator/vlc
  • louis/vlc
  • xqq/vlc
  • EmperorYP7/vlc
  • NicoLiam/vlc
  • loveleen/vlc
  • rofferom/vlc
  • rbultje/vlc
  • TheUnamed/vlc
  • pratiksharma341/vlc
  • Saurab17/vlc
  • purist.coder/vlc
  • Shuicheng/vlc
  • mdrrubel292/vlc
  • silverbleu00/vlc
  • metif12/vlc
  • asher-m/vlc
  • jeffk/vlc
  • Brandonbr1/vlc
  • beautyyuyanli/vlc
  • rego21/vlc
  • muyangren907/vlc
  • collectionbylawrencejason/vlc
  • evelez/vlc
  • GSMgeeth/vlc
  • Oneric/vlc
  • TJ5/vlc
  • XuanTung95/vlc
  • darrenjenny21/vlc
  • Trenly/vlc
  • RockyTDR/vlc
  • mjakubowski/vlc
  • caprica/vlc
  • ForteFrankie/vlc
  • seannamiller19/vlc
  • junlon2006/vlc
  • kiwiren6666/vlc
  • iuseiphonexs/vlc
  • fenngtun/vlc
  • Rajdutt999/vlc
  • typx/vlc
  • leon.vitanos/vlc
  • robertogarci0938/vlc
  • gsoc/gsoc2022/luc65r/vlc-mpd
  • skeller/vlc
  • MCJack123/vlc
  • luc65r/vlc-mpd
  • popov895/vlc
  • claucambra/vlc
  • brad/vlc
  • matthewmurua88/vlc
  • Tomas8874/vlc
  • philenotfound/vlc
  • makita-do3/vlc
  • LZXCorp/vlc
  • mar0x/vlc
  • senojetkennedy0102/vlc
  • shaneb243/vlc
  • ahmadbader/vlc
  • rajduttcse26/vlc-audio-filters
  • Juniorzito8415/vlc
  • achernyakov/vlc
  • lucasjetgroup/vlc
  • pupdoggy666/vlc
  • gmde9363/vlc
  • alexnwayne/vlc
  • bahareebrahimi781/vlc
  • hamad633666/vlc
  • umghof3112/vlc
  • joe0199771874/vlc
  • Octocats66666666/vlc
  • jjm_223/vlc
  • btech10110.19/vlc
  • sunnykfc028/vlc-audio-filters
  • loic/vlc
  • nguyenminhducmx1/vlc
  • JanekKrueger/vlc
  • bstubbington2/vlc
  • rcombs/vlc
  • Ordissimo/vlc
  • king7532/vlc
  • noobsauce101/vlc
  • schong0525/vlc
  • myQwil/vlc
  • apisbg91/vlc
  • geeboy0101017/vlc
  • kim.faughey/vlc
  • nurupo/vlc
  • yyusea/vlc
  • 0711235879.khco/vlc
  • ialo/vlc
  • iloveyeye2/vlc
  • gdtdftdqtd/vlc
  • leandroconsiglio/vlc
  • AndyHTML2012/vlc
  • ncz/vlc
  • lucenticus/vlc
  • knr1931/vlc
  • kjoonlee/vlc
  • chandrakant100/vlc-qt
  • johge42/vlc
  • polter/vlc
  • hexchain/vlc
  • Tushwrld/vlc
  • mztea928/vlc
  • jbelloncastro/vlc
  • alvinhochun/vlc
  • ghostpiratecrow/vlc
  • ujjwaltwitx/vlc
  • alexsonarin06/vlc
  • adrianbon76/vlc
  • altsod/vlc
  • damien.lucas44/vlc
  • dmytrivtaisa/vlc
  • utk202/vlc
  • aaxhrj/vlc
  • thomas.hermes/vlc
  • structurenewworldorder/vlc
  • slomo/vlc
  • wantlamy/vlc
  • musc.o3cminc/vlc
  • thebarshablog/vlc
  • kerrick/vlc
  • kratos142518/vlc
  • leogps/vlc
  • vacantron/vlc
  • luna_koly/vlc
  • Ratio2/vlc
  • anuoshemohammad/vlc
  • apsun/vlc
  • aaa1115910/vlc
  • alimotmoyo/vlc
  • Ambossmann/vlc
  • Sam-LearnsToCode/vlc
  • Chilledheart/vlc
  • Labnann/vlc
  • ktcoooot1/vlc
  • mohit-marathe/vlc
  • johnddx/vlc
  • manstabuk/vlc
  • Omar-ahmed314/vlc
  • vineethkm/vlc
  • 9Enemi86/vlc
  • radoslav.m.panteleev/vlc
  • ashishami2002/vlc
  • Corbax/vlc
  • firnasahmed/vlc
  • pelayarmalam4/vlc
  • c0ff330k/vlc
  • shikhindahikar/vlc
  • l342723951/vlc
  • christianschwandner/vlc
  • douniwan5788/vlc
  • 7damian7/vlc
  • ferdnyc/vlc
  • f.ales1/vlc
  • pandagby/vlc
  • BaaBaa/vlc
  • jewe37/vlc
  • w00drow/vlc
  • russelltg/vlc
  • ironicallygod/vlc
  • soumyaDghosh/vlc
  • linzihao1999/vlc
  • deyayush6/vlc
  • mibi88/vlc
  • newabdallah10/vlc
  • jhorbincolombia/vlc
  • rimvihaqueshupto/vlc
  • andrewkhon98/vlc
  • fab78/vlc
  • lapaz17/vlc
  • amanna13/vlc
  • mdakram28/vlc
  • 07jw1980/vlc
  • sohamgupta/vlc
  • Eson-Jia1/vlc
  • Sumou/vlc
  • vikram-kangotra/vlc
  • chalice191/vlc
  • olivercalder/vlc
  • aaasg4001/vlc
  • zipdox/vlc
  • kwizart/vlc
  • Dragon-S/vlc
  • jdemeule/vlc
  • gabriel_lt/vlc
  • locutusofborg/vlc
  • sammirata/vlc-librist
  • another/vlc
  • Benjamin_Loison/vlc
  • ahmedmoselhi/vlc
  • petergaal/vlc
  • huynhsontung/vlc
  • dariusmihut/vlc
  • tvermaashutosh/vlc
  • buti/vlc
  • Niram7777/vlc
  • rohan-here/vlc
  • balaji-sivasakthi/vlc
  • rlindner81/vlc
  • Kakadus/vlc
  • djain/vlc
  • ABBurmeister/vlc
  • craighuggins/vlc
  • orbea/vlc
  • maxos/vlc
  • aakarshmj/vlc
  • kblaschke/vlc
  • ankitm/vlc
  • advait-0/vlc
  • mohak2003/vlc
  • yselkowitz/vlc
  • AZM999/vlc-azm
  • andrey.turkin/vlc
  • Disha-Baghel/vlc
  • nowrep/vlc
  • Apeng/vlc
  • Choucroute_melba/vlc
  • autra/vlc
  • eclipseo/vlc
  • fhuber/vlc
  • olafhering/vlc
  • sdasda7777/vlc
  • 1div0/vlc
  • skosnits/vlc-extended-playlist-support
  • dnicolson/vlc
  • Timshel/vlc
  • octopols/vlc
  • MangalK/vlc
  • nima64/vlc
  • misawai/vlc
  • Alexander-Wilms/vlc
  • Maxime2/vlc-fork-for-visualizer
  • ww/vlc
  • jeske/vlc
  • sgross-emlix/vlc
  • morenonatural/vlc
  • freakingLovesVLC/vlc
  • borisgolovnev/vlc
  • mpromonet/vlc
  • diogo.simao-marques/vlc
  • masstock/vlc
  • pratikpatel8982/vlc
  • hugok79/vlc
  • longervision/vlc
  • abhiudaysurya/vlc
  • rishabhgarg/vlc
  • tumic/vlc
  • cart/vlc
  • shubham442/vlc
  • Aditya692005/vlc
  • sammirata/vlc4
  • syrykh/vlc
  • Vvorcun/macos-new-icon
  • AyaanshC/vlc
  • nasso/vlc
  • Quark/vlc
  • sebastinas/vlc
  • rhstone/vlc
  • talregev/vlc
  • Managor/vlc
403 results
Show changes
Commits on Source (8)
--[[
$Id$
Copyright © 2007-2020 the VideoLAN team
Copyright © 2007-2021 the VideoLAN team
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -108,31 +108,339 @@ function js_extract( js, pattern )
return ex
end
end
vlc.msg.err( "Couldn't process youtube video URL, please check for updates to this script" )
return nil
end
-- Descramble the "n" parameter using the javascript code that does that
-- in the web page
function n_descramble( nparam, js )
if not js then
return nil
end
-- Look for the descrambler function's name
-- a.D&&(b=a.get("n"))&&(b=lha(b),a.set("n",b))}};
local descrambler = js_extract( js, '[=%(,&|](...?)%(.%),.%.set%("n",' )
if not descrambler then
vlc.msg.dbg( "Couldn't extract YouTube video throttling parameter descrambling function name" )
return nil
end
-- Fetch the code of the descrambler function
-- lha=function(a){var b=a.split(""),c=[310282131,"KLf3",b,null,function(d,e){d.push(e)},-45817231, [data and transformations...] ,1248130556];c[3]=c;c[15]=c;c[18]=c;try{c[40](c[14],c[2]),c[25](c[48]),c[21](c[32],c[23]), [scripted calls...] ,c[25](c[33],c[3])}catch(d){return"enhanced_except_4ZMBnuz-_w8_"+a}return b.join("")};
local code = js_extract( js, "^"..descrambler.."=function%([^)]*%){(.-)};" )
if not code then
vlc.msg.dbg( "Couldn't extract YouTube video throttling parameter descrambling code" )
return nil
end
-- Split code into two main sections: 1/ data and transformations,
-- and 2/ a script of calls
local datac, script = string.match( code, "c=%[(.*)%];.-;try{(.*)}catch%(" )
if ( not datac ) or ( not script ) then
vlc.msg.dbg( "Couldn't extract YouTube video throttling parameter descrambling rules" )
return nil
end
-- Split "n" parameter into a table as descrambling operates on it
-- as one of several arrays
local n = {}
for c in string.gmatch( nparam, "." ) do
table.insert( n, c )
end
-- Helper
local table_len = function( tab )
local len = 0
for i, val in ipairs( tab ) do
len = len + 1
end
return len
end
-- Common routine shared by the compound transformations,
-- compounding the "n" parameter with an input string,
-- character by character using a Base64 alphabet.
-- d.forEach(function(l,m,n){this.push(n[m]=h[(h.indexOf(l)-h.indexOf(this[m])+m-32+f--)%h.length])},e.split(""))
local compound = function( ntab, str, alphabet, charcode )
if ntab ~= n or type( str ) ~= "string" then
return true
end
local input = {}
for c in string.gmatch( str, "." ) do
table.insert( input, c )
end
local len = string.len( alphabet )
for i, c in ipairs( ntab ) do
if type( c ) ~= "string" then
return true
end
local pos1 = string.find( alphabet, c, 1, true )
local pos2 = string.find( alphabet, input[i], 1, true )
if ( not pos1 ) or ( not pos2 ) then
return true
end
local pos = ( pos1 - pos2 + charcode - 32 ) % len
local newc = string.sub( alphabet, pos + 1, pos + 1 )
ntab[i] = newc
table.insert( input, newc )
end
end
-- The data section contains among others function code for a number
-- of transformations, most of which are basic array operations.
-- We can match these functions' code to identify them, and emulate
-- the corresponding transformations.
local trans = {
reverse = {
func = function( tab )
local len = table_len( tab )
local tmp = {}
for i, val in ipairs( tab ) do
tmp[len - i + 1] = val
end
for i, val in ipairs( tmp ) do
tab[i] = val
end
end,
match = {
-- function(d){d.reverse()}
-- function(d){for(var e=d.length;e;)d.push(d.splice(--e,1)[0])}
"^function%(d%)",
}
},
append = {
func = function( tab, val )
table.insert( tab, val )
end,
match = {
-- function(d,e){d.push(e)}
"^function%(d,e%){d%.push%(e%)},",
}
},
remove = {
func = function( tab, i )
if type( i ) ~= "number" then
return true
end
i = i % table_len( tab )
table.remove( tab, i + 1 )
end,
match = {
-- function(d,e){e=(e%d.length+d.length)%d.length;d.splice(e,1)}
"^[^}]-;d%.splice%(e,1%)},",
}
},
swap = {
func = function( tab, i )
if type( i ) ~= "number" then
return true
end
i = i % table_len( tab )
local tmp = tab[1]
tab[1] = tab[i + 1]
tab[i + 1] = tmp
end,
match = {
-- function(d,e){e=(e%d.length+d.length)%d.length;var f=d[0];d[0]=d[e];d[e]=f}
-- function(d,e){e=(e%d.length+d.length)%d.length;d.splice(0,1,d.splice(e,1,d[0])[0])}
"^[^}]-;var f=d%[0%];d%[0%]=d%[e%];d%[e%]=f},",
"^[^}]-;d%.splice%(0,1,d%.splice%(e,1,d%[0%]%)%[0%]%)},",
}
},
rotate = {
func = function( tab, shift )
if type( shift ) ~= "number" then
return true
end
local len = table_len( tab )
shift = shift % len
local tmp = {}
for i, val in ipairs( tab ) do
tmp[( i - 1 + shift ) % len + 1] = val
end
for i, val in ipairs( tmp ) do
tab[i] = val
end
end,
match = {
-- function(d,e){for(e=(e%d.length+d.length)%d.length;e--;)d.unshift(d.pop())}
-- function(d,e){e=(e%d.length+d.length)%d.length;d.splice(-e).reverse().forEach(function(f){d.unshift(f)})}
"^[^}]-d%.unshift%(d.pop%(%)%)},",
"^[^}]-d%.unshift%(f%)}%)},",
}
},
-- Compound transformations first build a variation of a
-- Base64 alphabet, then in a common section, compound the
-- "n" parameter with an input string, character by character.
compound1 = {
func = function( ntab, str )
return compound( ntab, str, "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_", 96 )
end,
match = {
-- function(d,e){for(var f=64,h=[];++f-h.length-32;)switch(f){case 58:f=96;continue;case 91:f=44;break;case 65:f=47;continue;case 46:f=153;case 123:f-=58;default:h.push(String.fromCharCode(f))} [ compound... ] }
"^[^}]-case 58:f=96;",
}
},
compound2 = {
func = function( ntab, str )
return compound( ntab, str,"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_", 96 )
end,
match = {
-- function(d,e){for(var f=64,h=[];++f-h.length-32;){switch(f){case 58:f-=14;case 91:case 92:case 93:continue;case 123:f=47;case 94:case 95:case 96:continue;case 46:f=95}h.push(String.fromCharCode(f))} [ compound... ] }
-- function(d,e){for(var f=64,h=[];++f-h.length-32;)switch(f){case 46:f=95;default:h.push(String.fromCharCode(f));case 94:case 95:case 96:break;case 123:f-=76;case 92:case 93:continue;case 58:f=44;case 91:} [ compound... ] }
"^[^}]-case 58:f%-=14;",
"^[^}]-case 58:f=44;",
}
},
-- Fallback
unid = {
func = function( )
vlc.msg.dbg( "Couldn't apply unidentified YouTube video throttling parameter transformation, aborting descrambling" )
return true
end,
match = {
}
},
}
-- The data section actually mixes input data, reference to the
-- "n" parameter array, and self-reference to its own array, with
-- transformation functions used to modify itself. We parse it
-- as such into a table.
local data = {}
datac = datac..","
while datac ~= "" do
local el = nil
-- Transformation functions
if string.match( datac, "^function%(" ) then
for name, tr in pairs( trans ) do
for i, match in ipairs( tr.match ) do
if string.match( datac, match ) then
el = tr.func
break
end
end
if el then
break
end
end
if not el then
el = trans.unid.func
vlc.msg.warn( "Couldn't parse unidentified YouTube video throttling parameter transformation" )
end
-- Compounding functions use a subfunction, so we need to be
-- more specific in how much parsed data we consume.
if el == trans.compound1.func or el == trans.compound2.func then
datac = string.match( datac, '^.-},e%.split%(""%)%)},(.*)$' )
else
datac = string.match( datac, "^.-},(.*)$" )
end
-- String input data
elseif string.match( datac, '^"[^"]*",' ) then
el, datac = string.match( datac, '^"([^"]*)",(.*)$' )
-- Integer input data
elseif string.match( datac, '^-?%d+,' ) then
el, datac = string.match( datac, "^(.-),(.*)$" )
el = tonumber( el )
-- Reference to "n" parameter array
elseif string.match( datac, '^b,' ) then
el = n
datac = string.match( datac, "^b,(.*)$" )
-- Replaced by self-reference to data array after its declaration
elseif string.match( datac, '^null,' ) then
el = data
datac = string.match( datac, "^null,(.*)$" )
else
vlc.msg.warn( "Couldn't parse unidentified YouTube video throttling parameter descrambling data" )
el = false -- Lua tables can't contain nil values
datac = string.match( datac, "^[^,]-,(.*)$" )
end
table.insert( data, el )
end
-- Debugging helper to print data array elements
local prd = function( el, tab )
if not el then
return "???"
elseif el == n then
return "n"
elseif el == data then
return "data"
elseif type( el ) == "string" then
return '"'..el..'"'
elseif type( el ) == "number" then
el = tostring( el )
if type( tab ) == "table" then
el = el.." -> "..( el % table_len( tab ) )
end
return el
else
for name, tr in pairs( trans ) do
if el == tr.func then
return name
end
end
return tostring( el )
end
end
-- The script section contains a series of calls to elements of
-- the data section array onto other elements of it: calls to
-- transformations, with a reference to the data array itself or
-- the "n" parameter array as first argument, and often input data
-- as a second argument. We parse and emulate those calls to follow
-- the descrambling script.
-- c[40](c[14],c[2]),c[25](c[48]),c[21](c[32],c[23]), [...]
for ifunc, itab, iarg in string.gmatch( script, "c%[(%d+)%]%(c%[(%d+)%]([^)]-)%)" ) do
iarg = string.match( iarg, ",c%[(%d+)%]" )
local func = data[tonumber( ifunc ) + 1]
local tab = data[tonumber( itab ) + 1]
local arg = iarg and data[tonumber( iarg ) + 1]
-- Uncomment to debug transformation chain
--vlc.msg.dbg( '"n" parameter transformation: '..prd( func ).."("..prd( tab )..( arg ~= nil and ( ", "..prd( arg, tab ) ) or "" )..") "..ifunc.."("..itab..( iarg and ( ", "..iarg ) or "" )..")" )
--local nprev = table.concat( n )
if type( func ) ~= "function" or type( tab ) ~= "table"
or func( tab, arg ) then
vlc.msg.dbg( "Invalid data type encountered during YouTube video throttling parameter descrambling transformation chain, aborting" )
vlc.msg.dbg( "Couldn't descramble YouTube throttling URL parameter: data transfer will get throttled" )
vlc.msg.err( "Couldn't process youtube video URL, please check for updates to this script" )
break
end
-- Uncomment to debug transformation chain
--local nnew = table.concat( n )
--if nprev ~= nnew then
-- vlc.msg.dbg( '"n" parameter transformation: '..nprev.." -> "..nnew )
--end
end
return table.concat( n )
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 = { stream = vlc.stream( js_url ), lines = {}, i = 0 }
if not js.stream then
vlc.msg.err( "Couldn't process youtube video URL, please check for updates to this script" )
return sig
function sig_descramble( sig, js )
if not js then
return nil
end
-- Look for the descrambler function's name
-- if(k.s){var l=k.sp,m=pt(decodeURIComponent(k.s));f.set(l,encodeURIComponent(m))}
-- Descrambler function name - 3 chars length
-- if(h.s){var l=h.sp,m=wja(decodeURIComponent(h.s));f.set(l,encodeURIComponent(m))}
-- k.s (from stream map field "s") holds the input scrambled signature
-- k.sp (from stream map field "sp") holds a parameter name (normally
-- "signature" or "sig") to set with the output, descrambled signature
local descrambler = js_extract( js, "[=%(,&|](%a?%a?%a?)%(decodeURIComponent%(.%.s%)%)" )
local descrambler = js_extract( js, "[=%(,&|](...?)%(decodeURIComponent%(.%.s%)%)" )
if not descrambler then
vlc.msg.dbg( "Couldn't extract youtube video URL signature descrambling function name" )
return sig
return nil
end
-- Fetch the code of the descrambler function
......@@ -140,15 +448,14 @@ function js_descramble( sig, js_url )
local rules = js_extract( js, "^"..descrambler.."=function%([^)]*%){(.-)};" )
if not rules then
vlc.msg.dbg( "Couldn't extract youtube video URL signature descrambling rules" )
return sig
return nil
end
-- Get the name of the helper object providing transformation definitions
local helper = string.match( rules, ";(..)%...%(" )
if not helper then
vlc.msg.dbg( "Couldn't extract youtube video URL signature transformation helper name" )
vlc.msg.err( "Couldn't process youtube video URL, please check for updates to this script" )
return sig
return nil
end
-- Fetch the helper object code
......@@ -156,7 +463,7 @@ function js_descramble( sig, js_url )
local transformations = js_extract( js, "[ ,]"..helper.."={(.-)};" )
if not transformations then
vlc.msg.dbg( "Couldn't extract youtube video URL signature transformation code" )
return sig
return nil
end
-- Parse the helper object to map available transformations
......@@ -208,7 +515,7 @@ function js_descramble( sig, js_url )
end
-- Parse and assemble video stream URL
function stream_url( params, js_url )
function stream_url( params, js )
local url = string.match( params, "url=([^&]+)" )
if not url then
return nil
......@@ -220,10 +527,11 @@ function stream_url( params, js_url )
if s then
s = vlc.strings.decode_uri( s )
vlc.msg.dbg( "Found "..string.len( s ).."-character scrambled signature for youtube video URL, attempting to descramble... " )
if js_url then
s = js_descramble( s, js_url )
else
local ds = sig_descramble( s, js )
if not ds then
vlc.msg.dbg( "Couldn't descramble YouTube video URL signature" )
vlc.msg.err( "Couldn't process youtube video URL, please check for updates to this script" )
ds = s
end
local sp = string.match( params, "sp=([^&]+)" )
......@@ -231,13 +539,13 @@ function stream_url( params, js_url )
vlc.msg.warn( "Couldn't extract signature parameters for youtube video URL, guessing" )
sp = "signature"
end
url = url.."&"..sp.."="..vlc.strings.encode_uri_component( s )
url = url.."&"..sp.."="..vlc.strings.encode_uri_component( ds )
end
return url
end
-- Parse and pick our video stream URL (classic parameters)
-- Parse and pick our video stream URL (classic parameters, out of use)
function pick_url( url_map, fmt, js_url )
for stream in string.gmatch( url_map, "[^,]+" ) do
local itag = string.match( stream, "itag=(%d+)" )
......@@ -288,19 +596,54 @@ function pick_stream( stream_map, js_url )
return nil
end
-- Fetch javascript code: we'll need this to descramble maybe the
-- URL signature, and normally always the "n" throttling parameter.
local js = nil
if js_url then
js = { stream = vlc.stream( js_url ), lines = {}, i = 0 }
if not js.stream then
-- Retry once for transient errors
js.stream = vlc.stream( js_url )
if not js.stream then
js = nil
end
end
end
-- Either the "url" or the "signatureCipher" parameter is present,
-- depending on whether the URL signature is scrambled.
local url
local cipher = string.match( pick, '"signatureCipher":"(.-)"' )
or string.match( pick, '"[a-zA-Z]*[Cc]ipher":"(.-)"' )
if cipher then
-- Scrambled signature: some assembly required
local url = stream_url( cipher, js_url )
if url then
return url
url = stream_url( cipher, js )
end
if not url then
-- Unscrambled signature, already included in ready-to-use URL
url = string.match( pick, '"url":"(.-)"' )
end
if not url then
return nil
end
-- The "n" parameter is scrambled too, and needs to be descrambled
-- and replaced in place, otherwise the data transfer gets throttled
-- down to between 40 and 80 kB/s, below real-time playability level.
local n = string.match( url, "[?&]n=([^&]+)" )
if n then
n = vlc.strings.decode_uri( n )
local dn = n_descramble( n, js )
if dn then
url = string.gsub( url, "([?&])n=[^&]+", "%1n="..vlc.strings.encode_uri_component( dn ), 1 )
else
vlc.msg.dbg( "Couldn't descramble YouTube throttling URL parameter: data transfer will get throttled" )
vlc.msg.err( "Couldn't process youtube video URL, please check for updates to this script" )
end
end
-- Unscrambled signature, already included in ready-to-use URL
return string.match( pick, '"url":"(.-)"' )
return url
end
-- Probe function.
......@@ -492,28 +835,6 @@ function parse()
end
end
if not path then
local video_id = get_url_param( vlc.path, "v" )
if video_id then
-- Passing no "el" parameter to /get_video_info seems to
-- let it default to "embedded", and both known values
-- of "embedded" and "detailpage" have historically been
-- wrong and failed for various restricted videos.
path = vlc.access.."://www.youtube.com/get_video_info?video_id="..video_id..copy_url_param( vlc.path, "fmt" )
-- The YouTube API output doesn't provide the URL to the
-- javascript code necessary to descramble URL signatures,
-- without which functionality can be seriously limited.
-- #18801 prevents us from using a subrequest to the API,
-- so we forward the URL this way.
if js_url then
path = path.."&jsurl="..vlc.strings.encode_uri_component( js_url )
end
vlc.msg.warn( "Couldn't extract video URL, falling back to alternate youtube API" )
end
end
if not path then
vlc.msg.err( "Couldn't extract youtube video URL, please check for updates to this script" )
return { }
......@@ -525,7 +846,12 @@ function parse()
return { { path = path; name = title; description = description; artist = artist; arturl = arturl } }
elseif string.match( vlc.path, "/get_video_info%?" ) then -- video info API
elseif string.match( vlc.path, "/get_video_info%?" ) then
-- video info API, retired since summer 2021
-- Replacement Innertube API requires HTTP POST requests
-- and so remains for now unworkable from lua parser scripts
-- (see #26185)
local line = vlc.read( 1024*1024 ) -- data is on one line only
if not line then
vlc.msg.err( "YouTube API output missing" )
......