');
+
+ $item = array();
+ $item['uri'] = $article_url;
+ $item['title'] = $article_title;
+ $item['author'] = $article_author;
+ $item['timestamp'] = $article_timestamp;
+ $item['content'] = trim($contents);
+ $this->items[] = $item;
+ $limit++;
+ }
+ }
+
+ }
+}
diff --git a/bridges/TheOatMealBridge.php b/bridges/TheOatMealBridge.php
index 97aae693..3c3d216f 100644
--- a/bridges/TheOatMealBridge.php
+++ b/bridges/TheOatMealBridge.php
@@ -1,64 +1,29 @@
maintainer = "Riduidel";
- $this->name = "The Oatmeal";
- $this->uri = "http://theoatmeal.com/";
- $this->description = "Un petit site de dessins assez rigolos";
- $this->update = "2015-07-03";
-
- }
-
- public function collectData(array $param){
- parent::collectExpandableDatas($param, THE_OATMEAL_RSS);
+ public function collectData(){
+ $this->collectExpandableDatas('http://feeds.feedburner.com/oatmealfeed');
}
+ protected function parseItem($newsItem) {
+ $item = $this->parseRSS_1_0_Item($newsItem);
- /**
- * Since the oatmeal produces a weird RSS feed, I have to fix it by loading the items separatly from the feed infos
- */
- protected function collect_RSS_2_0_data($rssContent) {
- $rssContent->registerXPathNamespace("dc", "http://purl.org/dc/elements/1.1/");
- $rssHeaderContent = $rssContent->channel[0];
-// $this->message("RSS content is ===========\n".var_export($rssHeaderContent, true)."===========");
- $this->load_RSS_2_0_feed_data($rssHeaderContent);
- foreach($rssContent->item as $item) {
- $this->message("parsing item ".var_export($item, true));
- $this->items[] = $this->parseRSSItem($item);
- }
- }
-
-
- protected function parseRSSItem($newsItem) {
- $namespaces = $newsItem->getNameSpaces(true);
- $dc = $newsItem->children($namespaces['dc']);
- $rdf = $newsItem->children($namespaces['rdf']);
- $item = new Item();
- $item->title = trim($newsItem->title);
- $this->message("browsing Oatmeal item ".var_export($newsItem, true));
- $item->uri=$newsItem->attributes($namespaces['rdf'])->about;
- // now load that uri from cache
- $this->message("now loading page ".$item->uri);
- $articlePage = str_get_html($this->get_cached($item->uri));
-
+ $articlePage = $this->getSimpleHTMLDOMCached($item['uri']);
$content = $articlePage->find('#comic', 0);
- if($content==null) {
- $content = $articlePage->find('#blog');
- }
- $item->content = $content->innertext;
-
- $this->message("dc content is ".var_export($dc, true));
- $item->name = $dc->creator;
- $item->timestamp = DateTime::createFromFormat(DateTime::ISO8601, $dc->date)->getTimestamp();
- $this->message("writtem by ".$item->name." on ".$item->timestamp);
+ if(is_null($content)) // load alternative
+ $content = $articlePage->find('#blog', 0);
+
+ if(!is_null($content))
+ $item['content'] = $content->innertext;
+
return $item;
}
-
+
public function getCacheDuration(){
return 7200; // 2h hours
}
diff --git a/bridges/ThePirateBayBridge.php b/bridges/ThePirateBayBridge.php
index 3e55c605..3fe61de9 100644
--- a/bridges/ThePirateBayBridge.php
+++ b/bridges/ThePirateBayBridge.php
@@ -1,25 +1,20 @@
maintainer = "mitsukarenai";
- $this->name = "The Pirate Bay";
- $this->uri = "https://thepiratebay.se/";
- $this->description = "Returns results for the keywords. You can put several list of keywords by separating them with a semicolon (e.g. \"one show;another show\")";
- $this->update = "2015-01-09";
+ const PARAMETERS = array( array(
+ 'q'=>array(
+ 'name'=>'keywords, separated by semicolons',
+ 'exampleValue'=>'first list;second list;…',
+ 'required'=>true
+ )
+ ));
- $this->parameters[] =
- '[
- {
- "name" : "keywords, separated by semicolons",
- "identifier" : "q",
- "exampleValue" : "first list;second list;..."
- }
- ]';
- }
-
- public function collectData(array $param){
+ public function collectData(){
function parseDateTimestamp($element){
$guessedDate = $element->find('font',0)->plaintext;
@@ -55,41 +50,27 @@ class ThePirateBayBridge extends BridgeAbstract{
}
- if (!isset($param['q']))
- $this->returnError('You must specify keywords (?q=...)', 400);
-
- $keywordsList = explode(";",$param['q']);
+ $keywordsList = explode(";",$this->getInput('q'));
foreach($keywordsList as $keywords){
- $html = file_get_html('https://thepiratebay.se/search/'.rawurlencode($keywords).'/0/3/0') or $this->returnError('Could not request TPB.', 404);
+ $html = $this->getSimpleHTMLDOM(self::URI.'search/'.rawurlencode($keywords).'/0/3/0')
+ or $this->returnServerError('Could not request TPB.');
if ($html->find('table#searchResult', 0) == FALSE)
- $this->returnError('No result for query '.$keywords, 404);
+ $this->returnServerError('No result for query '.$keywords);
foreach($html->find('tr') as $element) {
- $item = new \Item();
- $item->uri = 'https://thepiratebay.se/'.$element->find('a.detLink',0)->href;
- $item->id = $item->uri;
- $item->timestamp = parseDateTimestamp($element);
- $item->title = $element->find('a.detLink',0)->plaintext;
- $item->seeders = (int)$element->find('td',2)->plaintext;
- $item->leechers = (int)$element->find('td',3)->plaintext;
- $item->content = $element->find('font',0)->plaintext.'
seeders: '.$item->seeders.' | leechers: '.$item->leechers.'
download';
- if(!empty($item->title))
+ $item = array();
+ $item['uri'] = self::URI.$element->find('a.detLink',0)->href;
+ $item['id'] = $item['uri'];
+ $item['timestamp'] = parseDateTimestamp($element);
+ $item['title'] = $element->find('a.detLink',0)->plaintext;
+ $item['seeders'] = (int)$element->find('td',2)->plaintext;
+ $item['leechers'] = (int)$element->find('td',3)->plaintext;
+ $item['content'] = $element->find('font',0)->plaintext.'
seeders: '.$item['seeders'].' | leechers: '.$item['leechers'].'
download';
+ if(isset($item['title']))
$this->items[] = $item;
}
}
}
-
- public function getName(){
- return 'The Pirate Bay';
- }
-
- public function getURI(){
- return 'https://thepiratebay.se/';
- }
-
- public function getCacheDuration(){
- return 3600; // 1 hour
- }
}
diff --git a/bridges/TuxboardBridge.php b/bridges/TuxboardBridge.php
deleted file mode 100644
index 63f9d092..00000000
--- a/bridges/TuxboardBridge.php
+++ /dev/null
@@ -1,64 +0,0 @@
-maintainer = "superbaillot.net";
- $this->name = "Tuxboard";
- $this->uri = "http://www.tuxboard.com/";
- $this->description = "Tuxboard";
- $this->update = "2014-07-08";
-
- }
-
- public function collectData(array $param){
-
- function StripCDATA($string) {
- $string = str_replace('', '', $string);
- return $string;
- }
-
- function ExtractContent($url) {
- $html2 = file_get_html($url);
- $text = $html2->find('article#page', 0)->innertext;
- $text = preg_replace('@@si', '', $text);
- return $text;
- }
-
- $html = file_get_html('http://www.tuxboard.com/feed/atom/') or $this->returnError('Could not request Tuxboard.', 404);
- $limit = 0;
-
- foreach($html->find('entry') as $element) {
- if($limit < 10) {
- $item = new \Item();
- $item->title = StripCDATA($element->find('title', 0)->innertext);
- $item->uri = $element->find('link', 0)->href;
- $item->timestamp = strtotime($element->find('published', 0)->plaintext);
- $item->content = ExtractContent($item->uri);
- $this->items[] = $item;
- $limit++;
- }
- }
-
-
-
- }
-
- public function getName(){
- return 'Tuxboard';
- }
-
- public function getURI(){
- return 'http://www.tuxboard.com';
- }
-
- public function getDescription(){
- return 'Tuxboard via rss-bridge';
- }
-
- public function getCacheDuration(){
- return 3600; // 1 hour
- }
-}
-?>
diff --git a/bridges/TwitchApiBridge.php b/bridges/TwitchApiBridge.php
index c3dbdefb..11da945d 100644
--- a/bridges/TwitchApiBridge.php
+++ b/bridges/TwitchApiBridge.php
@@ -1,76 +1,34 @@
array(
+ 'channel'=>array(
+ 'name'=>'Channel',
+ 'required'=>true
+ ),
+ 'broadcasts'=>array(
+ 'name'=>'Show Broadcasts rather than Highlights',
+ 'type'=>'checkbox'
+ ),
+ 'limit'=>array(
+ 'name'=>'Limit',
+ 'type'=>'number'
+ )
+ )
+ );
- $this->maintainer = "logmanoriginal";
- $this->name = "Twitch API Bridge";
- $this->uri = "http://www.twitch.tv";
- $this->description = "Returns the newest broadcasts or highlights by channel name using the Twitch API (v3)";
- $this->update = "2016-01-09";
+ public function collectData(){
- $this->parameters["Get channel without limit"] =
- '[
- {
- "name" : "Channel",
- "identifier" : "channel"
- },
- {
- "name" : "Broadcasts",
- "identifier" : "broadcasts",
- "type" : "list",
- "values" : [
- {
- "name" : "Show broadcasts",
- "value" : "true"
- },
- {
- "name" : "Show highlights",
- "value" : "false"
- }
- ]
- }
- ]';
- $this->parameters["Get channel with limit"] =
- '[
- {
- "name" : "Channel",
- "identifier" : "channel"
- },
- {
- "name" : "Limit",
- "identifier" : "limit",
- "type" : "number"
- },
- {
- "name" : "Broadcasts",
- "identifier" : "broadcasts",
- "type" : "list",
- "values" : [
- {
- "name" : "Show broadcasts",
- "value" : "true"
- },
- {
- "name" : "Show highlights",
- "value" : "false"
- }
- ]
- }
- ]';
-
- }
-
- public function collectData(array $param){
-
- /* In accordance with API description:
- * "When specifying a version for a request to the Twitch API, set the Accept HTTP header to the API version you prefer."
+ /* In accordance with API description:
+ * "When specifying a version for a request to the Twitch API, set the Accept HTTP header to the API version you prefer."
* Now we prefer v3 right now and need to build the context options. */
$opts = array('https' =>
array(
@@ -78,80 +36,63 @@ class TwitchApiBridge extends BridgeAbstract{
'header' => 'Accept: application/vnd.twitchtv.v3+json'
)
);
-
+
$context = stream_context_create($opts);
-
- $channel = '';
- $limit = TWITCH_LIMIT;
- $broadcasts = TWITCH_BROADCASTS;
- $requests = 1;
-
- if(isset($param['channel'])) {
- $channel = $param['channel'];
- } else {
- $this->returnError('You must specify a valid channel name! Received: &channel=' . $param['channel'], 400);
- }
-
- $this->channel = $channel;
-
- if(isset($param['limit'])) {
- try {
- $limit = (int)$param['limit'];
- } catch (Exception $e){
- $this->returnError('The limit you specified is not valid! Received: &limit=' . $param['limit'] . ' Expected: &limit=
where is any integer number.', 400);
- }
- } else {
+
+ $limit = $this->getInput('limit');
+ if(!$limit){
$limit = TWITCH_LIMIT;
}
-
+
// The Twitch API allows a limit between 1 .. 100. Therefore any value below must be set to 1, any greater must result in multiple requests.
+ $requests=1;
if($limit < 1) { $limit = 1; }
- if($limit > 100) {
- $requests = (int)($limit / 100);
+ if($limit > 100) {
+ $requests = (int)($limit / 100);
if($limit % 100 != 0) { $requests++; }
}
-
- if(isset($param['broadcasts']) && ($param['broadcasts'] == 'true' || $param['broadcasts'] == 'false')) {
- $broadcasts = $param['broadcasts'];
- } else {
- $this->returnError('The value for broadcasts you specified is not valid! Received: &broadcasts=' . $param['broadcasts'] . ' Expected: &broadcasts=false or &broadcasts=true', 400);
+
+ if($this->getInput('broadcasts')){
+ $broadcasts='true';
+ }else{
+ $broadcasts='false';
}
-
+
+
// Build the initial request, see also: https://github.com/justintv/Twitch-API/blob/master/v3_resources/videos.md#get-channelschannelvideos
$request = '';
-
+
if($requests == 1) {
- $request = 'https://api.twitch.tv/kraken/channels/' . $channel . '/videos?limit=' . $limit . '&broadcasts=' . $broadcasts;
+ $request = 'https://api.twitch.tv/kraken/channels/' . $this->getInput('channel') . '/videos?limit=' . $limit . '&broadcasts=' . $broadcasts;
} else {
- $request = 'https://api.twitch.tv/kraken/channels/' . $channel . '/videos?limit=100&broadcasts=' . $broadcasts;
+ $request = 'https://api.twitch.tv/kraken/channels/' . $this->getInput('channel') . '/videos?limit=100&broadcasts=' . $broadcasts;
}
-
+
/* Finally we're ready to request data from the API. Each response provides information for the next request. */
for($i = 0; $i < $requests; $i++) {
- $response = file_get_contents($request, false, $context);
-
- if($response == false) {
- $this->returnError('Request failed! Check if the channel name is valid!', 400);
+ $response = $this->getSimpleHTMLDOM($request, false, $context);
+
+ if($response == false) {
+ $this->returnServerError('Request failed! Check if the channel name is valid!');
}
-
+
$data = json_decode($response);
-
+
foreach($data->videos as $video) {
- $item = new \Item();
- $item->id = $video->_id;
- $item->uri = $video->url;
- $item->thumbnailUri = $video->preview;
- $item->title = htmlspecialchars($video->title);
- $item->timestamp = strtotime($video->recorded_at);
- $item->content = '
' . $item->title . '';
+ $item = array();
+ $item['id'] = $video->_id;
+ $item['uri'] = $video->url;
+ $item['title'] = htmlspecialchars($video->title);
+ $item['timestamp'] = strtotime($video->recorded_at);
+ $item['content'] = '
' . $item['title'] . '';
$this->items[] = $item;
-
+
// Stop once the number of requested items is reached
if(count($this->items) >= $limit) {
break;
}
}
-
+
// Get next request (if available)
if(isset($data->_links->next)) {
$request = $data->_links->next;
@@ -162,11 +103,7 @@ class TwitchApiBridge extends BridgeAbstract{
}
public function getName(){
- return (!empty($this->channel) ? $this->channel . ' - ' : '') . 'Twitch API Bridge';
- }
-
- public function getURI(){
- return 'https://www.twitch.tv';
+ return $this->getInput('channel') . ' - Twitch API Bridge';
}
public function getCacheDuration(){
diff --git a/bridges/TwitterBridge.php b/bridges/TwitterBridge.php
index 90dea5b3..e30f7f08 100644
--- a/bridges/TwitterBridge.php
+++ b/bridges/TwitterBridge.php
@@ -1,84 +1,142 @@
maintainer = "mitsukarenai";
- $this->name = "Twitter Bridge";
- $this->uri = "http://twitter.com/";
- $this->description = "Returns user timelines or keyword/hashtag search results (without using their API).";
- $this->update = "2014-05-25";
-
- $this->parameters["By keyword or hashtag"] =
- '[
- {
- "name" : "Keyword or #hashtag",
- "identifier" : "q"
- }
- ]';
-
- $this->parameters["By username"] =
- '[
- {
- "name" : "username",
- "identifier" : "u"
- }
- ]';
-
- }
-
- public function collectData(array $param){
- $html = '';
- if (isset($param['q'])) { /* keyword search mode */
- $this->request = $param['q'];
- $html = file_get_html('https://twitter.com/search?q='.urlencode($this->request).'&f=tweets') or $this->returnError('No results for this query.', 404);
- }
- elseif (isset($param['u'])) { /* user timeline mode */
- $this->request = $param['u'];
- $html = file_get_html('http://twitter.com/'.urlencode($this->request)) or $this->returnError('Requested username can\'t be found.', 404);
- }
- else {
- $this->returnError('You must specify a keyword (?q=...) or a Twitter username (?u=...).', 400);
- }
-
- foreach($html->find('div.js-stream-tweet') as $tweet) {
- $item = new \Item();
- $item->username = $tweet->getAttribute('data-screen-name'); // extract username and sanitize
- $item->fullname = $tweet->getAttribute('data-name'); // extract fullname (pseudonym)
- $item->avatar = $tweet->find('img', 0)->src; // get avatar link
- $item->id = $tweet->getAttribute('data-tweet-id'); // get TweetID
- $item->uri = 'https://twitter.com'.$tweet->find('a.js-permalink', 0)->getAttribute('href'); // get tweet link
- $item->timestamp = $tweet->find('span.js-short-timestamp', 0)->getAttribute('data-time'); // extract tweet timestamp
- // processing content links
- foreach($tweet->find('a') as $link) {
- if($link->hasAttribute('data-expanded-url') ) {
- $link->href = $link->getAttribute('data-expanded-url');
- }
- $link->removeAttribute('data-expanded-url');
- $link->removeAttribute('data-query-source');
- $link->removeAttribute('rel');
- $link->removeAttribute('class');
- $link->removeAttribute('target');
- $link->removeAttribute('title');
- }
- $item->content = str_replace('href="/', 'href="https://twitter.com/', strip_tags($tweet->find('p.js-tweet-text', 0)->innertext, '')); // extract tweet text
- $item->title = $item->fullname . ' (@' . $item->username . ') | ' . strip_tags($item->content);
- $this->items[] = $item;
- }
- }
+ const NAME='Twitter Bridge';
+ const URI='https://twitter.com/';
+ const DESCRIPTION='returns tweets';
+ const PARAMETERS=array(
+ 'global'=>array(
+ 'nopic'=>array(
+ 'name'=>'Hide profile pictures',
+ 'type'=>'checkbox',
+ 'title'=>'Activate to hide profile pictures in content'
+ )
+ ),
+ 'By keyword or hashtag' => array(
+ 'q'=>array(
+ 'name'=>'Keyword or #hashtag',
+ 'required'=>true,
+ 'exampleValue'=>'rss-bridge, #rss-bridge',
+ 'title'=>'Insert a keyword or hashtag'
+ )
+ ),
+ 'By username' => array(
+ 'u'=>array(
+ 'name'=>'username',
+ 'required'=>true,
+ 'exampleValue'=>'sebsauvage',
+ 'title'=>'Insert a user name'
+ ),
+ 'norep'=>array(
+ 'name'=>'Without replies',
+ 'type'=>'checkbox',
+ 'title'=>'Only return initial tweets'
+ )
+ )
+ );
public function getName(){
- return (!empty($this->request) ? $this->request .' - ' : '') .'Twitter Bridge';
+ switch($this->queriedContext){
+ case 'By keyword or hashtag':
+ $specific='search ';
+ $param='q';
+ break;
+ case 'By username':
+ $specific='@';
+ $param='u';
+ break;
+ }
+ return 'Twitter '.$specific.$this->getInput($param);
}
public function getURI(){
- return 'http://twitter.com';
+ switch($this->queriedContext){
+ case 'By keyword or hashtag':
+ return self::URI.'search?q='.urlencode($this->getInput('q')).'&f=tweets';
+ case 'By username':
+ return self::URI.urlencode($this->getInput('u')).
+ ($this->getInput('norep')?'':'/with_replies');
+ }
}
- public function getCacheDuration(){
- return 300; // 5 minutes
- }
+ public function collectData(){
+ $html = '';
+
+ $html = $this->getSimpleHTMLDOM($this->getURI());
+ if(!$html){
+ switch($this->queriedContext){
+ case 'By keyword or hashtag':
+ $this->returnServerError('No results for this query.');
+ case 'By username':
+ $this->returnServerError('Requested username can\'t be found.');
+ }
+ }
+
+ $hidePictures = $this->getInput('nopic');
+
+ foreach($html->find('div.js-stream-tweet') as $tweet) {
+ $item = array();
+ // extract username and sanitize
+ $item['username'] = $tweet->getAttribute('data-screen-name');
+ // extract fullname (pseudonym)
+ $item['fullname'] = $tweet->getAttribute('data-name');
+ // get author
+ $item['author'] = $item['fullname'] . ' (@' . $item['username'] . ')';
+ // get avatar link
+ $item['avatar'] = $tweet->find('img', 0)->src;
+ // get TweetID
+ $item['id'] = $tweet->getAttribute('data-tweet-id');
+ // get tweet link
+ $item['uri'] = self::URI.$tweet->find('a.js-permalink', 0)->getAttribute('href');
+ // extract tweet timestamp
+ $item['timestamp'] = $tweet->find('span.js-short-timestamp', 0)->getAttribute('data-time');
+ // generate the title
+ $item['title'] = strip_tags(html_entity_decode($tweet->find('p.js-tweet-text', 0)->innertext,ENT_QUOTES,'UTF-8'));
+
+ // processing content links
+ foreach($tweet->find('a') as $link) {
+ if($link->hasAttribute('data-expanded-url') ) {
+ $link->href = $link->getAttribute('data-expanded-url');
+ }
+ $link->removeAttribute('data-expanded-url');
+ $link->removeAttribute('data-query-source');
+ $link->removeAttribute('rel');
+ $link->removeAttribute('class');
+ $link->removeAttribute('target');
+ $link->removeAttribute('title');
+ }
+
+ // process emojis (reduce size)
+ foreach($tweet->find('img.Emoji') as $img){
+ $img->style .= ' height: 1em;';
+ }
+
+ // get tweet text
+ $cleanedTweet = str_replace('href="/', 'href="'.self::URI, $tweet->find('p.js-tweet-text', 0)->innertext);
+
+ // Add picture to content
+ $picture_html = '';
+ if(!$hidePictures){
+ $picture_html = <<
+EOD;
+ }
+
+ // add content
+ $item['content'] = <<
+ {$picture_html}
+
+