PageRenderTime 152ms CodeModel.GetById 48ms RepoModel.GetById 6ms app.codeStats 0ms

/plugins/opfitalia/library/X/VlcShares/Plugins/OPFItalia.php

http://vlc-shares.googlecode.com/
PHP | 605 lines | 365 code | 100 blank | 140 comment | 75 complexity | 545208992ef2581a37a8ee18f5ba63fe MD5 | raw file
Possible License(s): GPL-2.0
  1. <?php
  2. require_once 'Zend/Http/CookieJar.php';
  3. require_once 'Zend/Http/Cookie.php';
  4. require_once 'X/VlcShares/Plugins/Abstract.php';
  5. require_once 'Zend/Dom/Query.php';
  6. /**
  7. * Add OPFItalia site as a video source
  8. * @author ximarx
  9. *
  10. */
  11. class X_VlcShares_Plugins_OPFItalia extends X_VlcShares_Plugins_Abstract implements X_VlcShares_Plugins_ResolverInterface {
  12. const VERSION = '0.2.1';
  13. const VERSION_CLEAN = '0.2.1';
  14. /**
  15. * @var Zend_Http_CookieJar
  16. */
  17. private $jar = null;
  18. public function __construct() {
  19. $this->setPriority('gen_beforeInit')
  20. ->setPriority('getCollectionsItems')
  21. ->setPriority('preRegisterVlcArgs')
  22. ->setPriority('getShareItems')
  23. ->setPriority('preGetModeItems')
  24. ->setPriority('getIndexManageLinks')
  25. ->setPriority('getIndexMessages')
  26. ->setPriority('getTestItems')
  27. ->setPriority('prepareConfigElement')
  28. ;
  29. }
  30. /**
  31. * Inizialize translator for this plugin
  32. * @param Zend_Controller_Action $controller
  33. */
  34. function gen_beforeInit(Zend_Controller_Action $controller) {
  35. $this->helpers()->language()->addTranslation(__CLASS__);
  36. }
  37. /**
  38. * Add the main link for megavideo library
  39. * @param Zend_Controller_Action $controller
  40. */
  41. public function getCollectionsItems(Zend_Controller_Action $controller) {
  42. X_Debug::i("Plugin triggered");
  43. $link = new X_Page_Item_PItem($this->getId(), X_Env::_('p_opfitalia_collectionindex'));
  44. $link->setIcon('/images/opfitalia/logo.png')
  45. ->setDescription(X_Env::_('p_opfitalia_collectionindex_desc'))
  46. ->setType(X_Page_Item_PItem::TYPE_CONTAINER)
  47. ->setLink(
  48. array(
  49. 'controller' => 'browse',
  50. 'action' => 'share',
  51. 'p' => $this->getId(),
  52. ), 'default', true
  53. );
  54. return new X_Page_ItemList_PItem(array($link));
  55. }
  56. /**
  57. * Get category/video list
  58. * @param unknown_type $provider
  59. * @param unknown_type $location
  60. * @param Zend_Controller_Action $controller
  61. */
  62. public function getShareItems($provider, $location, Zend_Controller_Action $controller) {
  63. if ( $provider != $this->getId() ) return;
  64. X_Debug::i('Plugin triggered');
  65. X_VlcShares_Plugins::broker()->unregisterPluginClass('X_VlcShares_Plugins_SortItems');
  66. $baseUrl = $this->config('base.url', 'http://www.opfitalia.net/mediacenter/index.php?page=ajax_show_folder&id=');
  67. $items = new X_Page_ItemList_PItem();
  68. try {
  69. if ( $location != '' ) {
  70. @list($path, $type, $link) = explode('/', $location);
  71. $lStack = explode(':', $path);
  72. $last = count($lStack) > 0 ? $lStack[count($lStack)-1] : 0;
  73. $decoded = $this->_loadPage($baseUrl.$last);
  74. $this->_fillPlaylist($items, $decoded, $lStack);
  75. } else {
  76. // show the index
  77. $indexCategory = $this->config('index.category', 0);
  78. $decoded = $this->_loadPage($baseUrl.$indexCategory);
  79. $this->_fillPlaylist($items, $decoded, array());
  80. }
  81. } catch (Exception $e ) {
  82. // auth problems
  83. $item = new X_Page_Item_PItem('opf-autherror', X_Env::_('p_opfitalia_br_error').": {$e->getMessage()}");
  84. $item->setIcon('/images/msg_error.png')
  85. ->setType(X_Page_Item_PItem::TYPE_ELEMENT)
  86. ->setDescription($e->getMessage())
  87. ->setLink(array(
  88. 'controller' => 'index',
  89. 'action' => 'collections'
  90. ), 'default', true);
  91. $items->append($item);
  92. }
  93. return $items;
  94. }
  95. /**
  96. * This hook can be used to add low priority args in vlc stack
  97. *
  98. * @param X_Vlc $vlc vlc wrapper object
  99. * @param string $provider id of the plugin that should handle request
  100. * @param string $location to stream
  101. * @param Zend_Controller_Action $controller the controller who handle the request
  102. */
  103. public function preRegisterVlcArgs(X_Vlc $vlc, $provider, $location, Zend_Controller_Action $controller) {
  104. // this plugin inject params only if this is the provider
  105. if ( $provider != $this->getId() ) return;
  106. // i need to register source as first, because subtitles plugin use source
  107. // for create subfile
  108. X_Debug::i('Plugin triggered');
  109. $location = $this->resolveLocation($location);
  110. if ( $location !== null ) {
  111. // TODO adapt to newer api when ready
  112. $vlc->registerArg('source', "\"$location\"");
  113. } else {
  114. X_Debug::e("No source o_O");
  115. }
  116. }
  117. /**
  118. * Add button -watch megavideo stream directly-
  119. *
  120. * @param string $provider
  121. * @param string $location
  122. * @param Zend_Controller_Action $controller
  123. */
  124. public function preGetModeItems($provider, $location, Zend_Controller_Action $controller) {
  125. if ( $provider != $this->getId()) return;
  126. X_Debug::i("Plugin triggered");
  127. $url = $this->resolveLocation($location);
  128. if ( $url ) {
  129. $link = new X_Page_Item_PItem('core-directwatch', X_Env::_('p_opfitalia_watchdirectly'));
  130. $link->setIcon('/images/icons/play.png')
  131. ->setType(X_Page_Item_PItem::TYPE_PLAYABLE)
  132. ->setLink($url);
  133. return new X_Page_ItemList_PItem(array($link));
  134. } else {
  135. // if there is no link, i have to remove start-vlc button
  136. // and replace it with a Warning button
  137. X_Debug::i('Setting priority to filterModeItems');
  138. $this->setPriority('filterModeItems', 99);
  139. $link = new X_Page_Item_PItem('megavideo-warning', X_Env::_('p_opfitalia_invalidlink'));
  140. $link->setIcon('/images/msg_error.png')
  141. ->setType(X_Page_Item_PItem::TYPE_ELEMENT)
  142. ->setLink(array (
  143. 'controller' => 'browse',
  144. 'action' => 'share',
  145. 'p' => $this->getId(),
  146. 'l' => X_Env::encode($this->getParentLocation($location)),
  147. ), 'default', true);
  148. return new X_Page_ItemList_PItem(array($link));
  149. }
  150. }
  151. /**
  152. * Remove vlc-play button if location is invalid
  153. * @param X_Page_Item_PItem $item,
  154. * @param string $provider
  155. * @param Zend_Controller_Action $controller
  156. */
  157. public function filterModeItems(X_Page_Item_PItem $item, $provider,Zend_Controller_Action $controller) {
  158. if ( $item->getKey() == 'core-play') {
  159. X_Debug::i('plugin triggered');
  160. X_Debug::w('core-play flagged as invalid because the link is invalid');
  161. return false;
  162. }
  163. }
  164. private $cachedLocation = array();
  165. /**
  166. * @see X_VlcShares_Plugins_ResolverInterface::resolveLocation
  167. * @param string $location
  168. * @return string real address of a resource
  169. */
  170. function resolveLocation($location = null) {
  171. if ( $location == '' || $location == null ) return false;
  172. X_Debug::i("Requested location: $location");
  173. @list($path, $type, $href) = explode('/', $location, 3);
  174. X_Debug::i("Path: $path, Type: $type, Href: $href");
  175. if ( $href == null || $type == null ) return false;
  176. switch ($type) {
  177. case 'file':
  178. return $href;
  179. case 'megavideo':
  180. try {
  181. /* @var $megavideo X_VlcShares_Plugins_Helper_Megavideo */
  182. $megavideo = $this->helpers('megavideo');
  183. // if server isn't specified, there is no video
  184. if ( $megavideo->setLocation($href)->getServer() ) {
  185. return $megavideo->getUrl();
  186. }
  187. } catch (Exception $e) {
  188. X_Debug::e($e->getMessage());
  189. }
  190. }
  191. return false;
  192. }
  193. /**
  194. * No support for parent location
  195. * @see X_VlcShares_Plugins_ResolverInterface::getParentLocation
  196. * @param $location
  197. */
  198. function getParentLocation($location = null) {
  199. if ( $location == '' || $location == null ) return false;
  200. @list($path, $type, $href) = explode('/', $location, 3);
  201. if ( $href != null ) {
  202. return $path;
  203. } else {
  204. $lStack = explode(':',$path);
  205. if ( count($lStack) > 1 ) {
  206. array_pop($lStack);
  207. return implode(':', $lStack);
  208. } else {
  209. return null;
  210. }
  211. }
  212. }
  213. /**
  214. * Add the link for -manage-megavideo-
  215. * @param Zend_Controller_Action $this
  216. * @return X_Page_ItemList_ManageLink
  217. */
  218. public function getIndexManageLinks(Zend_Controller_Action $controller) {
  219. $link = new X_Page_Item_ManageLink($this->getId(), X_Env::_('p_opfitalia_mlink'));
  220. $link->setTitle(X_Env::_('p_opfitalia_managetitle'))
  221. ->setIcon('/images/opfitalia/logo.png')
  222. ->setLink(array(
  223. 'controller' => 'config',
  224. 'action' => 'index',
  225. 'key' => 'opfitalia'
  226. ), 'default', true);
  227. return new X_Page_ItemList_ManageLink(array($link));
  228. }
  229. /**
  230. * Show a warning message if username and password aren't specified yet
  231. * @param Zend_Controller_Action $this
  232. * @return X_Page_ItemList_Message
  233. */
  234. public function getIndexMessages(Zend_Controller_Action $controller) {
  235. X_Debug::i('Plugin triggered');
  236. if ( $this->config('auth.username', '') == '' || $this->config('auth.password', '') == '' ) {
  237. $m = new X_Page_Item_Message($this->getId(), X_Env::_('p_opfitalia_dashboardwarning'));
  238. $m->setType(X_Page_Item_Message::TYPE_WARNING);
  239. return new X_Page_ItemList_Message(array($m));
  240. }
  241. }
  242. /**
  243. * Animedb tests:
  244. * - check for username & password
  245. * - check for data/animedb/ path writable
  246. * @param Zend_Config $options
  247. * @param Zend_Controller_Action $controller
  248. * @return X_Page_ItemList_Message
  249. */
  250. public function getTestItems(Zend_Config $options,Zend_Controller_Action $controller) {
  251. $tests = new X_Page_ItemList_Test();
  252. $test = new X_Page_Item_Test($this->getId().'-writeaccess', '[OPFItalia] Checking for write access to /data/opfitalia/ folder');
  253. if ( is_writable(APPLICATION_PATH . '/../data/opfitalia/') ) {
  254. $test->setType(X_Page_Item_Message::TYPE_INFO);
  255. $test->setReason('Write access granted');
  256. } else {
  257. $test->setType(X_Page_Item_Message::TYPE_WARNING);
  258. $test->setReason("CookieJar file can't be stored, items fetch will be really slow");
  259. }
  260. $tests->append($test);
  261. $test = new X_Page_Item_Test($this->getId().'-credentials', '[OPFItalia] Checking for authentication credentials');
  262. if ( $this->config('auth.username', '') != '' && $this->config('auth.password', '') != '' ) {
  263. $test->setType(X_Page_Item_Message::TYPE_INFO);
  264. $test->setReason('Credentials configurated');
  265. } else {
  266. $test->setType(X_Page_Item_Message::TYPE_WARNING);
  267. $test->setReason("Credentials not configurated. Contents could be not viewed");
  268. }
  269. $tests->append($test);
  270. return $tests;
  271. }
  272. /**
  273. * Remove cookie.jar if configs change and convert form password to password element
  274. * @param string $section
  275. * @param string $namespace
  276. * @param unknown_type $key
  277. * @param Zend_Form_Element $element
  278. * @param Zend_Form $form
  279. * @param Zend_Controller_Action $controller
  280. */
  281. public function prepareConfigElement($section, $namespace, $key, Zend_Form_Element $element, Zend_Form $form, Zend_Controller_Action $controller) {
  282. // nothing to do if this isn't the right section
  283. if ( $namespace != $this->getId() ) return;
  284. switch ($key) {
  285. // i have to convert it to a password element
  286. case 'plugins_opfitalia_auth_password':
  287. $password = $form->createElement('password', 'plugins_opfitalia_auth_password', array(
  288. 'label' => $element->getLabel(),
  289. 'description' => $element->getDescription(),
  290. 'renderPassword' => true,
  291. ));
  292. $form->plugins_opfitalia_auth_password = $password;
  293. break;
  294. }
  295. // remove cookie.jar if somethings has value
  296. if ( !$form->isErrors() && !is_null($element->getValue()) && file_exists(APPLICATION_PATH . '/../data/opfitalia/cookie.jar') ) {
  297. if ( @!unlink(APPLICATION_PATH . '/../data/opfitalia/cookie.jar') ) {
  298. X_Debug::e("Error removing cookie.jar");
  299. }
  300. }
  301. }
  302. private function _fillPlaylist(X_Page_ItemList_PItem $items, $decoded, $lStack) {
  303. X_Debug::i("Decoded: ".print_r($decoded, true));
  304. // The format of $decoded (only notable parts):
  305. // {
  306. // ok: true|false
  307. // msg: $msg ; Setted only if ok = false
  308. // folderId: $thisFolder
  309. // folders: [
  310. // {
  311. // id: $folderID
  312. // name: $folderName
  313. // }, ...
  314. // ]
  315. // objects: [
  316. // {
  317. // id: $objectID
  318. // name: $objectName
  319. // link: http://...?...&video=urlencoded(URL)&...
  320. // },
  321. // {
  322. // id: $objectID
  323. // name: $objectName
  324. // link: http://...?...&host=megavideo&video=urlencoded(MEGAVIDEOURL)&...
  325. // },
  326. // ]
  327. // ...
  328. // }
  329. foreach ($decoded->folders as $folder) {
  330. $_stack = $lStack;
  331. $_stack[] = $folder->id;
  332. $item = new X_Page_Item_PItem("opfitalia-folder-{$folder->id}", urldecode($folder->name) );
  333. $item->setType(X_Page_Item_PItem::TYPE_CONTAINER)
  334. ->setGenerator(__CLASS__)
  335. ->setCustom(__CLASS__.':location', implode(':', $_stack))
  336. ->setLink(array(
  337. 'l' => X_Env::encode(implode(':', $_stack))
  338. ),'default', false);
  339. $items->append($item);
  340. }
  341. foreach ($decoded->objects as $object) {
  342. $item = new X_Page_Item_PItem("opfitalia-video-{$object->id}", urldecode($object->name) );
  343. $item->setType(X_Page_Item_PItem::TYPE_ELEMENT)
  344. ->setGenerator(__CLASS__);
  345. // time to decode the link arg
  346. // file: index.php?page=show_streaming&video=http:\/\/www.dbforever.net\/strm\/onepiece\/one_piece_459.mp4&width=704&height=430
  347. // megavideo: index.php?page=show_streaming&host=megavideo&video=http:\/\/www.megavideo.com\/v\/GIV2R76V038221ac298ceb332a9cad75288c318b&width=640&height=480
  348. $link = explode('&', $object->link);
  349. $type = 'file';
  350. $href = '';
  351. foreach ($link as $sublink) {
  352. list($arg, $value) = @explode('=', $sublink, 2);
  353. if ( $arg == 'host' ) {
  354. if ( $value == 'megavideo' ) {
  355. $type = 'megavideo';
  356. }
  357. }
  358. if ( $arg == 'video' ) {
  359. $href = str_replace('\\/', '/', urldecode($value));
  360. }
  361. }
  362. if ( $type == 'megavideo' ) {
  363. // i gave to split the /v/ param only
  364. $splitted = explode('/v/', $href, 2);
  365. if ( count($splitted) == 2 ) {
  366. $href = $splitted[1];
  367. } else {
  368. // try to decode it
  369. // as ?v=
  370. preg_match('#\?v=(.+?)$#', $href, $id);
  371. if ( count($id) >= 2 ) {
  372. $href = $id[1];
  373. } else {
  374. // if even this fail
  375. // i have to skip thi entry
  376. continue;
  377. }
  378. }
  379. $item->setLabel($item->getLabel()." [Megavideo]");
  380. }
  381. $item->setCustom(__CLASS__.':location', implode(':', $lStack)."/$type/$href")
  382. ->setLink(array(
  383. 'action' => 'mode',
  384. 'l' => X_Env::encode(implode(':', $lStack)."/$type/$href")
  385. ),'default', false);
  386. $items->append($item);
  387. }
  388. }
  389. private function _loadPage($uri) {
  390. X_Debug::i("Loading page $uri");
  391. $http = new Zend_Http_Client($uri, array(
  392. 'maxredirects' => $this->config('request.maxredirects', 10),
  393. 'timeout' => $this->config('request.timeout', 10),
  394. 'keepalive' => true
  395. ));
  396. $http->setHeaders(array(
  397. $this->config('hide.useragent', false) ? 'User-Agent: vlc-shares/'.X_VlcShares::VERSION : 'User-Agent: Mozilla/5.0 (X11; Linux i686; rv:2.0.1) Gecko/20101019 Firefox/4.0.1',
  398. 'X-Requested-With: XMLHttpRequest',
  399. 'Referer: http://www.opfitalia.net/mediacenter/index.php?page=show_streaming',
  400. 'Content-Type: application/x-www-form-urlencoded'
  401. ));
  402. $jarFile = APPLICATION_PATH . '/../data/opfitalia/cookie.jar';
  403. //$ns = new Zend_Session_Namespace(__CLASS__);
  404. if ( $this->jar == null ) {
  405. // Session disabled, i'm not sure wiimc can handle sessions
  406. /*if ( false && isset($ns->jar) && $ns->jar instanceof Zend_Http_CookieJar ) {
  407. $this->jar = $ns->jar;
  408. X_Debug::i('Loading stored authentication in Session');
  409. } else*/if ( file_exists($jarFile) ) {
  410. $this->jar = new Zend_Http_CookieJar();
  411. $cookies = unserialize(file_get_contents($jarFile));
  412. foreach ($cookies as $c) {
  413. $_c = new Zend_Http_Cookie($c['name'], $c['value'], $c['domain'], $c['exp'], $c['path']);
  414. $this->jar->addCookie($_c);
  415. }
  416. X_Debug::i('Loading stored authentication in File');
  417. } else {
  418. X_Debug::i('No cookie file');
  419. }
  420. }
  421. $http->setCookieJar($this->jar);
  422. //time to make the request
  423. $response = $http->request();
  424. $jsonString = $response->getBody();
  425. try {
  426. $decoded = Zend_Json::decode($jsonString, Zend_Json::TYPE_OBJECT);
  427. return $decoded;
  428. } catch (Exception $e) {
  429. // if the request doesn't return JSON code,
  430. // maybe user isn't authenticated
  431. X_Debug::i('User not authenticated');
  432. if ( $this->config('auth.username', '') != '' && $this->config('auth.password', '') != '' ) {
  433. X_Debug::i("Autentication needed");
  434. // do new login
  435. $http->setCookieJar(true);
  436. $pageLogin = $this->config('login.url', 'http://www.opfitalia.net/mediacenter/index.php?page=login');
  437. $http->setUri($pageLogin);
  438. // TODO remove this
  439. $http->setParameterPost ( array (
  440. 'username' => (string) $this->config('auth.username', ''),
  441. 'password' => (string) hash('sha256',$this->config('auth.password', ''), false),
  442. 'redirectUrl' => '',
  443. 'rememberMe' => '1'
  444. ) );
  445. // TODO remove this
  446. if ( APPLICATION_ENV == 'development' ) {
  447. $response = $http->request(Zend_Http_Client::POST);
  448. if ( !$this->_isAuthenticated($response->getBody(), 'correttamente' )) {
  449. X_Debug::w('Wrong credentials or authentication procedure doesn\'t work');
  450. } else {
  451. X_Debug::w('Client authenticated. Full access granted');
  452. }
  453. //X_Debug::i($response->getBody());
  454. } else {
  455. $http->request(Zend_Http_Client::POST);
  456. }
  457. $this->jar = $http->getCookieJar();
  458. // store the cookiejar
  459. $cks = $this->jar->getAllCookies(Zend_Http_CookieJar::COOKIE_OBJECT);
  460. foreach ($cks as $i => $c) {
  461. /* @var $c Zend_Http_Cookie */
  462. $cks[$i] = array(
  463. 'domain' => $c->getDomain(),
  464. 'exp' => $c->getExpiryTime(),
  465. 'name' => $c->getName(),
  466. 'path' => $c->getPath(),
  467. 'value' => $c->getValue()
  468. );
  469. }
  470. if ( @file_put_contents($jarFile, serialize($cks), LOCK_EX) === false ) {
  471. X_Debug::e('Error while writing jar file. Check permissions. Everything will work, but much more slower');
  472. }
  473. //$ns->jar = $this->jar;
  474. $http->setUri($uri);
  475. $http->resetParameters(false);
  476. $response = $http->request(Zend_Http_Client::GET);
  477. $jsonString = $response->getBody();
  478. try {
  479. $decoded = Zend_Json::decode($jsonString, Zend_Json::TYPE_OBJECT);
  480. } catch (Exception $e) {
  481. // epic fail
  482. // Useless authentication
  483. //X_Debug::i('Epic fail page: '.print_r($jsonString, true));
  484. throw new Exception('Authetication failed');
  485. }
  486. } else {
  487. throw new Exception('Username/Password not found');
  488. }
  489. }
  490. return $decoded;
  491. }
  492. /**
  493. * Search the html string for pattern that
  494. * give info about authentication
  495. * @param string $htmlString an opf page
  496. */
  497. private function _isAuthenticated($htmlString, $pattern = 'correttamente') {
  498. //$pattern = '<li class="welcomelink">';
  499. return ( strpos($htmlString, $pattern) !== false );
  500. }
  501. }