diff --git a/bridges/OtrkeyFinderBridge.php b/bridges/OtrkeyFinderBridge.php new file mode 100644 index 00000000..887ccd1b --- /dev/null +++ b/bridges/OtrkeyFinderBridge.php @@ -0,0 +1,173 @@ + array( + 'name' => 'Search term', + 'exampleValue' => 'Terminator', + 'defaultValue' => '', + 'title' => 'The search term is case-insensitive', + ), + 'station' => array( + 'name' => 'Station name', + 'exampleValue' => 'ARD', + 'defaultValue' => '', + ), + '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); + } +}