/** * Add the button BackToStream in controls page * * @param X_Streamer_Engine $engine * @param Zend_Controller_Action $controller the controller who handle the request * @return array */ public function preGetControlItems(X_Streamer_Engine $engine, Zend_Controller_Action $controller) { $urlHelper = $controller->getHelper('url'); $return = new X_Page_ItemList_PItem(); if ($this->config('show.title', true)) { $onAirName = X_Env::_("p_streaminfo_unknown_source"); if ($engine instanceof X_Streamer_Engine_Vlc) { $vlc = $engine->getVlcWrapper(); $onAirName = $vlc->getCurrentName(); } else { // try to find the name from the location (if any) $providerId = $controller->getRequest()->getParam('p', false); $location = $controller->getRequest()->getParam('l', false); if ($providerId && $location) { $providerObj = X_VlcShares_Plugins::broker()->getPlugins($providerId); $location = X_Env::decode($location); if ($providerObj instanceof X_VlcShares_Plugins_ResolverInterface) { $onAirName = $providerObj->resolveLocation($location); } } } // show the title of the file $item = new X_Page_Item_PItem('streaminfo-onair', X_Env::_('p_streaminfo_onair') . ": {$onAirName}"); $item->setType(X_Page_Item_PItem::TYPE_ELEMENT)->setLink(X_Env::completeUrl($urlHelper->url())); $return->append($item); } if ($engine instanceof X_Streamer_Engine_Vlc) { $vlc = $engine->getVlcWrapper(); if ($this->config('show.time', false)) { $currentTime = X_Env::formatTime($vlc->getCurrentTime()); $totalTime = X_Env::formatTime($vlc->getTotalTime()); $item = new X_Page_Item_PItem('streaminfo-time', "{$currentTime}/{$totalTime}"); $item->setType(X_Page_Item_PItem::TYPE_ELEMENT)->setLink(X_Env::completeUrl($urlHelper->url())); $return->append($item); } } return $return; }
protected function _convertoToSrt(Zend_Dom_Query $dom) { $this->getResponse()->setHeader('Content-type', 'application/x-subrip', true); //$this->getResponse()->setHeader('Content-type', 'text/plain', true); $results = $dom->queryXpath('//text'); $i = 1; $string = ''; while ($results->valid()) { $current = $results->current(); $from = $current->getAttribute('start'); $dur = $current->getAttribute('dur'); $text = $current->nodeValue; $end = (double) $from + (double) $dur; $from = explode('.', (string) $from); $from = X_Env::formatTime($from[0]) . ',' . str_pad(substr($from[1], 0, 3), 3, '0', STR_PAD_RIGHT); $end = explode('.', (string) $end); $end = X_Env::formatTime($end[0]) . ',' . str_pad(substr($end[1], 0, 3), 3, '0', STR_PAD_RIGHT); $text = str_replace(array('"', '&', '''), array("\"", "&", "'"), utf8_decode($text)); $string .= "{$i}\r\n"; $string .= "{$from} --> {$end}\r\n"; $string .= "{$text}\r\n"; $string .= "\r\n"; $results->next(); $i++; } return $string; }
private function _prepareVideo(X_Page_ItemList_PItem $items, Zend_Gdata_Media_Feed $feed, $locationPrefix) { foreach ($feed as $yvideo) { /* @var $yvideo Zend_Gdata_YouTube_VideoEntry */ if ($yvideo->getVideoDuration() == 0) { continue; } // no duration = no video $item = new X_Page_Item_PItem('youtube-video-' . $yvideo->getVideoId(), $yvideo->getVideoTitle() . ' [' . X_Env::formatTime($yvideo->getVideoDuration()) . ']'); $thumb = $yvideo->getVideoThumbnails(); @($thumb = $thumb[0]['url']); $item->setDescription($yvideo->getVideoDescription())->setType(X_Page_Item_PItem::TYPE_ELEMENT)->setIcon('/images/youtube/icons/video.png')->setThumbnail($thumb)->setCustom(__CLASS__ . ':location', "{$locationPrefix}/{$yvideo->getVideoId()}")->setLink(array('action' => 'mode', 'l' => X_Env::encode("{$locationPrefix}/{$yvideo->getVideoId()}")), 'default', false)->setGenerator(__CLASS__); $items->append($item); } }
/** * get an array with standard information about the playable * @param string $url the hoster page or resource ID * @param boolean $isId * @return array format: * array( * 'title' => TITLE * 'description' => DESCRIPTION * 'length' => LENGTH * ... * ) */ function getPlayableInfos($url, $isId = true) { if (!$isId) { $url = $this->getResourceId($url); } // $url is an id now for sure /* @var $youtubeHelper X_VlcShares_Plugins_Helper_Youtube */ $youtubeHelper = X_VlcShares_Plugins::helpers()->helper('youtube'); try { $videoEntry = $youtubeHelper->getVideo($url); $thumb = $videoEntry->getVideoThumbnails(); $thumb = @$thumb[0]['url']; $thumb = str_replace('default', '0', $thumb); // use cached values $infos = array('title' => $videoEntry->getVideoTitle(), 'description' => $videoEntry->getVideoDescription(), 'length' => X_Env::formatTime($videoEntry->getVideoDuration()), 'thumbnail' => $thumb); return $infos; } catch (Exception $e) { throw new Exception("Invalid video", self::E_ID_INVALID); } }
public function gen_afterPageBuild(X_Page_ItemList_PItem $list, Zend_Controller_Action $controller) { // force Rendering win over everythings /*if ( !$this->_forceRendering ) { if ( !((bool) $this->config('forced.enabled', false)) && !$this->helpers()->devices()->isWiimc() ) return; } */ // new renderer interface if (!$this->isDefaultRenderer()) { return; } X_Debug::i("Plugin triggered"); $request = $controller->getRequest(); $enhanced = $this->helpers()->devices()->isWiimcEnhanced() && $this->config('support.enhanced', true); $plx = new X_Plx(X_Env::_('p_wiimcplxrenderer_plxtitle_' . $request->getControllerName() . '_' . $request->getActionName()), X_Env::_('p_wiimcplxrenderer_plxdescription_' . $request->getControllerName() . '_' . $request->getActionName())); // wiimc plus custom tags if ($enhanced) { $plx->setWiimcplus_generator_name('vlc-shares'); // uses the __call api $plx->setWiimcplus_generator_version(X_VlcShares::VERSION_CLEAN); // uses the __call api if ($request->getControllerName() == 'index' && $request->getActionName() == 'collections') { $plx->setWiimcplus_assert_mainmenu('true'); // uses the __call api } // show the current time as custom playlist header tag if the page is controls/control or browse/stream if ($request->getControllerName() == 'controls' && $request->getActionName() == 'control' || $request->getControllerName() == 'browse' && $request->getActionName() == 'stream') { $vlc = X_Vlc::getLastInstance(); if ($vlc) { // check to be sure that vlc is running right now $currentTime = X_Env::formatTime($vlc->getCurrentTime()); $totalTime = X_Env::formatTime($vlc->getTotalTime()); $plx->setWiimcplus_current_time("{$currentTime}/{$totalTime}"); // uses the __call api } } elseif ($request->getControllerName() == 'browse' && $request->getActionName() == 'selection') { $plx->setWiimcplus_assert_nohistory('true'); // uses the __call api } } foreach ($list->getItems() as $i => $item) { /* @var $item X_Page_Item_PItem */ $plxItemName = ($item->isHighlight() ? '-) ' : '') . $item->getLabel(); $plxItemWiimcplusIcon = null; switch ($item->getType()) { case X_Page_Item_PItem::TYPE_CONTAINER: $plxItemType = X_Plx_Item::TYPE_PLAYLIST; $plxItemWiimcplusIcon = 'folder'; break; case X_Page_Item_PItem::TYPE_ELEMENT: $plxItemType = X_Plx_Item::TYPE_PLAYLIST; if ($request->getControllerName() == 'browse' && $request->getActionName() == 'share') { $plxItemWiimcplusIcon = 'file'; } break; case X_Page_Item_PItem::TYPE_REQUEST: $plxItemType = X_Plx_Item::TYPE_SEARCH; break; case X_Page_Item_PItem::TYPE_PLAYABLE: $plxItemType = X_Plx_Item::TYPE_VIDEO; break; default: $plxItemType = $item->getType(); } /* @var $urlHelper Zend_Controller_Action_Helper_Url */ $urlHelper = $controller->getHelper('url'); $plxItemUrl = $item->isUrl() ? $item->getLink() : X_Env::completeUrl($urlHelper->url($item->getLink(), $item->getRoute(), $item->isReset())); $plxItem = new X_Plx_Item($plxItemName, $plxItemUrl, $plxItemType); if ($item->getThumbnail() != null) { if (X_Env::startWith($item->getThumbnail(), 'http') || X_Env::startWith($item->getThumbnail(), 'https')) { $plxItem->setThumb($item->getThumbnail()); } else { $plxItem->setThumb(X_Env::completeUrl($item->getThumbnail())); } } if ($enhanced) { if ($plxItemWiimcplusIcon !== null) { $plxItem->setWiimcplus_icon($plxItemWiimcplusIcon); } if ($item->getKey() == 'core-separator') { $plxItem->setWiimcplus_assert_separator('true'); } if ($item->getKey() == 'core-directwatch') { $plxItem->setWiimcplus_assert_directwatch('true'); if ($item->getCustom('subtitle') != null) { $plxItem->setWiimcplus_subtitle($item->getCustom('subtitle')); } } if ($item->getKey() == 'core-play') { $plxItem->setWiimcplus_assert_startvlc('true'); } } $plx->addItem($plxItem); } $this->_render($plx, $controller); }
/** * get an array with standard information about the playable * @param string $url the hoster page or resource ID * @param boolean $isId * @return array format: * array( * 'title' => TITLE * 'description' => DESCRIPTION * 'length' => LENGTH * ... * ) */ function getPlayableInfos($url, $isId = true) { if (!$isId) { $url = $this->getResourceId($url); } // use cached values if (array_key_exists($url, $this->info_cache)) { return $this->info_cache[$url]; } // use the api $http = new Zend_Http_Client("http://www.vimeo.com/moogaloop/load/clip:{$url}/local?param_force_embed=0¶m_clip_id={$url}¶m_show_portrait=0¶m_multimoog=¶m_server=vimeo.com¶m_show_title=0¶m_autoplay=0¶m_show_byline=0¶m_color=00ADEF¶m_fullscreen=1¶m_md5=0¶m_context_id=&context_id=null", array('headers' => array('User-Agent' => "vlc-shares/" . X_VlcShares::VERSION . " vimeo/" . X_VlcShares_Plugins_Vimeo::VERSION))); $datas = $http->request()->getBody(); $xml = new SimpleXMLElement($datas); if (@$xml['error']) { throw new Exception("Invalid ID {{$url}}", self::E_ID_INVALID); } $infos = array('title' => (string) @$xml->video->caption, 'description' => '', 'length' => X_Env::formatTime((string) @$xml->video->duration), 'thumbnail' => (string) @$xml->video->thumbnail, 'request_signature' => (string) @$xml->request_signature, 'request_signature_expires' => (string) @$xml->request_signature_expires); // add in cache $this->info_cache[$url] = $infos; return $infos; }
public function getPositions($location, $sourceFile) { $positions = array(); try { /* @var $cacheHelper X_VlcShares_Plugins_Helper_Cache */ $cacheHelper = X_VlcShares_Plugins::helpers('cache'); $positions = $cacheHelper->retrieveItem("streamseeker::{$location}"); if ($positions) { $positions = @unserialize($positions); } X_Debug::i("Using positions values stored in cache about {$location}"); // return stored values return $positions; } catch (Exception $e) { // no cache plugin or no positions cached X_Debug::i("No FLV info in cache about {$location}"); } // dump 9kb of the file to analyze it $tmpFile = tempnam(sys_get_temp_dir(), 'fia'); $sampleSize = intval($this->options->get('samplesize', 100)) * 1000; X_Debug::i("Downloading {$sampleSize} bytes in {$tmpFile} from {$sourceFile}"); $src = fopen($sourceFile, 'r'); $dest = fopen($tmpFile, 'w'); $copied = stream_copy_to_stream($src, $dest, $sampleSize); fclose($src); fclose($dest); X_Debug::i("{$copied} bytes downloaded"); try { $flvinfo = new X_FLVInfo(); $fileInfo = $flvinfo->getInfo($tmpFile, true, true); if ($fileInfo->signature) { $keyframes = @$fileInfo->rawMeta[1]['keyframes']; $times = $keyframes->times; $filepositions = $keyframes->filepositions; $lastAdd = 0; //$firstKey = 0; $minDelta = intval($this->options->get('mindelta', 5)) * 60; // mindelta is in minutes // time to parse and filter the response // filter using a minDelta function foreach ($times as $key => $seconds) { /* if ( $key == 0 ) { $firstKey = $filepositions[$key]; continue; }*/ if ($seconds - $lastAdd > $minDelta) { // new step //$positions["{$filepositions[$key]},{$firstKey}"] = X_Env::formatTime(intval($seconds)); $positions[$filepositions[$key]] = X_Env::formatTime(intval($seconds)); $lastAdd = intval($seconds); } } X_Debug::i("Valid position found in flv file: " . count($positions)); // parse done, store try { /* @var $cacheHelper X_VlcShares_Plugins_Helper_Cache */ $cacheHelper = X_VlcShares_Plugins::helpers('cache'); $cacheHelper->storeItem("streamseeker::{$location}", serialize($positions), $this->options->get('cachevalidity', 10)); } catch (Exception $e) { X_Debug::e("Cache is disabled. This is really bad for streamseeker"); } } else { X_Debug::w("Wrong signature. Can't analyze"); } } catch (Exception $e) { X_Debug::e("FLVInfo throws an error: {$e->getMessage()}"); } return $positions; }
public function fetch($infoOnly = false) { if ($this->_location == null) { X_Debug::w('Trying to fetch a hulu location without a location'); throw new Exception('Trying to fetch a hulu location without a location'); } if ($this->_fetched === false) { // ported code form http://gitorious.org/get-flash-videos-plugins/gfv-plugins/blobs/raw/release/Hulu.pm $http = $this->getHttpClient("http://www.hulu.com/watch/{$this->_location}"); $response = $http->request(); $datas = $response->getBody(); X_Debug::i("Fetching main page for: {{$this->_location}}"); //echo "<b>REQUESTED PAGE</b><textarea>".htmlentities($datas)."</textarea><br/>"; $pageUrl = str_replace('.com:80/', '.com/', $http->getUri(true)); X_Debug::i("Last location is {{$pageUrl}}"); /* $matches = array(); if ( !preg_match('/content_id\"\, (?P<CID>[0-9]+?)\)/', $datas, $matches) ) { X_Debug::e("Content_ID pattern failure"); throw new Exception("Content_ID pattern failure"); } $content_id = $matches['CID']; echo "<b>CONTENT ID FOUND:</b><textarea>".htmlentities($content_id)."</textarea><br/>"; */ $matches = array(); if (!preg_match('/videoEmbedId = "(?P<EID>[^\\"]+?)"/', $datas, $matches)) { X_Debug::e("EID pattern failure"); X_Debug::i("Searching EID in: \n{$datas}"); throw new Exception("EID pattern failure"); } $eid = $matches['EID']; //echo "<b>EID FOUND:</b><textarea>".htmlentities($eid)."</textarea><br/>"; X_Debug::i("EID Found {{$eid}}"); // fetch information about the player, required by rtmp //list($swfsize, $swfhash, $swfUrl) = $this->getPlayerData(); //$http->setHeaders('Host', 'r.hulu.com'); //echo "<b>API URL:</b><textarea>".htmlentities("http://r.hulu.com/videos?content_id=$content_id")."</textarea><br/>"; //$http->setUri("http://r.hulu.com/videos?content_id=$content_id"); $apiUrl = 'http://r.hulu.com/videos?eid=' . $eid; X_Debug::i("Fetching video info from {{$apiUrl}}"); $http->setUri($apiUrl); //echo "<b>API URL:</b><textarea>".htmlentities($apiUrl)."</textarea><br/>"; $datas = $http->request()->getBody(); //$http->setHeaders('Host', null); //echo "<b>API RESPONSE 1</b><textarea>".htmlentities($datas)."</textarea><br/>"; $xml = new SimpleXMLElement($datas); if ($xml->video == null) { X_Debug::e("Invalid response for EID {{$eid}}"); X_Debug::i("Response: \n{$datas}"); throw new Exception("Invalid response for EID {{$eid}}"); } //echo "<b>ENCODED PID</b><textarea>".htmlentities((string) $xml->video->pid[0])."</textarea><br/>"; X_Debug::i("Encoded PID: {{$xml->video[0]->pid[0]}}"); $pid = $this->decodePid((string) $xml->video[0]->pid[0]); X_Debug::i("Decoded PID: {{$pid}}"); //echo "<b>DECRYPTED PID</b><textarea>".htmlentities($pid)."</textarea><br/>"; $title = (string) $xml->video->title[0]; if ($xml->video->{'media-type'} == "TV") { $show_name = $xml->video->show->name[0]; $season = $xml->video->{"season-number"}[0]; $episode_number = $xml->video->{"episode-number"}[0]; $title = sprintf('%s - S%02dE%02d - %s', $show_name, $season, $episode_number, $title); } $description = (string) $xml->video->description[0]; $length = X_Env::formatTime((int) $xml->video->duration[0]); $thumbnail = (string) $xml->video->{"thumbnail-url"}[0]; $needProxy = $xml->video->{"allow-international"}[0] == 'false' ? true : false; if ($infoOnly) { $infos = array('title' => $title, 'description' => $description, 'length' => $length, 'thumbnail' => $thumbnail, 'needProxy' => $needProxy); X_Debug::i("Video info: " . print_r($infos, true)); return $infos; } // new focus on smil infos //$auth = md5($pid.self::$KEYS_PLAYER); //echo "<b>AUTH</b><pre>$auth</pre><br/>"; //echo "<b>REQUEST</b><pre>http://s.hulu.com/select.ashx?pid=$pid&auth=$auth&v=".self::$KEYS_V."</pre><br/>"; //$http->setUri("http://s.hulu.com/select.ashx?pid=$pid&auth=$auth&v=".self::$KEYS_V); $now = (int) time(); $parameters = array('video_id' => $pid, 'v' => self::$KEYS_V, 'ts' => (string) $now, 'np' => '1', 'vp' => '1', 'device_id' => '', 'pp' => 'Desktop', 'dp_id' => 'Hulu', 'region' => 'US', 'ep' => '1', 'language' => 'en'); $paramKeys = array_keys($parameters); $sortedParams = $parameters; ksort($sortedParams); $bcsl = ''; foreach ($sortedParams as $key => $value) { $bcsl .= $key . $value; } $bcs = hash_hmac('md5', $bcsl, self::$HMAC); $smil_file_url = 'http://s.hulu.com/select?' . http_build_query($sortedParams) . "&bcs={$bcs}"; X_Debug::i("Fetching SMIL file from {{$smil_file_url}}"); //echo "<b>SMIL FILE URL</b><textarea>".htmlentities($smil_file_url)."</textarea><br/>"; $http->setUri($smil_file_url); $datas = $http->request()->getBody(); //echo "<b>ENCODED SMIL</b><textarea>".htmlentities($datas)."</textarea><br/>"; $datas = $this->decodeSmil($datas); //echo "<b>DECRYPTED SMIL</b><textarea>".htmlentities($datas)."</textarea><br/>"; X_Debug::i("Decoded SMIL (50 chars only): \n" . substr($datas, 0, 50) . "..."); $xml = new SimpleXMLElement($datas); //$vids = $xml->body->switch[1]->video[0]; $vids = $xml->body->switch[1]->video; //[0]; //$ref = $xml->body->switch[1]->ref[0]; // choose the better source... ignored now //echo "<b>VIDEOS</b><pre>".print_r($vid, true)."</pre><br/>"; if ($this->options->get('priority', 'cdn')) { $vids = $this->filterCdn($vids, $this->options->get('cdn', 'limelight')); $vids = $this->filterCdn($vids, $this->options->get('quality', '400_h264')); } else { $vids = $this->filterCdn($vids, $this->options->get('quality', '400_h264')); $vids = $this->filterCdn($vids, $this->options->get('cdn', 'limelight')); } $vid = @$vids[0]; // if no vid available yet, just try to get the first one if (!$vid) { X_Debug::w('Filter mode failed'); $vid = $xml->body->switch[1]->video[0]; } if (is_null($vid)) { X_Debug::e('No video tag. Video requires HULU Plus or you are not in US'); X_Debug::i("Video info: " . print_r($vid, true)); throw new Exception('No video tag. Video requires HULU Plus or you are not in US'); } X_Debug::i("Selected video info: " . print_r($vid, true)); // ported code: http://code.google.com/p/bluecop-xbmc-repo/source/browse/trunk/plugin.video.hulu/resources/lib/stream_hulu.py?spec=svn157&r=157 $stream = (string) $vid['stream']; $server = (string) $vid['server']; $token = (string) $vid['token']; $cdn = (string) $vid['cdn']; $hostname = ""; $appName = ""; $protocol = ""; $pattern = '/^(?P<protocol>[a-zA-z]+:\\/\\/)(?P<hostname>[^\\/]+)\\/(?P<appname>.*)$/'; $matches = array(); if (preg_match($pattern, $server, $matches)) { $protocol = $matches['protocol']; $hostname = $matches['hostname']; $appName = $matches['appname']; } // rtmp params based on cdn switch ($cdn) { case 'level3': $appName .= "?sessionid=sessionId&{$token}"; $stream = substr($stream, 0, -4); // remove .mp4 $server = "{$server}?sessionid=sessionId&{$token}"; break; case 'limelight': $appName .= "?sessionid=sessionId&{$token}"; $stream = substr($stream, 0, -4); // remove .mp4 $server = "{$server}?sessionid=sessionId&{$token}"; break; case 'akamai': $appName .= "?sessionid=sessionId&{$token}"; $server = "{$server}?sessionid=sessionId&{$token}"; break; default: } $this->_fetched = array('title' => $title, 'description' => $description, 'length' => $length, 'thumbnail' => $thumbnail, 'eid' => $eid, 'pid' => $pid, 'needProxy' => $needProxy, 'stream' => $stream, 'server' => $server, 'token' => $token, 'cdn' => $cdn, 'hostname' => $hostname, 'protocol' => $protocol, 'appName' => $appName, 'playpath' => $stream, 'pageUrl' => self::HULU_PLAYER, 'swfUrl' => self::HULU_PLAYER); $this->_fetched['url'] = X_RtmpDump::buildUri(array('rtmp' => $server, 'app' => $appName, 'playpath' => $stream, 'swfUrl' => self::HULU_PLAYER, 'pageUrl' => self::HULU_PLAYER, 'swfVfy' => self::HULU_PLAYER)); $this->_cachedSearch[$this->_location] = $this->_fetched; //X_Debug::i("All info: ".print_r($this->_fetched, true)); return $this->_fetched; } }