diff --git a/.travis.yml b/.travis.yml index 794fdbf8..cd5e2d9a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,20 +2,6 @@ dist: trusty sudo: false 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: - pear channel-update pear.php.net - pear install PHP_CodeSniffer @@ -35,4 +21,4 @@ matrix: allow_failures: - php: hhvm - - php: nightly \ No newline at end of file + - php: nightly diff --git a/README.md b/README.md index e36f22b2..45bbc6d9 100644 --- a/README.md +++ b/README.md @@ -7,23 +7,23 @@ rss-bridge is a PHP project capable of generating ATOM feeds for websites which Supported sites/pages (main) === - * `FlickrExplore` : [Latest interesting images](http://www.flickr.com/explore) from Flickr - * `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/) - * `DansTonChat`: Most recent quotes from [danstonchat.com](http://danstonchat.com/) - * `DuckDuckGo`: Most recent results from [DuckDuckGo.com](https://duckduckgo.com/) - * `Instagram`: Most recent photos from an Instagram user - * `OpenClassrooms`: Lastest tutorials from [fr.openclassrooms.com](http://fr.openclassrooms.com/) - * `Pinterest`: Most recent photos from user or search - * `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 - * `Facebook` : Returns the latest posts on a page or profile on [Facebook](https://facebook.com/) +* `Bandcamp` : Returns last release from [bandcamp](https://bandcamp.com/) for a tag +* `Cryptome` : Returns the most recent documents from [Cryptome.org](http://cryptome.org/) +* `DansTonChat`: Most recent quotes from [danstonchat.com](http://danstonchat.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 +* `OpenClassrooms`: Lastest tutorials from [fr.openclassrooms.com](http://fr.openclassrooms.com/) +* `Pinterest`: Most recent photos from user or search +* `ScmbBridge`: Newest stories from [secouchermoinsbete.fr](http://secouchermoinsbete.fr/) +* `ThePirateBay` : Returns the newest indexed torrents from [The Pirate Bay](https://thepiratebay.se/) with keywords +* `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 @@ -31,11 +31,11 @@ Output format === Output format can take several forms: - * `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. - * `Plaintext` : raw text (php object, as returned by print_r) +* `Atom` : ATOM Feed, for use in RSS/Feed readers +* `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) Screenshot === diff --git a/bridges/BloombergBridge.php b/bridges/BloombergBridge.php new file mode 100644 index 00000000..8aff0ec7 --- /dev/null +++ b/bridges/BloombergBridge.php @@ -0,0 +1,65 @@ + 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
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
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; + } + } +} diff --git a/bridges/FacebookBridge.php b/bridges/FacebookBridge.php index d2f8b915..90f3d74c 100644 --- a/bridges/FacebookBridge.php +++ b/bridges/FacebookBridge.php @@ -46,7 +46,7 @@ class FacebookBridge extends BridgeAbstract { if(is_array($matches) && count($matches) > 1) { $link = $matches[1]; if(strpos($link, '/') === 0) - $link = self::URI . $link . '"'; + $link = self::URI . $link; if(strpos($link, 'facebook.com/l.php?u=') !== false) $link = urldecode(extractFromDelimiters($link, 'facebook.com/l.php?u=', '&')); return ' href="' . $link . '"'; diff --git a/bridges/LegifranceJOBridge.php b/bridges/LegifranceJOBridge.php index 348be8f1..d97fcff9 100644 --- a/bridges/LegifranceJOBridge.php +++ b/bridges/LegifranceJOBridge.php @@ -42,10 +42,10 @@ class LegifranceJOBridge extends BridgeAbstract { $html = getSimpleHTMLDOM(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; $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) { $subsections = $section->nextSibling()->find('h4'); diff --git a/bridges/MixCloudBridge.php b/bridges/MixCloudBridge.php index aa6340a1..723f634a 100644 --- a/bridges/MixCloudBridge.php +++ b/bridges/MixCloudBridge.php @@ -4,7 +4,7 @@ class MixCloudBridge extends BridgeAbstract { const MAINTAINER = 'Alexis CHEMEL'; const NAME = 'MixCloud'; - const URI = 'https://mixcloud.com/'; + const URI = 'https://www.mixcloud.com'; const CACHE_TIMEOUT = 3600; // 1h const DESCRIPTION = 'Returns latest musics on user stream'; @@ -24,8 +24,9 @@ class MixCloudBridge extends BridgeAbstract { } 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.'); foreach($html->find('section.card') as $element) { diff --git a/bridges/PcGamerBridge.php b/bridges/PcGamerBridge.php new file mode 100644 index 00000000..e0e55ce4 --- /dev/null +++ b/bridges/PcGamerBridge.php @@ -0,0 +1,23 @@ +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; + } + } +} diff --git a/bridges/TwitterBridge.php b/bridges/TwitterBridge.php index 66024cee..aedb3723 100644 --- a/bridges/TwitterBridge.php +++ b/bridges/TwitterBridge.php @@ -77,9 +77,7 @@ class TwitterBridge extends BridgeAbstract { $param = 'u'; break; case 'By list': - $specific = $this->getInput('user'); - $param = 'list'; - break; + return $this->getInput('list') . ' - Twitter list by ' . $this->getInput('user'); default: return parent::getName(); } return 'Twitter ' . $specific . $this->getInput($param); @@ -165,7 +163,7 @@ class TwitterBridge extends BridgeAbstract { switch($this->queriedContext) { case 'By list': // 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) { continue 2; // switch + for-loop! } diff --git a/bridges/YoutubeBridge.php b/bridges/YoutubeBridge.php index 1db07352..3d81daeb 100644 --- a/bridges/YoutubeBridge.php +++ b/bridges/YoutubeBridge.php @@ -91,7 +91,7 @@ class YoutubeBridge extends BridgeAbstract { if(strpos($vid, 'googleads') === false) $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){ @@ -164,7 +164,7 @@ class YoutubeBridge extends BridgeAbstract { $html = $this->ytGetSimpleHTMLDOM($url_listing) or returnServerError("Could not request YouTube. Tried:\n - $url_listing"); $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 */ $this->request = $this->getInput('s'); $page = 1; @@ -182,7 +182,7 @@ class YoutubeBridge extends BridgeAbstract { or returnServerError("Could not request YouTube. Tried:\n - $url_listing"); $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 */ returnClientError("You must either specify either:\n - YouTube username (?u=...)\n - Channel id (?c=...)\n - Playlist id (?p=...)\n - Search (?s=...)"); @@ -190,6 +190,15 @@ class YoutubeBridge extends BridgeAbstract { } 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(); + } + } }