PageRenderTime 195ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 1ms

/plugins/animeftw/library/X/VlcShares/Plugins/AnimeFTW.php

http://vlc-shares.googlecode.com/
PHP | 954 lines | 553 code | 224 blank | 177 comment | 122 complexity | fc6972993903e3995ef2020831662bd6 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 animeftw.tv site as a video source, using rest api
  8. *
  9. * @version 0.3
  10. * @author ximarx
  11. *
  12. */
  13. class X_VlcShares_Plugins_AnimeFTW extends X_VlcShares_Plugins_Abstract implements X_VlcShares_Plugins_ResolverInterface {
  14. const VERSION = '0.3.1';
  15. const VERSION_CLEAN = '0.3.1';
  16. const BASE_URL = 'http://www.animeftw.tv/';
  17. const PAGE_LOGIN = 'http://www.animeftw.tv/login';
  18. const PAGE_SERIES = 'http://www.animeftw.tv/videos';
  19. const PAGE_MOVIES = 'http://www.animeftw.tv/movies';
  20. const PAGE_OAV = 'http://www.animeftw.tv/ovas';
  21. const TYPE_SERIES_PERLETTER = 'videospletter';
  22. const TYPE_SERIES_PERGENRE = 'videospgenre';
  23. const TYPE_SERIES = 'videos';
  24. const TYPE_MOVIES = 'movies';
  25. const TYPE_OAV = 'ovas';
  26. /**
  27. * @var Zend_Http_CookieJar
  28. */
  29. private $jar = null;
  30. public function __construct() {
  31. $this->setPriority('gen_beforeInit')
  32. ->setPriority('getCollectionsItems')
  33. ->setPriority('preRegisterVlcArgs')
  34. ->setPriority('getShareItems')
  35. ->setPriority('preGetModeItems')
  36. ->setPriority('getIndexManageLinks')
  37. ->setPriority('getIndexMessages')
  38. ->setPriority('getTestItems')
  39. ->setPriority('prepareConfigElement')
  40. ;
  41. }
  42. /**
  43. * Inizialize translator for this plugin
  44. * @param Zend_Controller_Action $controller
  45. */
  46. function gen_beforeInit(Zend_Controller_Action $controller) {
  47. $this->helpers()->language()->addTranslation(__CLASS__);
  48. $this->helpers()->registerHelper('animeftw', new X_VlcShares_Plugins_Helper_AnimeFTW(array(
  49. 'username' => $this->config('auth.username', ''),
  50. 'password' => $this->config('auth.password', ''),
  51. )));
  52. }
  53. /**
  54. * Add the main link for animeftw
  55. * @param Zend_Controller_Action $controller
  56. */
  57. public function getCollectionsItems(Zend_Controller_Action $controller) {
  58. X_Debug::i("Plugin triggered");
  59. $link = new X_Page_Item_PItem($this->getId(), X_Env::_('p_animeftw_collectionindex'));
  60. $link->setIcon('/images/animeftw/logo.jpg')
  61. ->setDescription(X_Env::_('p_animeftw_collectionindex_desc'))
  62. ->setType(X_Page_Item_PItem::TYPE_CONTAINER)
  63. ->setLink(
  64. array(
  65. 'controller' => 'browse',
  66. 'action' => 'share',
  67. 'p' => $this->getId(),
  68. ), 'default', true
  69. );
  70. return new X_Page_ItemList_PItem(array($link));
  71. }
  72. /**
  73. * Get category/video list
  74. * @param unknown_type $provider
  75. * @param unknown_type $location
  76. * @param Zend_Controller_Action $controller
  77. */
  78. public function getShareItems($provider, $location, Zend_Controller_Action $controller) {
  79. if ( $provider != $this->getId() ) return;
  80. X_Debug::i('Plugin triggered');
  81. X_VlcShares_Plugins::broker()->unregisterPluginClass('X_VlcShares_Plugins_SortItems');
  82. $items = new X_Page_ItemList_PItem();
  83. X_Debug::i("Requested location: $location");
  84. $split = $location != '' ? @explode('/', $location, 5) : array();
  85. @list($type, $letter, $thread, $video) = $split;
  86. X_Debug::i("Exploded location: ".var_export($split, true));
  87. switch ( count($split) ) {
  88. // i should not be here, so i fallback to video case
  89. case 4:
  90. // show the list of video in the page
  91. case 3:
  92. $this->_fetchVideos($items, $type, $letter, $thread);
  93. break;
  94. // fetch the list of anime in group
  95. case 2:
  96. $this->_fetchThreads($items, $type, $letter);
  97. break;
  98. case 1:
  99. $this->_fetchClassification($items, $type);
  100. break;
  101. // fetch the list of groups
  102. default:
  103. $this->_fetchType($items);
  104. }
  105. return $items;
  106. }
  107. /**
  108. * This hook can be used to add low priority args in vlc stack
  109. *
  110. * @param X_Vlc $vlc vlc wrapper object
  111. * @param string $provider id of the plugin that should handle request
  112. * @param string $location to stream
  113. * @param Zend_Controller_Action $controller the controller who handle the request
  114. */
  115. public function preRegisterVlcArgs(X_Vlc $vlc, $provider, $location, Zend_Controller_Action $controller) {
  116. // this plugin inject params only if this is the provider
  117. if ( $provider != $this->getId() ) return;
  118. // i need to register source as first, because subtitles plugin use source
  119. // for create subfile
  120. X_Debug::i('Plugin triggered');
  121. $location = $this->resolveLocation($location);
  122. if ( $location !== null ) {
  123. // TODO adapt to newer api when ready
  124. $vlc->registerArg('source', "\"$location\"");
  125. } else {
  126. X_Debug::e("No source o_O");
  127. }
  128. }
  129. /**
  130. * Add button -watch megavideo stream directly-
  131. *
  132. * @param string $provider
  133. * @param string $location
  134. * @param Zend_Controller_Action $controller
  135. */
  136. public function preGetModeItems($provider, $location, Zend_Controller_Action $controller) {
  137. if ( $provider != $this->getId()) return;
  138. X_Debug::i("Plugin triggered");
  139. $url = $this->resolveLocation($location);
  140. if ( $url ) {
  141. $link = new X_Page_Item_PItem('core-directwatch', X_Env::_('p_animeftw_watchdirectly'));
  142. $link->setIcon('/images/icons/play.png')
  143. ->setType(X_Page_Item_PItem::TYPE_PLAYABLE)
  144. ->setLink($url);
  145. return new X_Page_ItemList_PItem(array($link));
  146. } else {
  147. // if there is no link, i have to remove start-vlc button
  148. // and replace it with a Warning button
  149. X_Debug::i('Setting priority to filterModeItems');
  150. $this->setPriority('filterModeItems', 99);
  151. $link = new X_Page_Item_PItem('megavideo-warning', X_Env::_('p_animeftw_invalidlink'));
  152. $link->setIcon('/images/msg_error.png')
  153. ->setType(X_Page_Item_PItem::TYPE_ELEMENT)
  154. ->setLink(array (
  155. 'controller' => 'browse',
  156. 'action' => 'share',
  157. 'p' => $this->getId(),
  158. 'l' => X_Env::encode($this->getParentLocation($location)),
  159. ), 'default', true);
  160. return new X_Page_ItemList_PItem(array($link));
  161. }
  162. }
  163. /**
  164. * Remove vlc-play button if location is invalid
  165. * @param X_Page_Item_PItem $item,
  166. * @param string $provider
  167. * @param Zend_Controller_Action $controller
  168. */
  169. public function filterModeItems(X_Page_Item_PItem $item, $provider,Zend_Controller_Action $controller) {
  170. if ( $item->getKey() == 'core-play') {
  171. X_Debug::i('plugin triggered');
  172. X_Debug::w('core-play flagged as invalid because the link is invalid');
  173. return false;
  174. }
  175. }
  176. /**
  177. * animeftw tests:
  178. * - check for username & password
  179. * - check for data/animeftw/ path writable
  180. * @param Zend_Config $options
  181. * @param Zend_Controller_Action $controller
  182. * @return X_Page_ItemList_Message
  183. */
  184. public function getTestItems(Zend_Config $options,Zend_Controller_Action $controller) {
  185. $tests = new X_Page_ItemList_Test();
  186. $test = new X_Page_Item_Test($this->getId().'-writeaccess', '[AnimeFTW] Checking for write access to /data/animeftw/ folder');
  187. if ( is_writable(APPLICATION_PATH . '/../data/animeftw/') ) {
  188. $test->setType(X_Page_Item_Message::TYPE_INFO);
  189. $test->setReason('Write access granted');
  190. } else {
  191. $test->setType(X_Page_Item_Message::TYPE_WARNING);
  192. $test->setReason("CookieJar file can't be stored, items fetch will be really slow");
  193. }
  194. $tests->append($test);
  195. $test = new X_Page_Item_Test($this->getId().'-credentials', '[AnimeFTW] Checking for authentication credentials');
  196. if ( $this->config('auth.username', '') != '' && $this->config('auth.password', '') != '' ) {
  197. $test->setType(X_Page_Item_Message::TYPE_INFO);
  198. $test->setReason('Credentials configurated');
  199. } else {
  200. $test->setType(X_Page_Item_Message::TYPE_FATAL);
  201. $test->setReason("Credentials not configurated. Contents cannot be viewed");
  202. }
  203. $tests->append($test);
  204. return $tests;
  205. }
  206. /**
  207. * Show a warning message if username and password aren't specified yet
  208. * @param Zend_Controller_Action $this
  209. * @return X_Page_ItemList_Message
  210. */
  211. public function getIndexMessages(Zend_Controller_Action $controller) {
  212. X_Debug::i('Plugin triggered');
  213. if ( $this->config('auth.username', '') == '' || $this->config('auth.password', '') == '' ) {
  214. $m = new X_Page_Item_Message($this->getId(), X_Env::_('p_animeftw_dashboardwarning'));
  215. $m->setType(X_Page_Item_Message::TYPE_ERROR);
  216. return new X_Page_ItemList_Message(array($m));
  217. }
  218. }
  219. private $cachedLocation = array();
  220. /**
  221. * @see X_VlcShares_Plugins_ResolverInterface::resolveLocation
  222. * @param string $location
  223. * @return string real address of a resource
  224. */
  225. function resolveLocation($location = null) {
  226. if ( $location == '' || $location == null ) return false;
  227. if ( array_key_exists($location, $this->cachedLocation) ) {
  228. return $this->cachedLocation[$location];
  229. }
  230. X_Debug::i("Requested location: $location");
  231. @list($type, $letter, $thread, $href) = explode('/', $location, 4);
  232. X_Debug::i("Type: $type, Letter: $letter, Thread: $thread, Ep: $href");
  233. if ( $href == null || $thread == null || $type == null ) {
  234. $this->cachedLocation[$location] = false;
  235. return false;
  236. }
  237. $return = false;;
  238. if ( $type == self::TYPE_SERIES_PERGENRE || $type == self::TYPE_SERIES_PERLETTER ) {
  239. if ($this->helpers()->devices()->isWiimc() || $this->config('proxy.enabled', true) ) {
  240. // X_Env::routeLink should be deprecated, but now is the best option
  241. $return = X_Env::routeLink('animeftw','proxy2', array(
  242. 'id' => X_Env::encode($href),
  243. ));
  244. } else {
  245. // $href is the video id
  246. try {
  247. /* @var $helper X_VlcShares_Plugins_Helper_AnimeFTW */
  248. $helper = $this->helpers('animeftw');
  249. $episode = $helper->getEpisode($href);
  250. if ( @$episode['url'] != '' ) {
  251. $return = $episode['url'];
  252. }
  253. } catch (Exception $e) {
  254. }
  255. }
  256. } else {
  257. // i have to fetch the streaming page :(
  258. $baseUrl = $this->config('base.url', self::BASE_URL);
  259. $baseUrl .= "$type/$thread/$href";
  260. $htmlString = $this->_loadPage($baseUrl, true);
  261. // <param name=\"src\" value=\"([^\"]*)\" \/>
  262. if ( preg_match('/<param name=\"src\" value=\"([^\"]*)\" \/>/', $htmlString, $match) ) {
  263. // link = match[1]
  264. $linkUrl = $match[1];
  265. if ( strpos($linkUrl, 'megavideo') !== false ) {
  266. @list(, $megavideoID) = explode('/v/', $linkUrl, 2);
  267. X_Debug::i("Megavideo ID: $megavideoID");
  268. try {
  269. /* @var $megavideo X_VlcShares_Plugins_Helper_Megavideo */
  270. $megavideo = $this->helpers('megavideo');
  271. // if server isn't specified, there is no video
  272. //$megavideo->setLocation($megavideoID);
  273. if ( $megavideo->setLocation($megavideoID)->getServer() ) {
  274. $return = $megavideo->getUrl();
  275. }
  276. } catch (Exception $e) {
  277. X_Debug::e($e->getMessage());
  278. }
  279. } else {
  280. // files in videos2.animeftw.tv require a valid referer page to be watched
  281. // and animeftw controller does the magic trick
  282. if ( /*strpos($linkUrl, 'videos2.animeftw.tv') !== false && */ $this->config('proxy.enabled', true) ) {
  283. // X_Env::routeLink should be deprecated, but now is the best option
  284. $linkUrl = X_Env::routeLink('animeftw','proxy', array(
  285. 'v' => X_Env::encode($linkUrl),
  286. 'r' => X_Env::encode($baseUrl) // baseUrl is the page containing the link
  287. ));
  288. }
  289. $return = $linkUrl;
  290. }
  291. }
  292. }
  293. $this->cachedLocation[$location] = $return;
  294. return $return;
  295. }
  296. /**
  297. * Support for parent location
  298. * @see X_VlcShares_Plugins_ResolverInterface::getParentLocation
  299. * @param $location
  300. */
  301. function getParentLocation($location = null) {
  302. if ( $location == '' || $location == null ) return false;
  303. //X_Debug::i($location);
  304. $exploded = @explode('/', $location);
  305. //X_Debug::i(var_export($exploded, true));
  306. $type = $exploded[0];
  307. if ( $type == self::TYPE_MOVIES && (count($exploded) == 4 || count($exploded) == 2) ) {
  308. array_pop($exploded);
  309. // extra pop if in movies and location is complete or is letter
  310. // because 3rd and 4th position are linked in type movies
  311. }
  312. array_pop($exploded);
  313. //X_Debug::i(var_export($exploded, true));
  314. if ( count($exploded) >= 1 ) {
  315. return implode('/', $exploded);
  316. } else {
  317. return null;
  318. }
  319. /*
  320. if ( $href != null ) {
  321. return $path;
  322. } else {
  323. $lStack = explode(':',$path);
  324. if ( count($lStack) > 1 ) {
  325. array_pop($lStack);
  326. return implode(':', $lStack);
  327. } else {
  328. return null;
  329. }
  330. }
  331. */
  332. }
  333. /**
  334. * Add the link for -manage-megavideo-
  335. * @param Zend_Controller_Action $this
  336. * @return X_Page_ItemList_ManageLink
  337. */
  338. public function getIndexManageLinks(Zend_Controller_Action $controller) {
  339. $link = new X_Page_Item_ManageLink($this->getId(), X_Env::_('p_animeftw_mlink'));
  340. $link->setTitle(X_Env::_('p_animeftw_managetitle'))
  341. ->setIcon('/images/animeftw/logo.jpg')
  342. ->setLink(array(
  343. 'controller' => 'config',
  344. 'action' => 'index',
  345. 'key' => 'animeftw'
  346. ), 'default', true);
  347. return new X_Page_ItemList_ManageLink(array($link));
  348. }
  349. /**
  350. * Remove cookie.jar if configs change and convert form password to password element
  351. * @param string $section
  352. * @param string $namespace
  353. * @param unknown_type $key
  354. * @param Zend_Form_Element $element
  355. * @param Zend_Form $form
  356. * @param Zend_Controller_Action $controller
  357. */
  358. public function prepareConfigElement($section, $namespace, $key, Zend_Form_Element $element, Zend_Form $form, Zend_Controller_Action $controller) {
  359. // nothing to do if this isn't the right section
  360. if ( $namespace != $this->getId() ) return;
  361. switch ($key) {
  362. // i have to convert it to a password element
  363. case 'plugins_animeftw_auth_password':
  364. $password = $form->createElement('password', 'plugins_animeftw_auth_password', array(
  365. 'label' => $element->getLabel(),
  366. 'description' => $element->getDescription(),
  367. 'renderPassword' => true,
  368. ));
  369. $form->plugins_animeftw_auth_password = $password;
  370. break;
  371. }
  372. // remove cookie.jar if somethings has value
  373. if ( !$form->isErrors() && !is_null($element->getValue()) && file_exists(APPLICATION_PATH . '/../data/animeftw/cookie.jar') ) {
  374. if ( @!unlink(APPLICATION_PATH . '/../data/animeftw/cookie.jar') ) {
  375. X_Debug::e("Error removing cookie.jar");
  376. }
  377. }
  378. }
  379. private function _fetchClassification(X_Page_ItemList_PItem $items, $type) {
  380. if ( $type == self::TYPE_SERIES || $type == self::TYPE_SERIES_PERLETTER ) {
  381. $lets = 'A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z';
  382. $lets = explode(',', $lets);
  383. foreach ( $lets as $l ) {
  384. $item = new X_Page_Item_PItem($this->getId()."-$type-$l", $l);
  385. $item->setIcon('/images/icons/folder_32.png')
  386. ->setType(X_Page_Item_PItem::TYPE_CONTAINER)
  387. ->setCustom(__CLASS__.':location', "$type/$l")
  388. ->setLink(array(
  389. 'l' => X_Env::encode("$type/$l")
  390. ), 'default', false);
  391. $items->append($item);
  392. }
  393. } elseif ( $type == self::TYPE_SERIES_PERGENRE ) {
  394. /* @var $helper X_VlcShares_Plugins_Helper_AnimeFTW */
  395. $helper = $this->helpers('animeftw');
  396. $genres = $helper->getGenres();
  397. foreach ( $genres as $genre => $count ) {
  398. if ( $genre == '' ) continue;
  399. $item = new X_Page_Item_PItem($this->getId()."-$type-$genre", X_Env::_('p_animeftw_genre', $genre, $count ));
  400. $item->setIcon('/images/icons/folder_32.png')
  401. ->setType(X_Page_Item_PItem::TYPE_CONTAINER)
  402. ->setCustom(__CLASS__.':location', "$type/$genre")
  403. ->setLink(array(
  404. 'l' => X_Env::encode("$type/$genre")
  405. ), 'default', false);
  406. $items->append($item);
  407. }
  408. } else {
  409. $item = new X_Page_Item_PItem($this->getId()."-$type-_", '_');
  410. $item->setIcon('/images/icons/folder_32.png')
  411. ->setType(X_Page_Item_PItem::TYPE_CONTAINER)
  412. ->setCustom(__CLASS__.':location', "$type/_")
  413. ->setLink(array(
  414. 'l' => X_Env::encode("$type/_")
  415. ), 'default', false);
  416. $items->append($item);
  417. }
  418. }
  419. private function _fetchType(X_Page_ItemList_PItem $items) {
  420. $item = new X_Page_Item_PItem($this->getId()."-seriesperletter", X_Env::_('p_animeftw_typeseries_perletter'));
  421. $item->setIcon('/images/icons/folder_32.png')
  422. ->setType(X_Page_Item_PItem::TYPE_CONTAINER)
  423. ->setCustom(__CLASS__.':location', self::TYPE_SERIES_PERLETTER)
  424. ->setLink(array(
  425. 'l' => X_Env::encode(self::TYPE_SERIES_PERLETTER)
  426. ), 'default', false);
  427. $items->append($item);
  428. $item = new X_Page_Item_PItem($this->getId()."-seriespergenre", X_Env::_('p_animeftw_typeseries_pergenre'));
  429. $item->setIcon('/images/icons/folder_32.png')
  430. ->setType(X_Page_Item_PItem::TYPE_CONTAINER)
  431. ->setCustom(__CLASS__.':location', self::TYPE_SERIES_PERGENRE)
  432. ->setLink(array(
  433. 'l' => X_Env::encode(self::TYPE_SERIES_PERGENRE)
  434. ), 'default', false);
  435. $items->append($item);
  436. if ( $this->config('sitescraper.enabled', false) ) {
  437. $item = new X_Page_Item_PItem($this->getId()."-series", X_Env::_('p_animeftw_typeseries'));
  438. $item->setIcon('/images/icons/folder_32.png')
  439. ->setType(X_Page_Item_PItem::TYPE_CONTAINER)
  440. ->setCustom(__CLASS__.':location', self::TYPE_SERIES)
  441. ->setLink(array(
  442. 'l' => X_Env::encode(self::TYPE_SERIES)
  443. ), 'default', false);
  444. $items->append($item);
  445. // movies
  446. $item = new X_Page_Item_PItem($this->getId()."-movies", X_Env::_('p_animeftw_typemovies'));
  447. $item->setIcon('/images/icons/folder_32.png')
  448. ->setType(X_Page_Item_PItem::TYPE_CONTAINER)
  449. ->setCustom(__CLASS__.':location', self::TYPE_MOVIES.'/_')
  450. ->setLink(array(
  451. 'l' => X_Env::encode(self::TYPE_MOVIES.'/_')
  452. ), 'default', false);
  453. $items->append($item);
  454. // oav
  455. $item = new X_Page_Item_PItem($this->getId()."-oav", X_Env::_('p_animeftw_typeoav'));
  456. $item->setIcon('/images/icons/folder_32.png')
  457. ->setType(X_Page_Item_PItem::TYPE_CONTAINER)
  458. ->setCustom(__CLASS__.':location', self::TYPE_OAV)
  459. ->setLink(array(
  460. 'l' => X_Env::encode(self::TYPE_OAV)
  461. ), 'default', false);
  462. $items->append($item);
  463. }
  464. }
  465. private function _fetchThreadsAPI(X_Page_ItemList_PItem $items, $type, $filter) {
  466. /* @var $helper X_VlcShares_Plugins_Helper_AnimeFTW */
  467. $helper = $this->helpers('animeftw');
  468. $series = $helper->getAnime($filter);
  469. foreach ($series as $serie) {
  470. /*
  471. $serie = array(
  472. 'id' => trim((string) $serie->id),
  473. 'label' => trim((string) $serie->seriesName),
  474. 'romaji' => trim((string) $serie->romaji),
  475. 'description' => trim(strip_tags((string) $series->description )),
  476. 'thumbnail' => trim((string) $serie->image),
  477. 'episodes' => trim((string) $serie->episodes),
  478. 'movies' => trim((string) $serie->movies),
  479. 'href' => value
  480. );
  481. */
  482. $item = new X_Page_Item_PItem($this->getId()."-$type-{$serie['id']}", X_Env::_('p_animeftw_serie', $serie['label'], $serie['romaji'], $serie['episodes'], $serie['movies'] ));
  483. $item->setIcon('/images/icons/folder_32.png')
  484. ->setThumbnail($serie['thumbnail'])
  485. ->setType(X_Page_Item_PItem::TYPE_CONTAINER )
  486. ->setCustom(__CLASS__.':location', "$type/$filter/{$serie['href']}")
  487. ->setLink(array(
  488. 'l' => X_Env::encode("$type/$filter/{$serie['href']}"),
  489. ), 'default', false);
  490. if ( APPLICATION_ENV == 'development' ) {
  491. $item->setDescription("$type/$filter/{$serie['href']}");
  492. } else {
  493. $item->setDescription($serie['description']);
  494. }
  495. $items->append($item);
  496. }
  497. }
  498. private function _fetchThreads(X_Page_ItemList_PItem $items, $type, $letter) {
  499. X_Debug::i("Fetching threads for $type/$letter");
  500. switch ($type) {
  501. case self::TYPE_SERIES_PERGENRE:
  502. case self::TYPE_SERIES_PERLETTER:
  503. $this->_fetchThreadsAPI($items, $type, $letter);
  504. return;
  505. case self::TYPE_SERIES:
  506. $indexUrl = $this->config('index.series.url', self::PAGE_SERIES);
  507. // more info for xpath: http://www.questionhub.com/StackOverflow/3428104
  508. $queryXpath = '//a[@name="'.$letter.'"]/following-sibling::div[count(.| //a[@name="'.$letter.'"]/following-sibling::a[1]/preceding-sibling::div)=count(//a[@name="'.$letter.'"]/following-sibling::a[1]/preceding-sibling::div)]/a';
  509. break;
  510. case self::TYPE_OAV:
  511. $indexUrl = $this->config('index.oav.url', self::PAGE_OAV);
  512. $queryXpath = '//a[@name="'.$letter.'"]/following-sibling::div[count(.| //a[@name="'.$letter.'"]/following-sibling::a[1]/preceding-sibling::div)=count(//a[@name="'.$letter.'"]/following-sibling::a[1]/preceding-sibling::div)]/a';
  513. break;
  514. case self::TYPE_MOVIES:
  515. $indexUrl = $this->config('index.movies.url', self::PAGE_MOVIES);
  516. $queryXpath = '//div[@class="mpart"]//a';
  517. break;
  518. }
  519. $htmlString = $this->_loadPage($indexUrl, true);
  520. $dom = new Zend_Dom_Query($htmlString);
  521. // fetch all threads inside the table
  522. //$results = $dom->queryXpath('//table[@id="streaming_elenco"]//a[@name="' . $letter . '"][text()!=""]/ancestor::table[@id="streaming_elenco"]/tr[@class!="header"]/td[@class="serie"]/a');
  523. $results = $dom->queryXpath($queryXpath);
  524. X_Debug::i("Threads found: ".$results->count());
  525. for ( $i = 0; $i < $results->count(); $i++, $results->next()) {
  526. $current = $results->current();
  527. $label = $current->textContent;
  528. $href = $current->getAttribute('href');
  529. if ( $type == self::TYPE_MOVIES ) {
  530. if ( X_Env::startWith($href, $this->config('index.movie.url', self::PAGE_MOVIES) ) ) {
  531. $href = substr($href, strlen($this->config('index.movie.url', self::PAGE_MOVIES)));
  532. }
  533. // now href has format: /anime/movies, and we need both
  534. // so replace / with a safer :
  535. //$href = str_replace('/', ':', trim($href, '/'));
  536. $href = trim($href, '/');
  537. } else {
  538. // href has format: /category/$NEEDEDVALUE/
  539. // so i trim / from the bounds and then i get the $NEEDEDVALUE
  540. @list(,$href) = explode('/', trim($href, '/'));
  541. }
  542. $item = new X_Page_Item_PItem($this->getId()."-$label", $label);
  543. $item->setIcon('/images/icons/folder_32.png')
  544. ->setType($type == self::TYPE_MOVIES ? X_Page_Item_PItem::TYPE_ELEMENT : X_Page_Item_PItem::TYPE_CONTAINER )
  545. ->setCustom(__CLASS__.':location', "$type/$letter/$href")
  546. ->setLink(array(
  547. 'l' => X_Env::encode("$type/$letter/$href"),
  548. 'action' => $type == self::TYPE_MOVIES ? 'mode' : 'share'
  549. ), 'default', false);
  550. if ( APPLICATION_ENV == 'development' ) {
  551. $item->setDescription("$type/$letter/$href");
  552. }
  553. $items->append($item);
  554. }
  555. }
  556. private function _fetchVideosAPI(X_Page_ItemList_PItem $items, $type, $filter, $href) {
  557. /* @var $helper X_VlcShares_Plugins_Helper_AnimeFTW */
  558. $helper = $this->helpers('animeftw');
  559. $episodes = $helper->getEpisodes($href);
  560. foreach ($episodes as $episode) {
  561. /*
  562. $episode = array(
  563. 'id' => trim((string) $episodeNode->id),
  564. 'epnumber' => trim((string) $episodeNode->epnumber),
  565. 'label' => trim((string) $episodeNode->name),
  566. 'movie' => false,
  567. 'type' => trim((string) $episodeNode->type),
  568. 'url' => trim((string) $episodeNode->videolink),
  569. 'thumbnail' => ''
  570. );
  571. */
  572. $item = new X_Page_Item_PItem($this->getId()."-$type-{$episode['id']}", X_Env::_('p_animeftw_episode', $episode['label'], $episode['epnumber'], ($episode['movie'] ? X_Env::_('p_animeftw_ismovie') : '' ) ) );
  573. $item->setIcon("/images/animeftw/file_{$episode['type']}.png")
  574. ->setThumbnail($episode['thumbnail'] != '' ? $episode['thumbnail'] : null )
  575. ->setType(X_Page_Item_PItem::TYPE_ELEMENT)
  576. ->setCustom(__CLASS__.':location', "$type/$filter/$href/{$episode['id']}")
  577. ->setLink(array(
  578. 'l' => X_Env::encode("$type/$filter/$href/{$episode['id']}"),
  579. 'action' => 'mode'
  580. ), 'default', false);
  581. if ( APPLICATION_ENV == 'development' ) {
  582. $item->setDescription("$type/$filter/$href/{$episode['id']}");
  583. }
  584. $items->append($item);
  585. }
  586. }
  587. private function _fetchVideos(X_Page_ItemList_PItem $items, $type, $letter, $thread) {
  588. X_Debug::i("Fetching videos for $type/$letter/$thread");
  589. if ( $type == self::TYPE_SERIES_PERGENRE || $type == self::TYPE_SERIES_PERLETTER ) {
  590. return $this->_fetchVideosAPI($items, $type, $letter, $thread);
  591. }
  592. $baseUrl = $this->config('base.url', self::BASE_URL);
  593. // threads for movies have / -> : conversion
  594. $_thread = str_replace(':', '/', $thread);
  595. $baseUrl .= "$type/$_thread";
  596. $htmlString = $this->_loadPage($baseUrl, true);
  597. // XPATH doesn't work well. Maybe for kanji inside the page, so i use regex
  598. $cleaned = stristr(strstr($htmlString, 'Episodes:'), '</table>', true);
  599. $regexp = "<a\s[^>]*href=(\"??)([^\" >]*?)\\1[^>]*>(.*)<\/a>";
  600. if(preg_match_all("/$regexp/siU", $cleaned, $matches, PREG_SET_ORDER)) {
  601. //X_Debug::i(var_export($matches, true));
  602. foreach($matches as $match) {
  603. // $match[2] = link address
  604. // $match[3] = link text
  605. $label = $match[3];
  606. if ( $label == '') {
  607. $label = X_Env::_('p_animeftw_nonamevideo');
  608. }
  609. $href = $match[2];
  610. // href format: http://www.animeftw.tv/videos/baccano/ep-3
  611. if ( X_Env::startWith($href, $this->config('base.url', self::BASE_URL) ) ) {
  612. $href = substr($href, strlen($this->config('base.url', self::BASE_URL)));
  613. }
  614. // href format: videos/baccano/ep-3
  615. @list( , ,$epName) = explode('/', trim($href, '/'));
  616. // works even without the $epName
  617. $href=$epName;
  618. //$found = true;
  619. X_Debug::i("Valid link found: $href");
  620. $item = new X_Page_Item_PItem($this->getId()."-$label", $label);
  621. $item->setIcon('/images/icons/folder_32.png')
  622. ->setType(X_Page_Item_PItem::TYPE_ELEMENT)
  623. ->setCustom(__CLASS__.':location', "$type/$letter/$thread/$href")
  624. ->setLink(array(
  625. 'action' => 'mode',
  626. 'l' => X_Env::encode("$type/$letter/$thread/$href")
  627. ), 'default', false);
  628. if ( APPLICATION_ENV == 'development' ) {
  629. $item->setDescription("$type/$letter/$thread/$href");
  630. }
  631. $items->append($item);
  632. }
  633. }
  634. }
  635. private function _loadPage($uri, $forceAuth = false) {
  636. X_Debug::i("Loading page $uri");
  637. $http = new Zend_Http_Client($uri, array(
  638. 'maxredirects' => $this->config('request.maxredirects', 10),
  639. 'timeout' => $this->config('request.timeout', 10),
  640. 'keepalive' => true
  641. ));
  642. $http->setHeaders(array(
  643. //$this->config('hide.useragent', true) ? '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',
  644. //'Content-Type: application/x-www-form-urlencoded'
  645. 'User-Agent: vlc-shares/'.X_VlcShares::VERSION.' animeftw/'.self::VERSION
  646. ));
  647. $jarFile = APPLICATION_PATH . '/../data/animeftw/cookie.jar';
  648. $ns = new Zend_Session_Namespace(__CLASS__);
  649. if ( $this->jar == null ) {
  650. if ( false && isset($ns->jar) && $ns->jar instanceof Zend_Http_CookieJar ) {
  651. $this->jar = $ns->jar;
  652. X_Debug::i('Loading stored authentication in Session');
  653. } elseif ( file_exists($jarFile) ) {
  654. if ( filectime($jarFile) < (time() - 24 * 60 * 60) ) {
  655. X_Debug::i('Jarfile is old. Refreshing it');
  656. @unlink($jarFile);
  657. } else {
  658. $this->jar = new Zend_Http_CookieJar();
  659. $cookies = unserialize(file_get_contents($jarFile));
  660. foreach ($cookies as $c) {
  661. $_c = new Zend_Http_Cookie($c['name'], $c['value'], $c['domain'], $c['exp'], $c['path']);
  662. $this->jar->addCookie($_c);
  663. }
  664. X_Debug::i('Loading stored authentication in File');
  665. }
  666. }
  667. }
  668. $http->setCookieJar($this->jar);
  669. $response = $http->request();
  670. $htmlString = $response->getBody();
  671. if ( $forceAuth && $this->config('auth.username', '') != '' && $this->config('auth.password', '') != '' && !$this->_isAuthenticated($htmlString) ) {
  672. X_Debug::i("Autentication needed");
  673. $http->setCookieJar(true);
  674. $pageLogin = $this->config('login.url', self::PAGE_LOGIN);
  675. $http->setUri($pageLogin);
  676. $http->setParameterPost ( array (
  677. // TODO REMOVE AUTH
  678. 'username' => (string) $this->config('auth.username', ''),
  679. 'password' => (string) $this->config('auth.password', ''),
  680. '_submit_check' => '1',
  681. 'submit' => 'Sign In',
  682. 'remember' => 'on',
  683. 'last_page' => 'https://www.animeftw.tv',
  684. ) );
  685. // TODO remove this
  686. if ( APPLICATION_ENV == 'development' ) {
  687. $response = $http->request(Zend_Http_Client::POST);
  688. if ( !$this->_isAuthenticated($response->getBody())) {
  689. X_Debug::w('Wrong credentials or authentication procedure doesn\'t work');
  690. } else {
  691. X_Debug::w('Client authenticated. Full access granted');
  692. }
  693. //X_Debug::i($response->getBody());
  694. } else {
  695. $http->request(Zend_Http_Client::POST);
  696. }
  697. $this->jar = $http->getCookieJar();
  698. // store the cookiejar
  699. $cks = $this->jar->getAllCookies(Zend_Http_CookieJar::COOKIE_OBJECT);
  700. foreach ($cks as $i => $c) {
  701. /* @var $c Zend_Http_Cookie */
  702. $cks[$i] = array(
  703. 'domain' => $c->getDomain(),
  704. 'exp' => $c->getExpiryTime(),
  705. 'name' => $c->getName(),
  706. 'path' => $c->getPath(),
  707. 'value' => $c->getValue()
  708. );
  709. }
  710. if ( @file_put_contents($jarFile, serialize($cks), LOCK_EX) === false ) {
  711. X_Debug::e('Error while writing jar file. Check permissions. Everything will work, but much more slower');
  712. }
  713. //$ns->jar = $this->jar;
  714. // time to do a new old request
  715. //$http->resetParameters();
  716. $http->setUri($uri);
  717. $response = $http->request(Zend_Http_Client::GET);
  718. $htmlString = $response->getBody();
  719. }
  720. return $htmlString;
  721. }
  722. private function _isAuthenticated($htmlString, $pattern = '<a href="https://www.animeftw.tv/logout">Logout</a>') {
  723. return ( strpos($htmlString, $pattern) !== false );
  724. }
  725. }