Advertisement
Guest User

playtv

a guest
May 15th, 2012
328
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 22.02 KB | None | 0 0
  1. <?php
  2. class CLI
  3. {
  4. protected static $ACCEPTED = array(
  5. 0 => array(
  6. 'help' => 'displays this help',
  7. 'quiet' => 'disables unnecessary output',
  8. 'print' => 'only prints the base rtmpdump command, does not start anything',
  9. 'list' => 'displays formatted channels list and exits'
  10. ),
  11. 1 => array(
  12. 'url' => 'immediately uses [param] as url without displaying channels list'
  13. )
  14. );
  15. var $params = array();
  16.  
  17. public function __construct()
  18. {
  19. global $argc, $argv;
  20.  
  21. // Parse params
  22. if ($argc > 1)
  23. {
  24. $doubleParam = false;
  25. for ($i = 1; $i < $argc; $i++)
  26. {
  27. $arg = $argv[$i];
  28. $isparam = preg_match('/^--/', $arg);
  29.  
  30. if ($isparam)
  31. $arg = preg_replace('/^--/', '', $arg);
  32.  
  33. if ($doubleParam && $isparam)
  34. {
  35. echo "[param] expected after '$doubleParam' switch (" . self::$ACCEPTED[1][$doubleParam] . ")\n";
  36. exit(1);
  37. }
  38. else if (!$doubleParam && !$isparam)
  39. {
  40. echo "'$arg' is an invalid switch, use --help to display valid switches\n";
  41. exit(1);
  42. }
  43. else if (!$doubleParam && $isparam)
  44. {
  45. if (isset($this->params[$arg]))
  46. {
  47. echo "'$arg' switch cannot occur more than once\n";
  48. die;
  49. }
  50.  
  51. $this->params[$arg] = true;
  52. if (isset(self::$ACCEPTED[1][$arg]))
  53. $doubleParam = $arg;
  54. else if (!isset(self::$ACCEPTED[0][$arg]))
  55. {
  56. echo "there's no '$arg' switch, use --help to display all switches\n";
  57. exit(1);
  58. }
  59. }
  60. else if ($doubleParam && !$isparam)
  61. {
  62. $this->params[$doubleParam] = $arg;
  63. $doubleParam = false;
  64. }
  65. }
  66. }
  67.  
  68. // Final check
  69. foreach ($this->params as $k => $v)
  70. if (isset(self::$ACCEPTED[1][$k]) && $v === true)
  71. {
  72. echo "[param] expected after '$k' switch (" . self::$ACCEPTED[1][$k] . ")\n";
  73. die;
  74. }
  75. }
  76.  
  77. public function getParam($name)
  78. {
  79. if (isset($this->params[$name]))
  80. return $this->params[$name];
  81. else
  82. return "";
  83. }
  84.  
  85. public function displayHelp()
  86. {
  87. echo "You can use script with following switches: \n\n";
  88. foreach (self::$ACCEPTED[0] as $key => $value)
  89. printf(" --%-13s%s\n", $key, $value);
  90. foreach (self::$ACCEPTED[1] as $key => $value)
  91. printf(" --%-13s%s\n", $key . " [param]", $value);
  92. }
  93. }
  94.  
  95. define('CRYPT_XXTEA_DELTA', 0x9E3779B9);
  96. class Crypt_XXTEA
  97. {
  98. var $_key;
  99.  
  100. function setKey($key)
  101. {
  102. if (is_string($key))
  103. {
  104. $k = $this->_str2long($key, false);
  105. }
  106. elseif (is_array($key))
  107. {
  108. $k = $key;
  109. }
  110. else
  111. {
  112. qecho("The secret key must be a string or long integer array\n");
  113. }
  114. if (count($k) > 4)
  115. {
  116. qecho("The secret key cannot be more than 16 characters or 4 long values\n");
  117. }
  118. elseif (count($k) == 0)
  119. {
  120. qecho("The secret key cannot be empty\n");
  121. }
  122. elseif (count($k) < 4)
  123. {
  124. for ($i = count($k); $i < 4; $i++)
  125. {
  126. $k[$i] = 0;
  127. }
  128. }
  129. $this->_key = $k;
  130. return true;
  131. }
  132.  
  133. function encrypt($plaintext)
  134. {
  135. if ($this->_key == null)
  136. {
  137. qecho("Secret key is undefined\n");
  138. }
  139. if (is_string($plaintext))
  140. {
  141. return $this->_encryptString($plaintext);
  142. }
  143. elseif (is_array($plaintext))
  144. {
  145. return $this->_encryptArray($plaintext);
  146. }
  147. else
  148. {
  149. qecho("The plain text must be a string or long integer array\n");
  150. }
  151. }
  152.  
  153. function decrypt($ciphertext)
  154. {
  155. if ($this->_key == null)
  156. {
  157. qecho("Secret key is undefined\n");
  158. }
  159. if (is_string($ciphertext))
  160. {
  161. return $this->_decryptString($ciphertext);
  162. }
  163. elseif (is_array($ciphertext))
  164. {
  165. return $this->_decryptArray($ciphertext);
  166. }
  167. else
  168. {
  169. qecho("The cipher text must be a string or long integer array\n");
  170. }
  171. }
  172.  
  173. function _encryptString($str)
  174. {
  175. if ($str == '')
  176. {
  177. return '';
  178. }
  179. $v = $this->_str2long($str, false);
  180. $v = $this->_encryptArray($v);
  181. return $this->_long2str($v, false);
  182. }
  183.  
  184. function _encryptArray($v)
  185. {
  186. $n = count($v) - 1;
  187. $z = $v[$n];
  188. $y = $v[0];
  189. $q = floor(6 + 52 / ($n + 1));
  190. $sum = 0;
  191. while (0 < $q--)
  192. {
  193. $sum = $this->_int32($sum + CRYPT_XXTEA_DELTA);
  194. $e = $sum >> 2 & 3;
  195. for ($p = 0; $p < $n; $p++)
  196. {
  197. $y = $v[$p + 1];
  198. $mx = $this->_int32((($z >> 5 & 0x07FFFFFF) ^ $y << 2) + (($y >> 3 & 0x1FFFFFFF) ^ $z << 4)) ^ $this->_int32(($sum ^ $y) + ($this->_key[$p & 3 ^ $e] ^ $z));
  199. $z = $v[$p] = $this->_int32($v[$p] + $mx);
  200. }
  201. $y = $v[0];
  202. $mx = $this->_int32((($z >> 5 & 0x07FFFFFF) ^ $y << 2) + (($y >> 3 & 0x1FFFFFFF) ^ $z << 4)) ^ $this->_int32(($sum ^ $y) + ($this->_key[$p & 3 ^ $e] ^ $z));
  203. $z = $v[$n] = $this->_int32($v[$n] + $mx);
  204. }
  205. return $v;
  206. }
  207.  
  208. function _decryptString($str)
  209. {
  210. if ($str == '')
  211. {
  212. return '';
  213. }
  214. $v = $this->_str2long($str, false);
  215. $v = $this->_decryptArray($v);
  216. return $this->_long2str($v, false);
  217. }
  218.  
  219. function _decryptArray($v)
  220. {
  221. $n = count($v) - 1;
  222. $z = $v[$n];
  223. $y = $v[0];
  224. $q = floor(6 + 52 / ($n + 1));
  225. $sum = $this->_int32($q * CRYPT_XXTEA_DELTA);
  226. while ($sum != 0)
  227. {
  228. $e = $sum >> 2 & 3;
  229. for ($p = $n; $p > 0; $p--)
  230. {
  231. $z = $v[$p - 1];
  232. $mx = $this->_int32((($z >> 5 & 0x07FFFFFF) ^ $y << 2) + (($y >> 3 & 0x1FFFFFFF) ^ $z << 4)) ^ $this->_int32(($sum ^ $y) + ($this->_key[$p & 3 ^ $e] ^ $z));
  233. $y = $v[$p] = $this->_int32($v[$p] - $mx);
  234. }
  235. $z = $v[$n];
  236. $mx = $this->_int32((($z >> 5 & 0x07FFFFFF) ^ $y << 2) + (($y >> 3 & 0x1FFFFFFF) ^ $z << 4)) ^ $this->_int32(($sum ^ $y) + ($this->_key[$p & 3 ^ $e] ^ $z));
  237. $y = $v[0] = $this->_int32($v[0] - $mx);
  238. $sum = $this->_int32($sum - CRYPT_XXTEA_DELTA);
  239. }
  240. return $v;
  241. }
  242.  
  243. function _long2str($v, $w)
  244. {
  245. $len = count($v);
  246. $s = '';
  247. for ($i = 0; $i < $len; $i++)
  248. {
  249. $s .= pack('V', $v[$i]);
  250. }
  251. if ($w)
  252. {
  253. return substr($s, 0, $v[$len - 1]);
  254. }
  255. else
  256. {
  257. return $s;
  258. }
  259. }
  260.  
  261. function _str2long($s, $w)
  262. {
  263. $v = array_values(unpack('V*', $s . str_repeat("\0", (4 - strlen($s) % 4) & 3)));
  264. if ($w)
  265. {
  266. $v[] = strlen($s);
  267. }
  268. return $v;
  269. }
  270.  
  271. function _int32($n)
  272. {
  273. while ($n >= 2147483648)
  274. $n -= 4294967296;
  275. while ($n <= -2147483649)
  276. $n += 4294967296;
  277. return (int) $n;
  278. }
  279. }
  280.  
  281. class cURL
  282. {
  283. var $headers;
  284. var $user_agent;
  285. var $compression;
  286. var $cookie_file;
  287. var $proxy;
  288. var $cert_check;
  289.  
  290. function cURL($cookies = true, $cookie = 'Cookies.txt', $compression = 'gzip', $proxy = '')
  291. {
  292. $this->headers[] = 'Accept: image/gif, image/x-bitmap, image/jpeg, image/pjpeg';
  293. $this->headers[] = 'Connection: Keep-Alive';
  294. $this->headers[] = 'Content-type: application/x-www-form-urlencoded;charset=UTF-8';
  295. $this->user_agent = 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Media Center PC 4.0)';
  296. $this->compression = $compression;
  297. $this->proxy = $proxy;
  298. $this->cookies = $cookies;
  299. $this->cert_check = true;
  300. if ($this->cookies == true)
  301. $this->cookie($cookie);
  302. }
  303.  
  304. function cookie($cookie_file)
  305. {
  306. if (file_exists($cookie_file))
  307. {
  308. $this->cookie_file = $cookie_file;
  309. }
  310. else
  311. {
  312. $file = fopen($cookie_file, 'w') or $this->error('The cookie file could not be opened. Make sure this directory has the correct permissions');
  313. $this->cookie_file = $cookie_file;
  314. fclose($file);
  315. }
  316. }
  317.  
  318. function get($url)
  319. {
  320. $process = curl_init($url);
  321. curl_setopt($process, CURLOPT_HTTPHEADER, $this->headers);
  322. curl_setopt($process, CURLOPT_HEADER, 0);
  323. curl_setopt($process, CURLOPT_USERAGENT, $this->user_agent);
  324. if ($this->cookies == true)
  325. curl_setopt($process, CURLOPT_COOKIEFILE, $this->cookie_file);
  326. if ($this->cookies == true)
  327. curl_setopt($process, CURLOPT_COOKIEJAR, $this->cookie_file);
  328. curl_setopt($process, CURLOPT_ENCODING, $this->compression);
  329. curl_setopt($process, CURLOPT_TIMEOUT, 30);
  330. if ($this->proxy)
  331. $this->setProxy($process, $this->proxy);
  332. curl_setopt($process, CURLOPT_RETURNTRANSFER, 1);
  333. curl_setopt($process, CURLOPT_FOLLOWLOCATION, 1);
  334. if (!$this->cert_check)
  335. curl_setopt($process, CURLOPT_SSL_VERIFYPEER, 0);
  336. $return = curl_exec($process);
  337. curl_close($process);
  338. return $return;
  339. }
  340.  
  341. function post($url, $data)
  342. {
  343. $process = curl_init($url);
  344. curl_setopt($process, CURLOPT_HTTPHEADER, $this->headers);
  345. curl_setopt($process, CURLOPT_HEADER, 1);
  346. curl_setopt($process, CURLOPT_USERAGENT, $this->user_agent);
  347. if ($this->cookies == true)
  348. curl_setopt($process, CURLOPT_COOKIEFILE, $this->cookie_file);
  349. if ($this->cookies == true)
  350. curl_setopt($process, CURLOPT_COOKIEJAR, $this->cookie_file);
  351. curl_setopt($process, CURLOPT_ENCODING, $this->compression);
  352. curl_setopt($process, CURLOPT_TIMEOUT, 30);
  353. if ($this->proxy)
  354. $this->setProxy($process, $this->proxy);
  355. curl_setopt($process, CURLOPT_POSTFIELDS, $data);
  356. curl_setopt($process, CURLOPT_RETURNTRANSFER, 1);
  357. curl_setopt($process, CURLOPT_FOLLOWLOCATION, 1);
  358. curl_setopt($process, CURLOPT_POST, 1);
  359. if (!$this->cert_check)
  360. curl_setopt($process, CURLOPT_SSL_VERIFYPEER, 0);
  361. $return = curl_exec($process);
  362. curl_close($process);
  363. return $return;
  364. }
  365.  
  366. function setProxy(&$process, $proxy)
  367. {
  368. $type = substr($proxy, 0, stripos($proxy, ":"));
  369. $proxy = substr($proxy, stripos($proxy, "//") + 2);
  370. switch ($type)
  371. {
  372. case "socks4":
  373. $type = CURLPROXY_SOCKS4;
  374. break;
  375. case "socks5":
  376. $type = CURLPROXY_SOCKS5;
  377. break;
  378. default:
  379. $type = CURLPROXY_HTTP;
  380. }
  381. curl_setopt($process, CURLOPT_PROXY, $this->proxy);
  382. curl_setopt($process, CURLOPT_PROXYTYPE, $type);
  383. }
  384.  
  385. function error($error)
  386. {
  387. echo "cURL Error : $error";
  388. die;
  389. }
  390. }
  391.  
  392. function runAsyncBatch($command, $filename)
  393. {
  394. $BatchFile = fopen("PlayTV.bat", 'w');
  395. fwrite($BatchFile, "@Echo off\r\n");
  396. fwrite($BatchFile, "Title $filename\r\n");
  397. fwrite($BatchFile, "$command\r\n");
  398. fwrite($BatchFile, "Del \"PlayTV.bat\"\r\n");
  399. fclose($BatchFile);
  400. $WshShell = new COM("WScript.Shell");
  401. $oExec = $WshShell->Run("PlayTV.bat", 1, false);
  402. unset($WshShell, $oExec);
  403. }
  404.  
  405. function SafeFileName($filename)
  406. {
  407. $len = strlen($filename);
  408. for ($i = 0; $i < $len; $i++)
  409. {
  410. $char = ord($filename[$i]);
  411. if (($char < 32) || ($char >= 127))
  412. $filename = substr_replace($filename, ' ', $i, 1);
  413. }
  414. $filename = preg_replace('/[\/\\\?\*\:\|\<\>]/i', ' ', $filename);
  415. $filename = preg_replace('/\s\s+/i', ' ', $filename);
  416. $filename = trim($filename);
  417. return $filename;
  418. }
  419.  
  420. function ShowHeader($headers)
  421. {
  422. global $cli;
  423. $len = strlen($headers);
  424. $width = (int) ((80 - $len) / 2) + $len;
  425. $format = "\n%" . $width . "s\n\n";
  426. if (!$cli->getParam('quiet'))
  427. printf($format, $headers);
  428. }
  429.  
  430. function KeyName(array $a, $pos)
  431. {
  432. $temp = array_slice($a, $pos, 1, true);
  433. return key($temp);
  434. }
  435.  
  436. function ci_uksort($a, $b)
  437. {
  438. $a = strtolower($a);
  439. $b = strtolower($b);
  440. return strnatcmp($a, $b);
  441. }
  442.  
  443. function Display($items, $format, $columns)
  444. {
  445. global $cli;
  446.  
  447. // Display formatted channels list for external script
  448. if ($cli->getParam('list'))
  449. {
  450. foreach ($items as $name => $url)
  451. {
  452. printf("%-25.20s", preg_replace('/=/', '-', $name));
  453. printf(" = %s\n", $url);
  454. }
  455. exit(0);
  456. }
  457.  
  458. $numcols = $columns;
  459. $numitems = count($items);
  460. $numrows = ceil($numitems / $numcols);
  461.  
  462. for ($row = 1; $row <= $numrows; $row++)
  463. {
  464. $cell = 0;
  465. for ($col = 1; $col <= $numcols; $col++)
  466. {
  467. if ($col === 1)
  468. {
  469. $cell += $row;
  470. printf($format, $cell, KeyName($items, $cell - 1));
  471. }
  472. else
  473. {
  474. $cell += $numrows;
  475. if (isset($items[KeyName($items, $cell - 1)]))
  476. printf($format, $cell, KeyName($items, $cell - 1));
  477. }
  478. }
  479. echo "\n\n";
  480. }
  481. }
  482.  
  483. function Close($message)
  484. {
  485. global $cli, $windows;
  486. if (file_exists("Cookies.txt"))
  487. unlink("Cookies.txt");
  488. if ($message)
  489. qecho($message . "\n");
  490. if ($windows)
  491. exec("chcp 1252");
  492. if (!count($cli->params))
  493. sleep(2);
  494. die();
  495. }
  496.  
  497. function ShowChannel($url, $filename)
  498. {
  499. global $cc, $cli, $format, $vlc, $windows, $xxtea;
  500. qecho("Retrieving html . . .\n");
  501.  
  502. // Retrieve channel id and primary key
  503. date_default_timezone_set("America/New_York");
  504. $date = new DateTime();
  505. $timestamp = $date->getTimestamp();
  506. $player_id = $url;
  507. $init = $cc->get("http://tvplayer.playtv.fr/js/$player_id.js?_=$timestamp");
  508. preg_match("/b:[^{]*?({[^}]+})/i", $init, $init);
  509. $init = json_decode(trim($init[1]));
  510. if (!$init)
  511. Close("Unable to retrieve initialization parameters");
  512. $a = pack("H*", $init->{'a'});
  513. $b = pack("H*", $init->{'b'});
  514.  
  515. $xxtea->setKey("object");
  516. $params = json_decode(trim($xxtea->decrypt($b)));
  517. if (!$params)
  518. Close("Unable to decode initialization parameters");
  519. $key = $xxtea->decrypt(pack("H*", $params->{'k'}));
  520. $xxtea->setKey($key);
  521. $params = json_decode(trim($xxtea->decrypt($a)));
  522. $channel_id = $params->{'i'};
  523. $api_url = $params->{'u'};
  524.  
  525. // Generate parameter request
  526. $request = json_encode(array(
  527. 'i' => $channel_id,
  528. 't' => $timestamp,
  529. 'h' => 'playtv.fr',
  530. 'a' => 5
  531. ));
  532. $request = unpack("H*", $xxtea->encrypt($request));
  533. $request = $request[1];
  534. $cc->headers[] = "Referer: http://static.playtv.fr/swf/tvplayer.swf?r=14";
  535. $cc->headers[] = "x-flash-version: 11,1,102,63";
  536. $response = $cc->get($api_url . $request);
  537.  
  538. // Decode server response
  539. $response = pack("H*", $response);
  540. $params = json_decode(trim($xxtea->decrypt($response)));
  541. if (!$params)
  542. Close("Unable to decode server response");
  543. if (isset($params->{'s'}[1]))
  544. $streams = $params->{'s'}[0]->{'bitrate'} > $params->{'s'}[1]->{'bitrate'} ? $params->{'s'}[0] : $params->{'s'}[1];
  545. else
  546. $streams = $params->{'s'}[0];
  547. $scheme = $streams->{'scheme'};
  548. $host = $streams->{'host'};
  549. $port = $streams->{'port'};
  550. $app = $streams->{'application'};
  551. $playpath = $streams->{'stream'};
  552. $token = $streams->{'token'};
  553. $title = $streams->{'title'};
  554.  
  555. // Generate authentication token for rtmp server
  556. $t = $params->{'j'}->{'t'};
  557. $k = $params->{'j'}->{'k'};
  558. $xxtea->setKey("object");
  559. $key = $xxtea->decrypt(pack("H*", $k));
  560. $xxtea->setKey($key);
  561. $auth = unpack("H*", $xxtea->encrypt($t));
  562. $auth = $auth[1];
  563.  
  564. if ($scheme == "http")
  565. qprintf($format, "HTTP Url", "$scheme://$host" . (isset($port) ? ":$port" : "") . "/$playpath");
  566. else
  567. qprintf($format, "RTMP Url", "$scheme://$host" . (isset($port) ? ":$port" : "") . "/$app");
  568. qprintf($format, "Playpath", $playpath);
  569. qprintf($format, "Auth", $auth);
  570.  
  571. $filename = SafeFileName($filename);
  572. if (file_exists($filename . ".flv"))
  573. unlink($filename . ".flv");
  574. if ($scheme == "http")
  575. {
  576. $basecmd = "$scheme://$host" . (isset($port) ? ":$port" : "") . "/$playpath";
  577. $command = "\"$vlc\" --meta-title \"$title\" \"$basecmd\"";
  578. }
  579. else
  580. {
  581. $basecmd = "rtmpdump -r \"$scheme://$host" . (isset($port) ? ":$port" : "") . "/$app\" -a \"$app\" -s \"http://static.playtv.fr/swf/tvplayer.swf\" -p \"http://playtv.fr/television\" -C S:$auth " . (isset($token) ? "-T \"$token\" " : "") . "--live -y \"$playpath\"";
  582. $command = $basecmd . " | \"$vlc\" --meta-title \"$title\" -";
  583. }
  584.  
  585. if ($cli->getParam('print'))
  586. {
  587. echo $basecmd;
  588. exit(0);
  589. }
  590.  
  591. qprintf($format, "Command", $command);
  592. if ($host && $playpath && $auth)
  593. if ($windows)
  594. runAsyncBatch($command, $filename);
  595. else
  596. exec($command);
  597. }
  598.  
  599. function qecho($str)
  600. {
  601. global $cli;
  602. if (!$cli->getParam('quiet'))
  603. echo $str;
  604. }
  605.  
  606. function qprintf($format, $param, $arg)
  607. {
  608. global $cli;
  609. if (!$cli->getParam('quiet'))
  610. printf($format, $param, $arg);
  611. }
  612.  
  613. // Global code starts here
  614. $header = "KSV PlayTV Downloader";
  615. $format = "%-8s : %s\n";
  616. $ChannelFormat = "%2d) %-22.22s";
  617.  
  618. strncasecmp(php_uname('s'), "Win", 3) == 0 ? $windows = true : $windows = false;
  619. if ($windows)
  620. {
  621. exec("chcp 65001");
  622. if (file_exists("C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe"))
  623. $vlc = "C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe";
  624. else
  625. $vlc = "C:\\Program Files\\VideoLAN\\VLC\\vlc.exe";
  626. }
  627. else
  628. $vlc = "vlc";
  629. $cli = new CLI();
  630. $cc = new cURL();
  631. $xxtea = new Crypt_XXTEA();
  632. $cc->proxy = '';
  633.  
  634. ShowHeader($header);
  635. if ($cli->getParam('help'))
  636. {
  637. $cli->displayHelp();
  638. Close("");
  639. }
  640.  
  641. if ($cli->getParam('url'))
  642. {
  643. $url = $cli->getParam('url');
  644. $filename = $url;
  645. ShowChannel($url, $filename);
  646. }
  647. else
  648. {
  649. $html = $cc->get("http://playtv.fr/television/");
  650. preg_match_all('/<a.*?data-channel="([^"]+).*?data-playerid="([^"]+)[^>]+>/i', $html, $links);
  651. for ($i = 0; $i < count($links[1]); $i++)
  652. {
  653. $ChannelList[$links[1][$i]] = $links[2][$i];
  654. }
  655. uksort($ChannelList, 'ci_uksort');
  656.  
  657. $FirstRun = true;
  658. $KeepRunning = true;
  659. while ($KeepRunning)
  660. {
  661. if ($FirstRun)
  662. $FirstRun = false;
  663. else
  664. ShowHeader($header);
  665. Display($ChannelList, $ChannelFormat, 3);
  666. echo "Enter Channel Number : ";
  667. $channel = trim(fgets(STDIN));
  668. if (is_numeric($channel) && ($channel >= 1) && ($channel <= count($ChannelList)))
  669. {
  670. $url = $ChannelList[KeyName($ChannelList, $channel - 1)];
  671. $filename = KeyName($ChannelList, $channel - 1);
  672. ShowChannel($url, $filename);
  673. }
  674. else
  675. $KeepRunning = false;
  676. }
  677. }
  678.  
  679. Close("Finished");
  680. ?>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement