array( 'name' => 'Search term', 'exampleValue' => 'Terminator', 'title' => 'The search term is case-insensitive', ), 'station' => array( 'name' => 'Station name', 'exampleValue' => 'ARD', ), 'type' => array( 'name' => 'Media type', 'type' => 'list', 'values' => array( 'any' => '', 'Detail' => array( 'HD' => 'HD.avi', 'AC3' => 'HD.ac3', 'HD & AC3' => 'HD.', 'HQ' => 'HQ.avi', 'AVI' => 'g.avi', // 'g.' to exclude HD.avi and HQ.avi (filename always contains 'mpg.') 'MP4' => '.mp4', ), ), ), 'minTime' => array( 'name' => 'Min. running time', 'type' => 'number', 'title' => 'The minimum running time in minutes. The resolution is 5 minutes.', 'exampleValue' => '90', 'defaultValue' => '0', ), 'maxTime' => array( 'name' => 'Max. running time', 'type' => 'number', 'title' => 'The maximum running time in minutes. The resolution is 5 minutes.', 'exampleValue' => '120', 'defaultValue' => '0', ), 'pages' => array( 'name' => 'Number of pages', 'type' => 'number', 'title' => 'Specifies the number of pages to fetch. Increase this value if you get an empty feed.', 'exampleValue' => '5', 'defaultValue' => '5', ), ) ); // Example: Terminator_20.04.13_02-25_sf2_100_TVOON_DE.mpg.avi.otrkey // The first group is the running time in minutes const FILENAME_REGEX = '/_(\d+)_TVOON_DE\.mpg\..+\.otrkey/'; // year.month.day_hour-minute with leading zeros const TIME_REGEX = '/\d{2}\.\d{2}\.\d{2}_\d{2}-\d{2}/'; const CONTENT_TEMPLATE = ''; const MIRROR_TEMPLATE = '
  • %s
  • '; public function collectData() { $pages = $this->getInput('pages'); for($page = 1; $page <= $pages; $page++) { $uri = $this->buildUri($page); $html = getSimpleHTMLDOMCached($uri, self::CACHE_TIMEOUT) or returnServerError('Could not request ' . $uri); $keys = $html->find('div.otrkey'); foreach($keys as $key) { $temp = $this->buildItem($key); if ($temp != null) $this->items[] = $temp; } // Sleep for 0.5 seconds to don't hammer the server. usleep(500000); } } private function buildUri($page) { $searchterm = $this->getInput('searchterm'); $station = $this->getInput('station'); $type = $this->getInput('type'); // Combine all three parts to a search query by separating them with white space $search = implode(' ', array($searchterm, $station, $type)); $search = trim($search); $search = urlencode($search); return sprintf(self::URI_TEMPLATE, $search, $page); } private function buildItem(simple_html_dom_node $node) { $file = $this->getFilename($node); if ($file == null) return null; $minTime = $this->getInput('minTime'); $maxTime = $this->getInput('maxTime'); // Do we need to check the running time? if ($minTime != 0 || $maxTime != 0) { if ($maxTime > 0 && $maxTime < $minTime) returnClientError('The minimum running time must be less than the maximum running time.'); preg_match(self::FILENAME_REGEX, $file, $matches); if (!isset($matches[1])) return null; $time = (integer)$matches[1]; // Check for minimum running time if ($minTime > 0 && $minTime > $time) return null; // Check for maximum running time if ($maxTime > 0 && $maxTime < $time) return null; } $item = array(); $item['title'] = $file; // The URI_TEMPLATE for querying the site can be reused here $item['uri'] = sprintf(self::URI_TEMPLATE, $file, 1); $content = $this->buildContent($node); if ($content != null) $item['content'] = $content; if (preg_match(self::TIME_REGEX, $file, $matches) === 1) { $item['timestamp'] = DateTime::createFromFormat( 'y.m.d_H-i', $matches[0], new DateTimeZone('Europe/Berlin') )->getTimestamp(); } return $item; } private function getFilename(simple_html_dom_node $node) { $file = $node->find('.file', 0); if ($file == null) return null; else return trim($file->innertext); } private function buildContent(simple_html_dom_node $node) { $mirrors = $node->find('div.mirror'); $list = ''; // Build list of available mirrors foreach($mirrors as $mirror) { $anchor = $mirror->find('a', 0); $list .= sprintf(self::MIRROR_TEMPLATE, $anchor->href, $anchor->innertext); } return sprintf(self::CONTENT_TEMPLATE, $list); } }