-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[OtrkeyFinderBridge] Add bridge for otrkeyfinder.com (#1712)
- Loading branch information
Showing
1 changed file
with
173 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
<?php | ||
class OtrkeyFinderBridge extends BridgeAbstract { | ||
const MAINTAINER = 'mibe'; | ||
const NAME = 'OtrkeyFinder'; | ||
const URI = 'https://otrkeyfinder.com'; | ||
const URI_TEMPLATE = 'https://otrkeyfinder.com/en/?search=%s&order=&page=%d'; | ||
const CACHE_TIMEOUT = 3600; // 1h | ||
const DESCRIPTION = 'Returns the newest .otrkey files matching the search criteria.'; | ||
const PARAMETERS = array( | ||
array( | ||
'searchterm' => 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 = '<ul>%s</ul>'; | ||
const MIRROR_TEMPLATE = '<li><a href="https://otrkeyfinder.com%s">%s</a></li>'; | ||
|
||
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); | ||
} | ||
} |