Merge pull request #3 from RSS-Bridge/master

123
This commit is contained in:
Ruslan 2018-01-28 13:07:30 +04:00 committed by GitHub
commit 43d02bac34
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 133 additions and 51 deletions

View File

@ -2,20 +2,6 @@ dist: trusty
sudo: false sudo: false
language: php language: php
before_install:
# Circumvent a bug in current Travis CI builds using Ubuntu Trusty, where the
# include_path is wrong.
#
# Default is:
# - include_path='.:/home/travis/.phpenv/versions/5.6.31/share/pear'
#
# Should be:
# - include_path='.:/home/travis/.phpenv/versions/5.6.31/lib/php/pear'
#
# This applies to all builds except hhvm and nightly. Once the distro is fixed
# the following line can be removed
- if [[ ${TRAVIS_PHP_VERSION:0:1} == "5" || ${TRAVIS_PHP_VERSION:0:1} == "7" ]]; then echo "include_path='.:/home/travis/.phpenv/versions/$(phpenv version-name)/lib/php/pear'" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini; fi
install: install:
- pear channel-update pear.php.net - pear channel-update pear.php.net
- pear install PHP_CodeSniffer - pear install PHP_CodeSniffer

View File

@ -7,23 +7,23 @@ rss-bridge is a PHP project capable of generating ATOM feeds for websites which
Supported sites/pages (main) Supported sites/pages (main)
=== ===
* `FlickrExplore` : [Latest interesting images](http://www.flickr.com/explore) from Flickr * `Bandcamp` : Returns last release from [bandcamp](https://bandcamp.com/) for a tag
* `GoogleSearch` : Most recent results from Google Search
* `GooglePlus` : Most recent posts of user timeline
* `Twitter` : Return keyword/hashtag search or user timeline
* `Identi.ca` : Identica user timeline (Should be compatible with other Pump.io instances)
* `YouTube` : YouTube user channel, playlist or search
* `Cryptome` : Returns the most recent documents from [Cryptome.org](http://cryptome.org/) * `Cryptome` : Returns the most recent documents from [Cryptome.org](http://cryptome.org/)
* `DansTonChat`: Most recent quotes from [danstonchat.com](http://danstonchat.com/) * `DansTonChat`: Most recent quotes from [danstonchat.com](http://danstonchat.com/)
* `DuckDuckGo`: Most recent results from [DuckDuckGo.com](https://duckduckgo.com/) * `DuckDuckGo`: Most recent results from [DuckDuckGo.com](https://duckduckgo.com/)
* `Facebook` : Returns the latest posts on a page or profile on [Facebook](https://facebook.com/)
* `FlickrExplore` : [Latest interesting images](http://www.flickr.com/explore) from Flickr
* `GooglePlus` : Most recent posts of user timeline
* `GoogleSearch` : Most recent results from Google Search
* `Identi.ca` : Identica user timeline (Should be compatible with other Pump.io instances)
* `Instagram`: Most recent photos from an Instagram user * `Instagram`: Most recent photos from an Instagram user
* `OpenClassrooms`: Lastest tutorials from [fr.openclassrooms.com](http://fr.openclassrooms.com/) * `OpenClassrooms`: Lastest tutorials from [fr.openclassrooms.com](http://fr.openclassrooms.com/)
* `Pinterest`: Most recent photos from user or search * `Pinterest`: Most recent photos from user or search
* `ScmbBridge`: Newest stories from [secouchermoinsbete.fr](http://secouchermoinsbete.fr/) * `ScmbBridge`: Newest stories from [secouchermoinsbete.fr](http://secouchermoinsbete.fr/)
* `Wikipedia`: highlighted articles from [Wikipedia](https://wikipedia.org/) in English, German, French or Esperanto
* `Bandcamp` : Returns last release from [bandcamp](https://bandcamp.com/) for a tag
* `ThePirateBay` : Returns the newest indexed torrents from [The Pirate Bay](https://thepiratebay.se/) with keywords * `ThePirateBay` : Returns the newest indexed torrents from [The Pirate Bay](https://thepiratebay.se/) with keywords
* `Facebook` : Returns the latest posts on a page or profile on [Facebook](https://facebook.com/) * `Twitter` : Return keyword/hashtag search or user timeline
* `Wikipedia`: highlighted articles from [Wikipedia](https://wikipedia.org/) in English, German, French or Esperanto
* `YouTube` : YouTube user channel, playlist or search
Plus [many other bridges](bridges/) to enable, thanks to the community Plus [many other bridges](bridges/) to enable, thanks to the community
@ -32,9 +32,9 @@ Output format
Output format can take several forms: Output format can take several forms:
* `Atom` : ATOM Feed, for use in RSS/Feed readers * `Atom` : ATOM Feed, for use in RSS/Feed readers
* `Mrss` : MRSS Feed, for use in RSS/Feed readers
* `Json` : Json, for consumption by other applications.
* `Html` : Simple html page. * `Html` : Simple html page.
* `Json` : Json, for consumption by other applications.
* `Mrss` : MRSS Feed, for use in RSS/Feed readers
* `Plaintext` : raw text (php object, as returned by print_r) * `Plaintext` : raw text (php object, as returned by print_r)
Screenshot Screenshot

View File

@ -0,0 +1,65 @@
<?php
class BloombergBridge extends BridgeAbstract
{
const NAME = 'Bloomberg';
const URI = 'https://www.bloomberg.com/';
const DESCRIPTION = 'Trending stories from Bloomberg';
const MAINTAINER = 'mdemoss';
const PARAMETERS = array(
'Trending Stories' => array(),
'From Search' => array(
'q' => array(
'name' => 'Keyword',
'required' => true
)
)
);
public function getName()
{
switch($this->queriedContext) {
case 'Trending Stories':
return self::NAME . ' Trending Stories';
case 'From Search':
if (!is_null($this->getInput('q'))) {
return self::NAME . ' Search : ' . $this->getInput('q');
}
break;
}
return parent::getName();
}
public function collectData()
{
switch($this->queriedContext) {
case 'Trending Stories': // Get list of top new <article>s from the front page.
$html = getSimpleHTMLDOMCached($this->getURI(), 300);
$stories = $html->find('ul.top-news-v3__stories article.top-news-v3-story');
break;
case 'From Search': // Get list of <article> elements from search.
$html = getSimpleHTMLDOMCached(
$this->getURI() .
'search?sort=time:desc&page=1&query=' .
urlencode($this->getInput('q')), 300
);
$stories = $html->find('div.search-result-items article.search-result-story');
break;
}
foreach ($stories as $element) {
$item['uri'] = $element->find('h1 a', 0)->href;
if (preg_match('#^https://#i', $item['uri']) !== 1) {
$item['uri'] = $this->getURI() . $item['uri'];
}
$articleHtml = getSimpleHTMLDOMCached($item['uri']);
if (!$articleHtml) {
continue;
}
$item['title'] = $element->find('h1 a', 0)->plaintext;
$item['timestamp'] = strtotime($articleHtml->find('meta[name=iso-8601-publish-date],meta[name=date]', 0)->content);
$item['content'] = $articleHtml->find('meta[name=description]', 0)->content;
$this->items[] = $item;
}
}
}

View File

@ -46,7 +46,7 @@ class FacebookBridge extends BridgeAbstract {
if(is_array($matches) && count($matches) > 1) { if(is_array($matches) && count($matches) > 1) {
$link = $matches[1]; $link = $matches[1];
if(strpos($link, '/') === 0) if(strpos($link, '/') === 0)
$link = self::URI . $link . '"'; $link = self::URI . $link;
if(strpos($link, 'facebook.com/l.php?u=') !== false) if(strpos($link, 'facebook.com/l.php?u=') !== false)
$link = urldecode(extractFromDelimiters($link, 'facebook.com/l.php?u=', '&')); $link = urldecode(extractFromDelimiters($link, 'facebook.com/l.php?u=', '&'));
return ' href="' . $link . '"'; return ' href="' . $link . '"';

View File

@ -42,10 +42,10 @@ class LegifranceJOBridge extends BridgeAbstract {
$html = getSimpleHTMLDOM(self::URI) $html = getSimpleHTMLDOM(self::URI)
or $this->returnServer('Unable to download ' . self::URI); or $this->returnServer('Unable to download ' . self::URI);
$this->author = trim($html->find('h2.title', 0)->plaintext); $this->author = trim($html->find('h2.titleJO', 0)->plaintext);
$uri = $html->find('h2.titleELI', 0)->plaintext; $uri = $html->find('h2.titleELI', 0)->plaintext;
$this->uri = trim(substr($uri, strpos($uri, 'https'))); $this->uri = trim(substr($uri, strpos($uri, 'https')));
$this->timestamp = strtotime(substr($this->uri, strpos($this->uri, 'eli/jo/') + strlen('eli/jo/'))); $this->timestamp = strtotime(substr($this->uri, strpos($this->uri, 'eli/jo/') + strlen('eli/jo/'), -5));
foreach($html->find('h3') as $section) { foreach($html->find('h3') as $section) {
$subsections = $section->nextSibling()->find('h4'); $subsections = $section->nextSibling()->find('h4');

View File

@ -4,7 +4,7 @@ class MixCloudBridge extends BridgeAbstract {
const MAINTAINER = 'Alexis CHEMEL'; const MAINTAINER = 'Alexis CHEMEL';
const NAME = 'MixCloud'; const NAME = 'MixCloud';
const URI = 'https://mixcloud.com/'; const URI = 'https://www.mixcloud.com';
const CACHE_TIMEOUT = 3600; // 1h const CACHE_TIMEOUT = 3600; // 1h
const DESCRIPTION = 'Returns latest musics on user stream'; const DESCRIPTION = 'Returns latest musics on user stream';
@ -24,8 +24,9 @@ class MixCloudBridge extends BridgeAbstract {
} }
public function collectData(){ public function collectData(){
ini_set('user_agent', 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:53.0) Gecko/20100101 Firefox/53.0');
$html = getSimpleHTMLDOM(self::URI . $this->getInput('u')) $html = getSimpleHTMLDOM(self::URI . '/' . $this->getInput('u'))
or returnServerError('Could not request MixCloud.'); or returnServerError('Could not request MixCloud.');
foreach($html->find('section.card') as $element) { foreach($html->find('section.card') as $element) {

23
bridges/PcGamerBridge.php Normal file
View File

@ -0,0 +1,23 @@
<?php
class PcGamerBridge extends BridgeAbstract
{
const NAME = 'PC Gamer';
const URI = 'https://www.pcgamer.com/';
const DESCRIPTION = 'PC Gamer Most Read Stories';
const MAINTAINER = 'mdemoss';
public function collectData()
{
$html = getSimpleHTMLDOMCached($this->getURI(), 300);
$stories = $html->find('div#popularcontent li.most-popular-item');
foreach ($stories as $element) {
$item['uri'] = $element->find('a', 0)->href;
$articleHtml = getSimpleHTMLDOMCached($item['uri']);
$item['title'] = $element->find('h4 a', 0)->plaintext;
$item['timestamp'] = strtotime($articleHtml->find('meta[name=pub_date]', 0)->content);
$item['content'] = $articleHtml->find('meta[name=description]', 0)->content;
$item['author'] = $articleHtml->find('a[itemprop=author]', 0)->plaintext;
$this->items[] = $item;
}
}
}

View File

@ -77,9 +77,7 @@ class TwitterBridge extends BridgeAbstract {
$param = 'u'; $param = 'u';
break; break;
case 'By list': case 'By list':
$specific = $this->getInput('user'); return $this->getInput('list') . ' - Twitter list by ' . $this->getInput('user');
$param = 'list';
break;
default: return parent::getName(); default: return parent::getName();
} }
return 'Twitter ' . $specific . $this->getInput($param); return 'Twitter ' . $specific . $this->getInput($param);
@ -165,7 +163,7 @@ class TwitterBridge extends BridgeAbstract {
switch($this->queriedContext) { switch($this->queriedContext) {
case 'By list': case 'By list':
// Check if filter applies to list (using raw content) // Check if filter applies to list (using raw content)
if(!is_null($this->getInput('filter'))) { if($this->getInput('filter')) {
if(stripos($tweet->find('p.js-tweet-text', 0)->plaintext, $this->getInput('filter')) === false) { if(stripos($tweet->find('p.js-tweet-text', 0)->plaintext, $this->getInput('filter')) === false) {
continue 2; // switch + for-loop! continue 2; // switch + for-loop!
} }

View File

@ -91,7 +91,7 @@ class YoutubeBridge extends BridgeAbstract {
if(strpos($vid, 'googleads') === false) if(strpos($vid, 'googleads') === false)
$this->ytBridgeAddItem($vid, $title, $author, $desc, $time); $this->ytBridgeAddItem($vid, $title, $author, $desc, $time);
} }
$this->request = $this->ytBridgeFixTitle($xml->find('feed > title', 0)->plaintext); $this->feedName = $this->ytBridgeFixTitle($xml->find('feed > title', 0)->plaintext); // feedName will be used by getName()
} }
private function ytBridgeParseHtmlListing($html, $element_selector, $title_selector){ private function ytBridgeParseHtmlListing($html, $element_selector, $title_selector){
@ -164,7 +164,7 @@ class YoutubeBridge extends BridgeAbstract {
$html = $this->ytGetSimpleHTMLDOM($url_listing) $html = $this->ytGetSimpleHTMLDOM($url_listing)
or returnServerError("Could not request YouTube. Tried:\n - $url_listing"); or returnServerError("Could not request YouTube. Tried:\n - $url_listing");
$this->ytBridgeParseHtmlListing($html, 'tr.pl-video', '.pl-video-title a'); $this->ytBridgeParseHtmlListing($html, 'tr.pl-video', '.pl-video-title a');
$this->request = 'Playlist: ' . str_replace(' - YouTube', '', $html->find('title', 0)->plaintext); $this->feedName = 'Playlist: ' . str_replace(' - YouTube', '', $html->find('title', 0)->plaintext); // feedName will be used by getName()
} elseif($this->getInput('s')) { /* search mode */ } elseif($this->getInput('s')) { /* search mode */
$this->request = $this->getInput('s'); $this->request = $this->getInput('s');
$page = 1; $page = 1;
@ -182,7 +182,7 @@ class YoutubeBridge extends BridgeAbstract {
or returnServerError("Could not request YouTube. Tried:\n - $url_listing"); or returnServerError("Could not request YouTube. Tried:\n - $url_listing");
$this->ytBridgeParseHtmlListing($html, 'div.yt-lockup', 'h3'); $this->ytBridgeParseHtmlListing($html, 'div.yt-lockup', 'h3');
$this->request = 'Search: ' . str_replace(' - YouTube', '', $html->find('title', 0)->plaintext); $this->feedName = 'Search: ' . str_replace(' - YouTube', '', $html->find('title', 0)->plaintext); // feedName will be used by getName()
} else { /* no valid mode */ } else { /* no valid mode */
returnClientError("You must either specify either:\n - YouTube returnClientError("You must either specify either:\n - YouTube
username (?u=...)\n - Channel id (?c=...)\n - Playlist id (?p=...)\n - Search (?s=...)"); username (?u=...)\n - Channel id (?c=...)\n - Playlist id (?p=...)\n - Search (?s=...)");
@ -190,6 +190,15 @@ class YoutubeBridge extends BridgeAbstract {
} }
public function getName(){ public function getName(){
return (!empty($this->request) ? $this->request . ' - ' : '') . 'YouTube Bridge'; // Name depends on queriedContext:
switch($this->queriedContext) {
case 'By username':
case 'By channel id':
case 'By playlist Id':
case 'Search result':
return $this->feedName . ' - YouTube'; // We already know it's a bridge, right?
default:
return parent::getName();
}
} }
} }