Advertisement
Tblogger

youtube_com.php

Dec 9th, 2014
554
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 22.14 KB | None | 0 0
  1. <?php
  2.  
  3. if (!defined('RAPIDLEECH')) {
  4.         require_once('index.html');
  5.         exit();
  6. }
  7.  
  8. class youtube_com extends DownloadClass {
  9.         private $page, $cookie, $fmturlmaps, $vid, $sts, $js, $playerJs, $sigJs, $jsVars,
  10.                 $fmts = array(38,37,46,22,45,44,35,43,34,18,6,5,36,17);
  11.  
  12.         public function Download($link) {
  13.                 $this->cookie = isset($_POST['yt_QS']) && !empty($_POST['cookie']) ? StrToCookies(decrypt(urldecode($_POST['cookie']))) : array();
  14.                 $url = parse_url($link);
  15.                 $this->vid = array();
  16.  
  17.                 if (host_matches('youtu.be', $url['host'])) preg_match('@/([\w\-\.]{11})@i', $url['path'], $this->vid);
  18.                 elseif (empty($url['query']) || ($this->vid[1] = cut_str('&'.$url['query'].'&', '&v=', '&')) === false || !preg_match('@^[\w\-\.]{11}$@i', $this->vid[1])) preg_match('@/(?:v|(?:embed))/([\w\-\.]{11})@i', $url['path'], $this->vid);
  19.  
  20.                 if (empty($this->vid[1])) html_error('Video ID not found.');
  21.                 $this->vid = $this->vid[1];
  22.                 $this->link = 'http://www.youtube.com/watch?v='.$this->vid;
  23.  
  24.                 $this->getFmtMaps();
  25.  
  26.                 $this->fmturlmaps = $this->GetVideosArr();
  27.  
  28.                 $yt_fmt = empty($_REQUEST['yt_fmt']) ? '' : $_REQUEST['yt_fmt'];
  29.                 if (empty($yt_fmt) && !isset($_GET['audl'])) return $this->QSelector();
  30.                 elseif (isset($_REQUEST['ytube_mp4']) && $_REQUEST['ytube_mp4'] == 'on' && !empty($yt_fmt)) {
  31.                         //look for and download the highest quality we can find?
  32.                         if ($yt_fmt == 'highest') {
  33.                                 foreach ($this->fmts as $fmt) if (array_key_exists($fmt, $this->fmturlmaps)) {
  34.                                         $furl = $this->fmturlmaps[$fmt];
  35.                                         break;
  36.                                 }
  37.                         } elseif (!$furl = $this->fmturlmaps[$yt_fmt]) html_error('Specified video format not found');
  38.                         else $fmt = $yt_fmt;
  39.                 } else { //just get the one Youtube plays by default (in some cases it could also be the highest quality format)
  40.                         $fmt = key($this->fmturlmaps);
  41.                         $furl = $this->fmturlmaps[$fmt];
  42.                 }
  43.  
  44.                 $ext = '.flv';
  45.                 $fmtexts = array('.mp4' => array(18,22,37,38), '.webm' => array(43,44,45,46), '.3gp' => array(36,17));
  46.                 foreach ($fmtexts as $k => $v) {
  47.                         if (!is_array($v)) $v = array($v);  
  48.                         if (in_array($fmt, $v)) {
  49.                                 $ext = $k;
  50.                                 break;
  51.                         }
  52.                 }
  53.  
  54.                 if (empty($this->response['title'])) html_error('No video title found! Download halted.');
  55.                 $FileName = str_replace(str_split('\\:*?"<>|=;'."\t\r\n\f"), '_', html_entity_decode(trim($this->response['title']), ENT_QUOTES));
  56.                 if (!empty($_REQUEST['cleanname'])) $FileName = preg_replace('@[^ A-Za-z_\-\d\.,\(\)\[\]\{\}&\!\'\@\%\#]@u', '_', $FileName);
  57.                 $FileName .= " [YT-f$fmt][{$this->vid}]$ext";
  58.  
  59.                 $this->RedirectDownload($furl, $FileName, $this->cookie, 0, 0, $FileName);
  60.         }
  61.  
  62.         private function FormToArr($content, $v1 = '&', $v2 = '=') {
  63.                 $rply = array();
  64.                 if (strpos($content, $v1) === false || strpos($content, $v2) === false) return $rply;
  65.                 foreach (array_filter(array_map('trim', explode($v1, $content))) as $v) {
  66.                         $v = array_map('trim', explode($v2, $v, 2));
  67.                         if ($v[0] != '') $rply[$v[0]] = $v[1];
  68.                 }
  69.                 return $rply;
  70.         }
  71.  
  72.         private function captcha() {
  73.                 $url = 'https://www.youtube.com/das_captcha?next=' . urlencode($this->link);
  74.                 if (isset($_REQUEST['step']) && $_REQUEST['step'] == '1') {
  75.                         if (empty($_POST['recaptcha_response_field'])) html_error('You didn\'t enter the image verification code.');
  76.                         $post = array('recaptcha_challenge_field' => $_POST['recaptcha_challenge_field'], 'recaptcha_response_field' => $_POST['recaptcha_response_field']);
  77.                         $post['next'] = $_POST['next'];
  78.                         $post['action_recaptcha_verify'] = $_POST['action_recaptcha_verify'];
  79.                         $post['submit'] = $_POST['_submit'];
  80.                         $post['session_token'] = $_POST['session_token'];
  81.                         $cookie = urldecode($_POST['cookie']);
  82.  
  83.                         $page = $this->GetPage($url, $cookie, $post, $url);
  84.                         is_present($page, 'The verification code was invalid', 'The verification code was invalid or has timed out, please try again.');
  85.                         is_present($page, "\r\n\r\nAuthorization Error.", 'Error sending captcha.');
  86.                         is_notpresent($page, 'Set-Cookie: goojf=', 'Cannot get captcha cookie.');
  87.  
  88.                         $this->cookie = GetCookiesArr($page);
  89.                         unset($_REQUEST['step']);
  90.                         $this->getFmtMaps();
  91.                 } else {
  92.                         $page = $this->GetPage($url);
  93.                         if (!preg_match('@//(?:[^/]+\.)?(?:(?:google\.com/recaptcha/api)|(?:recaptcha\.net))/(?:(?:challenge)|(?:noscript))\?k=([\w\.\-]+)@i', $page, $pid)) html_error('Error: reCAPTCHA not found.');
  94.  
  95.                         $data = $this->DefaultParamArr($this->link, GetCookies($page));
  96.                         $data['next'] = urlencode(html_entity_decode(cut_str($page, 'name="next" value="', '"')));
  97.                         $data['action_recaptcha_verify'] = urlencode(cut_str($page, 'name="action_recaptcha_verify" value="', '"'));
  98.                         $data['_submit'] = urlencode(cut_str($page, 'type="submit" name="submit" value="', '"'));
  99.                         $data['session_token'] = urlencode(cut_str($page, "'XSRF_TOKEN': '", "'"));
  100.                         if (isset($_REQUEST['ytube_mp4'])) $data['ytube_mp4'] = $_REQUEST['ytube_mp4'];
  101.                         if (isset($_REQUEST['ytdirect'])) $data['ytdirect'] = $_REQUEST['ytdirect'];
  102.                         if (isset($_REQUEST['yt_fmt'])) $data['yt_fmt'] = $_REQUEST['yt_fmt'];
  103.                         $data['step'] = 1;
  104.  
  105.                         $this->reCAPTCHA($pid[1], $data);
  106.                 }
  107.         }
  108.  
  109.         private function getFmtMaps() {
  110.                 $this->page = $this->GetPage('https://www.youtube.com/get_video_info?video_id='.$this->vid.'&asv=3&el=detailpage&hl=en_US&s'.'t'.'s'.'='.(!empty($this->sts) ? urlencode($this->sts) : 0), $this->cookie);
  111.                 $this->response = array_map('urldecode', $this->FormToArr(substr($this->page, strpos($this->page, "\r\n\r\n") + 4)));
  112.                 if (!empty($this->response['reason'])) html_error('['.htmlspecialchars($this->response['errorcode']).'] '.htmlspecialchars($this->response['reason']));
  113.  
  114.                 if (isset($_REQUEST['step']) || preg_match('@Location: https?://(www\.)?youtube\.com/das_captcha@i', $this->page)) $this->captcha();
  115.  
  116.                 if (empty($this->response['url_encoded_fmt_stream_map'])) html_error("[{$this->sts}] Video links not found.");
  117.                 $this->fmtmaps = explode(',', $this->response['url_encoded_fmt_stream_map']);
  118.         }
  119.  
  120.         private function decError($msg) {
  121.                 html_error("Error while decoding [{$this->sts}][{$this->js[1]}]: $msg");
  122.         }
  123.  
  124.         private function findFunction($fName, $num) {
  125.                 if ($fName == 'T8') return "w$num";
  126.                 $obj = explode('.', $fName, 3);
  127.                 if (count($obj) > 2) $this->decError("Cannot search function: '$fName'");
  128.                 if (count($obj) > 1) {
  129.                         $fName = $obj[1];
  130.                         $obj = $obj[0];
  131.                         if (empty($this->jsVars[$obj]['src'])) {
  132.                                 if (($spos = strpos($this->playerJs, "var $obj={")) === false || ($epos = strpos($this->playerJs, '};', $spos)) === false) $this->decError("Cannot find object '$obj'");
  133.                                 $spos += strlen("var $obj={");
  134.                                 $this->jsVars[$obj] = array('src' => substr($this->playerJs, $spos, $epos - $spos), 'fn' => array());
  135.                         }
  136.                         if (empty($this->jsVars[$obj]['fn'][$fName]['step'])) {
  137.                                 $v = '[\$_A-Za-z][\$\w]*';
  138.                                 if (!preg_match("@(?<=^|,)$fName:function\($v(?:,($v))?\)\{([^}]+)\}(?=,|$)@", $this->jsVars[$obj]['src'], $src)) $this->decError("Cannot find function '$obj.$fName'");
  139.                                 $this->jsVars[$obj]['fn'][$fName] = array('src' => $src);
  140.  
  141.                                 if (empty($src[1])) return $this->jsVars[$obj]['fn'][$fName]['step'] = 'r';
  142.                                 elseif (preg_match("@var\s+($v)=($v)\[0\];\\2\[0\]=\\2\[{$src[1]}%\\2(?:\.length|\[$v\])\];\\2\[{$src[1]}\]=\\1@", $src[2])) {
  143.                                         $this->jsVars[$obj]['fn'][$fName]['step'] = 'w%d';
  144.                                         return "w$num";
  145.                                 } elseif (preg_match("@(?:$v=)?$v(?:\.s(p)?lice|\[$v\])\((?(1)0,){$src[1]}\)@", $src[2])) {
  146.                                         $this->jsVars[$obj]['fn'][$fName]['step'] = 's%d';
  147.                                         return "s$num";
  148.                                 } elseif (preg_match("@(?:$v=)?$v(?:\.reverse|\[$v\])\(\)@", $src[2])) return $this->jsVars[$obj]['fn'][$fName]['step'] = 'r';
  149.                                 else $this->decError("Error parsing function '$obj.$fName'");
  150.                         } else return sprintf($this->jsVars[$obj]['fn'][$fName]['step'], $num);
  151.                 }
  152.                 if (empty($this->jsVars[$fName]['step'])) {
  153.                         if (($spos = strpos($this->playerJs, "function $fName(")) === false || ($epos = strpos($this->playerJs, '};', $spos)) === false) $this->decError("Cannot find function '$fName'");
  154.                         $this->jsVars[$fName] = array('src' => substr($this->playerJs, $spos, $epos - $spos));
  155.                         $v = '[\$_A-Za-z][\$\w]*';
  156.                         if (!preg_match("@^function\s+$fName\($v(?:,($v))?\)\{(.*)$@", $this->jsVars[$fName]['src'], $pars)) $this->decError("Cannot parse function '$fName'");
  157.                         if (empty($pars[1])) return $this->jsVars[$fName]['step'] = 'r';
  158.                         elseif (preg_match("@var\s+($v)=($v)\[0\];\\2\[0\]=\\2\[{$pars[1]}%\\2(?:\.length|\[$v\])\];\\2\[{$pars[1]}\]=\\1@", $src[2])) {
  159.                                 $this->jsVars[$fName]['step'] = 'w%d';
  160.                                 return "w$num";
  161.                         } elseif (preg_match("@(?:$v=)?$v(?:\.s(p)?lice|\[$v\])\((?(1)0,){$src[1]}\)@", $src[2])) {
  162.                                 $this->jsVars[$fName]['step'] = 's%d';
  163.                                 return "s$num";
  164.                         } elseif (preg_match("@(?:$v=)?$v(?:\.reverse|\[$v\])\(\)@", $src[2])) return $this->jsVars[$fName]['step'] = 'r';
  165.                         else $this->decError("Error parsing function '$fName'");
  166.                 } else return sprintf($this->jsVars[$fName]['step'], $num);
  167.         }
  168.  
  169.         // getCipher & sigDecode are based on jwz's youtubedown code.
  170.         private function getCipher() {
  171.                 $this->changeMesg('<br />Video with ciphered signature, trying to decode it.', 1);
  172.                 $page = $this->GetPage('https://www.youtube.com/embed/'.$this->vid, $this->cookie);
  173.                 $this->cookie = GetCookiesArr($page, $this->cookie);
  174.  
  175.                 if (!preg_match('@"sts"\s*:\s*(\d+)@i', $page, $this->sts)) html_error('Signature timestamp not found.');
  176.                 $this->sts = $this->sts[1];
  177.  
  178.                 $savefile = DOWNLOAD_DIR.'YT_lastjs.txt';
  179.                 if (!preg_match('@html5player-([\w\-\.]+(?:/\w+)?)\.js@i', str_replace('\\/', '/', $page), $this->js)) html_error('YT\'s player javascript not found.');
  180.                 if (@file_exists($savefile) && ($file = file_get_contents($savefile, NULL, NULL, -1, 822)) && ($saved = @unserialize($file)) && is_array($saved) && !empty($saved['sts']) && $saved['sts'] == $this->sts && !empty($saved['steps']) && preg_match('@^\s*([ws]\d+|r)( ([ws]\d+|r))*\s*$@', $saved['steps'])) {
  181.                         $this->encS = explode(' ', trim($saved['steps']));
  182.                 } else {
  183.                         $this->playerJs = $this->GetPage('http://s.ytimg.com/yts/jsbin/'.$this->js[0], $this->cookie, 0, 'http://www.youtube.com/embed/'.$this->vid);
  184.                         if (($spos = strpos($this->playerJs, '.sig||')) === false) $this->decError('Not found (".sig||")');
  185.                         if (($cut1 = cut_str(substr($this->playerJs, $spos), '{', '}')) == false) $this->decError('Cannot get inner content of "if(X.sig||X.s)"');
  186.                         $v = '[\$_A-Za-z][\$\w]*';
  187.                         if (!preg_match("@(?<=\.sig\|\|)$v(?=\($v\.s\))@", $cut1, $fn)) $this->decError('Cannot get decoder function name');
  188.                         $fn = $fn[0];
  189.                         if (($fpos = strpos($this->playerJs, "function $fn(")) === false) $this->decError('Cannot find decoder function');
  190.                         if (($cut2 = cut_str(substr($this->playerJs, $fpos), '{', '}')) == false) $this->decError('Cannot get decoder function contents');
  191.                         $this->sigJs = preg_replace("@var $v=$v\[0\];$v\[0\]=($v)\[(\d+)%$v(?:\.length|\[$v\])\];$v\[\d+\]=$v;@", '$1=T8($1,$2);', trim($cut2));
  192.                         $this->encS = array();
  193.                         foreach (array_map('trim', explode(';', '{'.$this->sigJs.'}')) as $step) {
  194.                                 if (($step{0} == '{' || substr($step, strlen($step) - 1, 1) == '}') && (preg_match("@^\{(?:var\s+)?$v=$v(?:\.split|\[$v\])\(\"\"\)$@", $step) || preg_match("@^return\s+$v(?:\.join|\[$v\])\(\"\"\);?\}$@", $step))) continue;
  195.                                 elseif (preg_match("@^(?:$v=)?((?:$v.)*$v)\($v\,(\d+)\)$@", $step, $s)) $this->encS[] = $this->findFunction($s[1], $s[2]);
  196.                                 //elseif (preg_match("@^$v=$v\($v\,(\d+)\)$@", $step, $s)) $this->encS[] = 'w'.$s[1];
  197.                                 elseif (preg_match("@^(?:$v=)?$v(?:\.s(p)?lice|\[$v\])\((?(1)0,)(\d+)\)$@", $step, $s)) $this->encS[] = 's'.$s[2];
  198.                                 elseif (preg_match("@^(?:$v=)?$v(?:\.reverse|\[$v\])\(\)$@", $step)) $this->encS[] = 'r';
  199.                                 else $this->decError($step.' | Unknown step on decoder function.');
  200.                         }
  201.  
  202.                         if (empty($this->encS)) $this->decError('Empty decoded result');
  203.                         file_put_contents($savefile, serialize(array('sts' => $this->sts, 'js' => $this->js[1], 'steps' => implode(' ', $this->encS))));
  204.                 }
  205.  
  206.                 // Request video fmts with the current sts
  207.                 $this->getFmtMaps();
  208.  
  209.                 return $this->GetVideosArr();
  210.         }
  211.  
  212.         private function sigDecode($sig) {
  213.                 if (empty($this->encS)) $this->decError('sigDecode() can\'t be called before getCipher()');
  214.                 $_sig = $sig;
  215.                 $sig = str_split($sig);
  216.                 foreach ($this->encS as $_step) {
  217.                         if (!preg_match('@^\s*([wrs])(\d*)\s*$@', $_step, $step) || ($step[1] != 'r' && !array_key_exists(2, $step))) $this->decError("Unknown decoding step \"$_step\"");
  218.                         switch ($step[1]) {
  219.                                 case 'w': $step[2] = (int)$step[2];$x = $sig[0];$sig[0] = $sig[$step[2] % count($sig)];$sig[$step[2]] = $x; break;
  220.                                 case 's': $step[2] = (int)$step[2];$sig = array_slice($sig, $step[2]); break;
  221.                                 case 'r': $sig = array_reverse($sig); break;
  222.                         }
  223.                 }
  224.                 return implode($sig);
  225.         }
  226.  
  227.         private function GetVideosArr() {
  228.                 $fmturls = array();
  229.                 foreach ($this->fmtmaps as $fmtlist) {
  230.                         $fmtlist = array_map('urldecode', $this->FormToArr($fmtlist));
  231.                         if (!in_array($fmtlist['itag'], $this->fmts)) continue;
  232.                         if (!empty($fmtlist['s']) && empty($this->encS)) {
  233.                                 if (empty($this->sts)) return $this->getCipher();
  234.                                 else $this->decError('No decoded steps');
  235.                         }
  236.                         $fmtlist['url'] = parse_url($fmtlist['url']);
  237.                         $fmtlist['url']['query'] = array_map('urldecode', $this->FormToArr($fmtlist['url']['query']));
  238.                         if (empty($fmtlist['url']['query']['signature'])) $fmtlist['url']['query']['signature'] = (!empty($fmtlist['s']) ? $this->sigDecode($fmtlist['s']) : $fmtlist['sig']);
  239.                         foreach (array_diff(array_keys($fmtlist), array('signature', 'sig', 's', 'url')) as $k) $fmtlist['url']['query'][$k] = $fmtlist[$k];
  240.                         ksort($fmtlist['url']['query']);
  241.                         $fmtlist['url']['query'] = http_build_query($fmtlist['url']['query']);
  242.                         $fmturls[$fmtlist['itag']] = rebuild_url($fmtlist['url']);
  243.                 }
  244.                 return $fmturls;
  245.         }
  246.  
  247.         private function QSelector() {
  248.                 $VR = array('>1080', 1080, 720, 480, 360, 270, 240, 144);
  249.                 $VC = array('MP4', 'WebM', 'FLV', '3GP');
  250.                 $AC = array('AAC', 'Vorbis', 'MP3');
  251.                 $AB = array(192, 128, 96, 64, 36, 24);
  252.                 $vinfo = array(38=>'0000',37=>'1000',46=>'1110',22=>'2000',45=>'2110',44=>'3111',35=>'3201',43=>'4111',34=>'4201',18=>'4002',6=>'5223',5=>'6223',36=>'6304',17=>'7305'); // VR VC AC AB
  253.  
  254.                 $sizes = array();
  255.                 /* Add a // at the start of this line for enable this code.
  256.                 if (extension_loaded('curl') && function_exists('curl_init') && function_exists('curl_exec')) {
  257.                         $sizes = array();
  258.                         $opt = array(CURLOPT_FOLLOWLOCATION => true, CURLOPT_MAXREDIRS => 5, CURLOPT_NOBODY => true); // Redirects may fail with open_basedir enabled
  259.                         foreach ($this->fmturlmaps as $fmt => $url) {
  260.                                 if (!in_array($fmt, $this->fmts)) continue;
  261.                                 $headers = explode("\r\n\r\n", cURL($url, $this->cookie, 0, 0, 0, $opt));
  262.                                 $headers = ((count($headers) > 2) ? $headers[count($headers) - 2] : $headers[0]) . "\r\n\r\n";
  263.                                 if (substr($headers, 9, 3) == '200' && ($CL = cut_str($headers, "\nContent-Length: ", "\n")) && $CL > 1024) $sizes[$fmt] = bytesToKbOrMbOrGb(trim($CL));
  264.                         }
  265.                         unset($headers, $CL);
  266.                 } //*/
  267.  
  268.                 echo "\n<br /><br /><h3 style='text-align: center;'>".lang(216).".</h4>";
  269.                 echo "\n<center><form name='YT_QS' action='{$GLOBALS['PHP_SELF']}' method='POST'>\n";
  270.                 echo "<input type='hidden' name='yt_QS' value='on' />\n";
  271.                 echo '<label><input type="checkbox" name="cleanname" checked="checked" /><small>&nbsp;Remove non-supported characters from filename</small></label><br />';
  272.                 echo "<select name='yt_fmt' id='QS_fmt'>\n";
  273.                 foreach ($this->fmturlmaps as $fmt => $url) if (in_array($fmt, $this->fmts) && ($I = str_split($vinfo[$fmt]))) echo '<option '.($fmt == 18 ? "selected='selected' " : '')."value='$fmt'>[$fmt] Video: {$VC[$I[1]]} {$VR[$I[0]]}p | Audio: {$AC[$I[2]]} ~{$AB[$I[3]]} kbps".(!empty($sizes[$fmt]) ? ' ('.$sizes[$fmt].')' : '')."</option>\n";
  274.                 echo "</select>\n";
  275.                 if (count($this->cookie) > 0) $this->cookie = encrypt(CookiesToStr($this->cookie));
  276.                 $data = $this->DefaultParamArr($this->link, $this->cookie);
  277.                 $data['ytube_mp4'] = 'on';
  278.                 foreach ($data as $n => $v) echo("<input type='hidden' name='$n' id='QS_$n' value='$v' />\n");
  279.  
  280.                 echo "<input type='submit' name='Th3-822' value='".lang(209)."' />\n";
  281.                 echo "</form></center>\n</body>\n</html>";
  282.                 exit;
  283.         }
  284. }
  285.  
  286. //re-written by szal based on original plugin by eqbal
  287. //updated 07 June 2010
  288. // [28-03-2011]  Fixed (!$video_id) regex. - Th3-822
  289. // [29-03-2011]  Added support for captcha. - Th3-822
  290. // [02-04-2011]  Fixed redirect error. [26-04-2011]  Added error msgs.  - Th3-822
  291. // [04-8-2011]  Fixed for recent changes in fmt_stream_map content & some edits maded for work fine. (Redirect is needed yet) - Th3-822
  292. // [12-8-2011]  Added support for videos that need login for verify age & Changed fmt order by quality & Fixed regexps for fileext. - Th3-822
  293. // [13-8-2011]  Some fixes & removed not working code & fixed verify_age function. - Th3-822
  294. // [17-9-2011]  Added function for skip 'verify_controversy' on youtube && Fixed cookies after captcha && Little changes. - Th3-822
  295. // [26-1-2012]  Fixed regexp for get title, added a quality selector (if the one in template is removed) and some changes in the code. - Th3-822
  296. // [17-5-2012]  Fixed captcha (Now uses reCaptcha). - Th3-822
  297. // [14-9-2012]  Fixed Download links & small changes. - Th3-822
  298. // [07-10-2012]  Fixed for redirect at link. - Th3-822
  299. // [02-1-2013]  Using new way for getting links and video info, now it doesn't need login for restricted videos. - Th3-822
  300. // [02-10-2013]  Fixed issues with videos with ciphered signature & Rewritten quality selector (Now it doesn't use lang) & Remove direct-link option & Added option for sanitize filenames & small changes. - Th3-822
  301. // [04-3-2014]  Re-Added Support for 3GP quality. - Th3-822
  302. // [16-3-2014]  Added functions for decoding ciphered signatures. - Th3-822
  303. // [28-7-2014]  Fixed signature decoding functions. - Th3-822
  304. // [12-8-2014]  Forced https on some requests for avoid some errors. - Th3-822
  305. // [09-12-2014] Little Touch in Plugin by Tblogger
  306. ?>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement