pax_global_header00006660000000000000000000000064131406703170014514gustar00rootroot0000000000000052 comment=f7265ca77b17844f159fc4b9c1ac7087f42bc0b1 rss-bridge-2017-08-03/000077500000000000000000000000001314067031700141555ustar00rootroot00000000000000rss-bridge-2017-08-03/.gitattributes000066400000000000000000000007431314067031700170540ustar00rootroot00000000000000# Auto detect text files and perform LF normalization * text=auto # Custom for Visual Studio *.cs diff=csharp *.sln merge=union *.csproj merge=union *.vbproj merge=union *.fsproj merge=union *.dbproj merge=union # Standard to msysgit *.doc diff=astextplain *.DOC diff=astextplain *.docx diff=astextplain *.DOCX diff=astextplain *.dot diff=astextplain *.DOT diff=astextplain *.pdf diff=astextplain *.PDF diff=astextplain *.rtf diff=astextplain *.RTF diff=astextplain rss-bridge-2017-08-03/.gitignore000066400000000000000000000055011314067031700161460ustar00rootroot00000000000000################# ## Eclipse ################# vendor/* data/ *.pydevproject .project .metadata bin/ tmp/ *.tmp *.bak *.swp *~.nib local.properties .classpath .settings/ .loadpath # External tool builders .externalToolBuilders/ # Locally stored "Eclipse launch configurations" *.launch # CDT-specific .cproject # PDT-specific .buildpath ################# ## Visual Studio ################# ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. # User-specific files *.suo *.user *.sln.docstates # Build results [Dd]ebug/ [Rr]elease/ x64/ build/ [Bb]in/ [Oo]bj/ # MSTest test Results [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* *_i.c *_p.c *.ilk *.meta *.obj *.pch *.pdb *.pgc *.pgd *.rsp *.sbr *.tlb *.tli *.tlh *.tmp *.tmp_proj *.log *.vspscc *.vssscc .builds *.pidb *.log *.scc # Visual C++ cache files ipch/ *.aps *.ncb *.opensdf *.sdf *.cachefile # Visual Studio profiler *.psess *.vsp *.vspx # Guidance Automation Toolkit *.gpState # ReSharper is a .NET coding add-in _ReSharper*/ *.[Rr]e[Ss]harper # TeamCity is a build add-in _TeamCity* # DotCover is a Code Coverage Tool *.dotCover # NCrunch *.ncrunch* .*crunch*.local.xml # Installshield output folder [Ee]xpress/ # DocProject is a documentation generator add-in DocProject/buildhelp/ DocProject/Help/*.HxT DocProject/Help/*.HxC DocProject/Help/*.hhc DocProject/Help/*.hhk DocProject/Help/*.hhp DocProject/Help/Html2 DocProject/Help/html # Click-Once directory publish/ # Publish Web Output *.Publish.xml *.pubxml # NuGet Packages Directory ## TODO: If you have NuGet Package Restore enabled, uncomment the next line #packages/ # Windows Azure Build Output csx *.build.csdef # Windows Store app package directory AppPackages/ # Others sql/ *.Cache ClientBin/ [Ss]tyle[Cc]op.* ~$* *~ *.dbmdl *.[Pp]ublish.xml *.pfx *.publishsettings # RIA/Silverlight projects Generated_Code/ # Backup & report files from converting an old project file to a newer # Visual Studio version. Backup files are not needed, because we have git ;-) _UpgradeReport_Files/ Backup*/ UpgradeLog*.XML UpgradeLog*.htm # SQL Server files App_Data/*.mdf App_Data/*.ldf ################# ## Other ide stuff ################# .idea/* [#]*[#] ############# ## Windows detritus ############# # Windows image file caches Thumbs.db ehthumbs.db # Folder config file Desktop.ini # Recycle Bin used on file shares $RECYCLE.BIN/ # Mac crap .DS_Store ############# ## Python ############# *.py[co] # Packages *.egg *.egg-info dist/ build/ eggs/ parts/ var/ sdist/ develop-eggs/ .installed.cfg # Installer logs pip-log.txt # Unit test / coverage reports .coverage .tox #Translations *.mo #Mr Developer .mr.developer.cfg ############## ## RSS-Bridge ############## /cache /whitelist.txt DEBUG ###################### ## VisualStudioCode ## ###################### .vscode/*rss-bridge-2017-08-03/.travis.yml000066400000000000000000000004351314067031700162700ustar00rootroot00000000000000language: php php: - '5.6' - '7.0' - hhvm - nightly install: - pear install PHP_CodeSniffer script: - phpenv rehash - phpcs . --standard=phpcs.xml --warning-severity=0 --extensions=php -p matrix: fast_finish: true allow_failures: - php: hhvm - php: nightlyrss-bridge-2017-08-03/CHANGELOG.md000066400000000000000000000145541314067031700157770ustar00rootroot00000000000000rss-bridge Changelog === RSS-Bridge 2017-08-03 == ## Important changes RSS-Bridge now has [contribution guidelines](CONTRIBUTING.md) [phpcs rules](phpcs.xml) follow the [contribution guidelines](CONTRIBUTING.md) ## General changes Added a search bar to make searching for bridges easier Added user friendly error page for when a bridge fails Added caching of extraInfos (name, uri) Added an indicator to warn for bridges using HTTP instead of HTTPS Various bug fixes and improvements ## Modified bridges [AllocineFRBridge] Update Faux Raccord link [DanbooruBridge] Fix broken URI [DuckDuckGoBridge] Disable DuckDuckGo redirects so that the links returned are correct. [FacebookBridge] Add option to hide posts with facebook videos [FacebookBridge] Add requester languages to HTTP header [FacebookBridge] Handle summary posts [FacebookBridge] Replace 'novideo' with 'media_type' [FilterBridge] Initial implementation of basic title permit and block [FlickrTagBridge] Fix and improve bridge by using the FlickrExploreBridge approach [GooglePlusPostBridge] Autofix user names [GooglePlusPostBridge] Fix bridge implementation [GooglePlusPostBridge] Fix content loading [InstagramBridge] Add option to filter for videos and pictures [LWNprevBridge] full rewrite [MangareaderBridge] Fix double forward slashes [NasaApodBridge] Use HTTPS instead of HTTP [PinterestBridge] Fix checkbox not working [PinterestBridge] Fix implementation after DOM changes [RTBFBridge] Update URI [SexactuBridge] Fix URI and timestamp [SexactuBridge] Use most modern version of bridge api and cached pages (#504) [ShanaprojectBridge] Don't throw error if timestamp is missing [TwitterBridge] Add option to hide retweets [TwitterBridge] Avoid empty content caused by new login policy [TwitterBridge] Fix double slashes in URI [TwitterBridge] Fix missing spaces [TwitterBridge] Fix title includes anchors in plaintext format [TwitterBridge] ignore promoted tweets [TwitterBridge] Optimize returned image sizes [TwitterBridge] Show quotes and pictures [WebfailBridge] Properly handle gifs (DOM changed) [YoutubeBridge] Improve readability of feed contents [YoutubeBridge] Improve URL handling in video descriptions ## New bridges AmazonBridge DiceBridge EtsyBridge FB2Bridge FilterBridge FlickrBridge GithubSearchBridge GoComicsBridge KATBridge KernelBugTrackerBridge MixCloudBridge MoinMoinBridge RainbowSixSiegeBridge SteamBridge TheTVDBBridge Torrent9Bridge UsbekEtRicaBridge WikiLeaksBridge WordPressPluginUpdateBridge Alpha 0.2 === ## Important changes * RSS-Bridge has been [UNLICENSED](UNLICENSE) * RSS-Bridge is now a community-managed project on [GitHub](https://github.com/rss-bridge/rss-bridge) * RSS-Bridge now has a [Wiki](https://github.com/rss-bridge/rss-bridge/wiki) * RSS-Bridge now supports [Travis-CI](https://travis-ci.org) ## General changes * Added [CHANGELOG](CHANGELOG.md) (this file) * Added [PHP Simple HTML DOM Parser](http://simplehtmldom.sourceforge.net) to [vendor](vendor/simplehtmldom/) * Added cache purging function (cache will be force-purged after 24 hours or as defined by bridge) * Added new format [MrssFormat](formats/MrssFormat.php) * Added parameter `author` - for display of the feed author name - to all formats * Added new abstraction of the BridgeInterface: - [FeedExpander](https://github.com/RSS-Bridge/rss-bridge/wiki/Bridge-API) * Added optional support for proxy usage on each individual bridge * Added support for [custom bridge parameter](https://github.com/RSS-Bridge/rss-bridge/wiki/BridgeAbstract#format-specifications) (text, number, list, checkbox) * Changed design of the welcome screen * Changed design of HtmlFormat * Changed behavior of debug mode: - Enable debug mode by placing a file called "DEBUG" in the root folder - Debug mode automatically disables cache file loading * Changed implementation of bridges - see [Wiki](https://github.com/rss-bridge/rss-bridge/wiki) - Changed comment-style metadata to constants - Added support for multiple utilizations per bridge - Changed the parameter loading algorithm to be loaded by RSS-Bridge core * Improved checks for PHP version, configuration and extensions * Many bug fixes ## Modified Bridges * FlickrExploreBridge * GoogleSearchBridge * TwitterBridge ## New Bridges * ABCTabsBridge * AcrimedBridge * AllocineFRBridge * AnimeUltimeBridge * Arte7Bridge * AskfmBridge * BandcampBridge * BastaBridge * BlaguesDeMerdeBridge * BooruprojectBridge * CADBridge * CNETBridge * CastorusBridge * CollegeDeFranceBridge * CommonDreamsBridge * CopieDoubleBridge * CourrierInternationalBridge * CpasbienBridge * CryptomeBridge * DailymotionBridge * DanbooruBridge * DansTonChatBridge * DauphineLibereBridge * DemoBridge * DeveloppezDotComBridge * DilbertBridge * DollbooruBridge * DuckDuckGoBridge * EZTVBridge * EliteDangerousGalnetBridge * ElsevierBridge * EstCeQuonMetEnProdBridge * FacebookBridge * FierPandaBridge * FlickrTagBridge * FootitoBridge * FourchanBridge * FuturaSciencesBridge * GBAtempBridge * GelbooruBridge * GiphyBridge * GithubIssueBridge * GizmodoBridge * GooglePlusPostBridge * HDWallpapersBridge * HentaiHavenBridge * IdenticaBridge * InstagramBridge * IsoHuntBridge * JapanExpoBridge * KonachanBridge * KoreusBridge * KununuBridge * LWNprevBridge * LeBonCoinBridge * LegifranceJOBridge * LeMondeInformatiqueBridge * LesJoiesDuCodeBridge * LichessBridge * LinkedInCompanyBridge * LolibooruBridge * MangareaderBridge * MilbooruBridge * MoebooruBridge * MondeDiploBridge * MsnMondeBridge * MspabooruBridge * NasaApodBridge * NeuviemeArtBridge * NextInpactBridge * NextgovBridge * NiceMatinBridge * NovelUpdatesBridge * OpenClassroomsBridge * ParuVenduImmoBridge * PickyWallpapersBridge * PinterestBridge * PlanetLibreBridge * RTBFBridge * ReadComicsBridge * Releases3DSBridge * ReporterreBridge * Rue89Bridge * Rule34Bridge * Rule34pahealBridge * SafebooruBridge * SakugabooruBridge * ScmbBridge * ScoopItBridge * SensCritiqueBridge * SexactuBridge * ShanaprojectBridge * Shimmie2Bridge * SoundcloudBridge * StripeAPIChangeLogBridge * SuperbWallpapersBridge * T411Bridge * TagBoardBridge * TbibBridge * TheCodingLoveBridge * TheHackerNewsBridge * ThePirateBayBridge * UnsplashBridge * ViadeoCompanyBridge * VineBridge * VkBridge * WallpaperStopBridge * WebfailBridge * WeLiveSecurityBridge * WhydBridge * WikipediaBridge * WordPressBridge * WorldOfTanksBridge * XbooruBridge * YandereBridge * YoutubeBridge * ZDNetBridge Alpha 0.1 === * First tagged version. * Includes refactoring. * Unstable.rss-bridge-2017-08-03/CONTRIBUTING.md000066400000000000000000000027271314067031700164160ustar00rootroot00000000000000### Pull request policy Fix one issue per pull request. Squash commits before opening a pull request. Respect the coding style policy. Name your PR like the following : * When correcting a single bridge, use `[BridgeName] Feature`. * When fixing a problem in a specific file, use `[FileName] Feature`. * When fixing a general problem, use `category : feature`. Note that all pull-requests should pass the unit tests before they can be merged. ### Coding style Use `camelCase` for variables and methods. Use `UPPERCASE` for constants. Use `PascalCase` for class names. When creating a bridge, your class and PHP file should be named `MyImplementationBridge`. Use tabs for indentation. Add an empty line at the end of your file. Use `''` to encapsulate strings, including in arrays. Prefer lines shorter than 80 chars, no line longer than 120 chars. PHP constants should be in lower case (`true, false, null`...) * Add spaces between the logical operator and your expressions (not needed for the `!` operator). * Use `||` and `&&` instead of `or` and `and`. * Add space between your condition and the opening bracket/closing bracket. * Don't put a space between `if` and your bracket. * Use `elseif` instead of `else if`. * Add new lines in your conditions if they are containing more than one line. * Example : ```PHP if($a == true && $b) { print($a); } else if(!$b) { $a = !$a; $b = $b >> $a; print($b); } else { print($b); } ``` rss-bridge-2017-08-03/README.md000066400000000000000000000160021314067031700154330ustar00rootroot00000000000000rss-bridge === [![LICENSE](https://img.shields.io/badge/license-UNLICENSE-blue.svg)](UNLICENSE) [![Build Status](https://travis-ci.org/RSS-Bridge/rss-bridge.svg?branch=master)](https://travis-ci.org/RSS-Bridge/rss-bridge) rss-bridge is a PHP project capable of generating ATOM feeds for websites which don't have one. 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/) Plus [many other bridges](bridges/) to enable, thanks to the community 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) Screenshot === Welcome screen: ![Screenshot](https://github.com/RSS-Bridge/rss-bridge/wiki/images/screenshot_rss-bridge_welcome.png) RSS-Bridge hashtag (#rss-bridge) search on Twitter, in ATOM format (as displayed by Firefox): ![Screenshot](https://github.com/RSS-Bridge/rss-bridge/wiki/images/screenshot_twitterbridge_atom.png) Requirements === * PHP 5.6, e.g. `AddHandler application/x-httpd-php56 .php` in `.htaccess` * `openssl` extension enabled in PHP config (`php.ini`) * `allow_url_fopen=1` in `php.ini` Enabling/Disabling bridges === By default, the script creates `whitelist.txt` and adds the main bridges (see above). `whitelist.txt` is ignored by git, you can edit it: * to enable extra bridges (one bridge per line) * to disable main bridges (remove the line) * to enable all bridges (just one wildcard `*` as file content) New bridges are disabled by default, so make sure to check regularly what's new and whitelist what you want! Deploy === [![Deploy on Scalingo](https://cdn.scalingo.com/deploy/button.svg)](https://my.scalingo.com/deploy?source=https://github.com/sebsauvage/rss-bridge) Authors === We are RSS Bridge Community, a group of developers continuing the project initiated by sebsauvage, webmaster of [sebsauvage.net](http://sebsauvage.net), author of [Shaarli](http://sebsauvage.net/wiki/doku.php?id=php:shaarli) and [ZeroBin](http://sebsauvage.net/wiki/doku.php?id=php:zerobin). Patch/contributors : * Yves ASTIER ([Draeli](https://github.com/Draeli)) : PHP optimizations, fixes, dynamic brigde/format list with all stuff behind and extend cache system. Mail : contact /at\ yves-astier.com * [Mitsukarenai](https://github.com/Mitsukarenai) : Initial inspiration, collaborator * [ArthurHoaro](https://github.com/ArthurHoaro) * [BoboTiG](https://github.com/BoboTiG) * [Astalaseven](https://github.com/Astalaseven) * [qwertygc](https://github.com/qwertygc) * [Djuuu](https://github.com/Djuuu) * [Anadrark](https://github.com/Anadrark]) * [Grummfy](https://github.com/Grummfy) * [Polopollo](https://github.com/Polopollo) * [16mhz](https://github.com/16mhz) * [kranack](https://github.com/kranack) * [logmanoriginal](https://github.com/logmanoriginal) * [polo2ro](https://github.com/polo2ro) * [Riduidel](https://github.com/Riduidel) * [superbaillot.net](http://superbaillot.net/) * [vinzv](https://github.com/vinzv) * [teromene](https://github.com/teromene) * [nel50n](https://github.com/nel50n) * [nyutag](https://github.com/nyutag) * [ORelio](https://github.com/ORelio) * [Pitchoule](https://github.com/Pitchoule) * [pit-fgfjiudghdf](https://github.com/pit-fgfjiudghdf) * [aledeg](https://github.com/aledeg) * [alexAubin](https://github.com/alexAubin) * [cnlpete](https://github.com/cnlpete) * [corenting](https://github.com/corenting) * [Daiyousei](https://github.com/Daiyousei) * [erwang](https://github.com/erwang) * [gsurrel](https://github.com/gsurrel) * [kraoc](https://github.com/kraoc) * [lagaisse](https://github.com/lagaisse) * [az5he6ch](https://github.com/az5he6ch) * [niawag](https://github.com/niawag) * [JeremyRand](https://github.com/JeremyRand) * [mro](https://github.com/mro) Licenses === Code is [Public Domain](UNLICENSE). Including `PHP Simple HTML DOM Parser` under the [MIT License](http://opensource.org/licenses/MIT) Technical notes === * There is a cache so that source services won't ban you even if you hammer the rss-bridge with requests. Each bridge can have a different duration for the cache. The `cache` subdirectory will be automatically created and cached objects older than 24 hours get purged. * To implement a new Bridge, [follow the specifications](https://github.com/RSS-Bridge/rss-bridge/wiki/Bridge-API) and take a look at existing Bridges for examples. * To enable debug mode (disabling cache and enabling error reporting), create an empty file named `DEBUG` in the root directory (next to `index.php`). * For more information refer to the [Wiki](https://github.com/RSS-Bridge/rss-bridge/wiki) Rant === *Dear so-called "social" websites.* Your catchword is "share", but you don't want us to share. You want to keep us within your walled gardens. That's why you've been removing RSS links from webpages, hiding them deep on your website, or removed feeds entirely, replacing it with crippled or demented proprietary API. **FUCK YOU.** You're not social when you hamper sharing by removing feeds. You're happy to have customers creating content for your ecosystem, but you don't want this content out - a content you do not even own. Google Takeout is just a gimmick. We want our data to flow, we want RSS or ATOM feeds. We want to share with friends, using open protocols: RSS, ATOM, XMPP, whatever. Because no one wants to have *your* service with *your* applications using *your* API force-feeding them. Friends must be free to choose whatever software and service they want. We are rebuilding bridges you have wilfully destroyed. Get your shit together: Put RSS/ATOM back in. rss-bridge-2017-08-03/UNLICENSE000066400000000000000000000022731314067031700154310ustar00rootroot00000000000000This is free and unencumbered software released into the public domain. Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means. In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. For more information, please refer to rss-bridge-2017-08-03/bridges/000077500000000000000000000000001314067031700155745ustar00rootroot00000000000000rss-bridge-2017-08-03/bridges/ABCTabsBridge.php000066400000000000000000000021051314067031700206170ustar00rootroot00000000000000find('table#myTable', 0)->children(1); foreach ($table->find('tr') as $tab) { $item = array(); $item['author'] = $tab->find('td', 1)->plaintext . ' - ' . $tab->find('td', 2)->plaintext; $item['title'] = $tab->find('td', 1)->plaintext . ' - ' . $tab->find('td', 2)->plaintext; $item['content'] = 'Le ' . $tab->find('td', 0)->plaintext . '
Par: ' . $tab->find('td', 5)->plaintext . '
Type: ' . $tab->find('td', 3)->plaintext; $item['id'] = static::URI . $tab->find('td', 2)->find('a', 0)->getAttribute('href'); $item['uri'] = static::URI . $tab->find('td', 2)->find('a', 0)->getAttribute('href'); $this->items[] = $item; } } } rss-bridge-2017-08-03/bridges/AcrimedBridge.php000066400000000000000000000012361314067031700207700ustar00rootroot00000000000000collectExpandableDatas(static::URI . 'spip.php?page=backend'); } protected function parseItem($newsItem){ $item = parent::parseItem($newsItem); $articlePage = getSimpleHTMLDOM($newsItem->link); $article = sanitize($articlePage->find('article.article1', 0)->innertext); $article = defaultLinkTo($article, static::URI); $item['content'] = $article; return $item; } } rss-bridge-2017-08-03/bridges/AllocineFRBridge.php000066400000000000000000000044371314067031700214100ustar00rootroot00000000000000 array( 'name' => 'category', 'type' => 'list', 'required' => true, 'exampleValue' => 'Faux Raccord', 'title' => 'Select your category', 'values' => array( 'Faux Raccord' => 'faux-raccord', 'Top 5' => 'top-5', 'Tueurs en Séries' => 'tueurs-en-serie' ) ) )); public function getURI(){ if(!is_null($this->getInput('category'))) { switch($this->getInput('category')) { case 'faux-raccord': $uri = static::URI . 'video/programme-12284/saison-29841/'; break; case 'top-5': $uri = static::URI . 'video/programme-12299/saison-29561/'; break; case 'tueurs-en-serie': $uri = static::URI . 'video/programme-12286/saison-22938/'; break; } return $uri; } return parent::getURI(); } public function getName(){ if(!is_null($this->getInput('category'))) { return self::NAME . ' : ' .array_search( $this->getInput('category'), self::PARAMETERS[$this->queriedContext]['category']['values'] ); } return parent::getName(); } public function collectData(){ $html = getSimpleHTMLDOM($this->getURI()) or returnServerError('Could not request ' . $this->getURI() . ' !'); $category = array_search( $this->getInput('category'), self::PARAMETERS[$this->queriedContext]['category']['values'] ); foreach($html->find('figure.media-meta-fig') as $element) { $item = array(); $title = $element->find('div.titlebar h3.title a', 0); $content = trim($element->innertext); $figCaption = strpos($content, $category); if($figCaption !== false) { $content = str_replace('src="/', 'src="' . static::URI, $content); $content = str_replace('href="/', 'href="' . static::URI, $content); $content = str_replace('src=\'/', 'src=\'' . static::URI, $content); $content = str_replace('href=\'/', 'href=\'' . static::URI, $content); $item['content'] = $content; $item['title'] = trim($title->innertext); $item['uri'] = static::URI . $title->href; $this->items[] = $item; } } } } rss-bridge-2017-08-03/bridges/AmazonBridge.php000066400000000000000000000044641314067031700206570ustar00rootroot00000000000000 array( 'name' => 'Keyword', 'required' => true, ), 'sort' => array( 'name' => 'Sort by', 'type' => 'list', 'required' => false, 'values' => array( 'Relevance' => 'relevanceblender', 'Price: Low to High' => 'price-asc-rank', 'Price: High to Low' => 'price-desc-rank', 'Average Customer Review' => 'review-rank', 'Newest Arrivals' => 'date-desc-rank', ), 'defaultValue' => 'relevanceblender', ), 'tld' => array( 'name' => 'Country', 'type' => 'list', 'required' => true, 'values' => array( 'Australia' => 'com.au', 'Brazil' => 'com.br', 'Canada' => 'ca', 'China' => 'cn', 'France' => 'fr', 'Germany' => 'de', 'India' => 'in', 'Italy' => 'it', 'Japan' => 'co.jp', 'Mexico' => 'com.mx', 'Netherlands' => 'nl', 'Spain' => 'es', 'United Kingdom' => 'co.uk', 'United States' => 'com', ), 'defaultValue' => 'com', ), )); public function getName(){ if(!is_null($this->getInput('tld')) && !is_null($this->getInput('q'))) { return 'Amazon.'.$this->getInput('tld').': '.$this->getInput('q'); } return parent::getName(); } public function collectData() { $uri = 'https://www.amazon.'.$this->getInput('tld').'/'; $uri .= 's/?field-keywords='.urlencode($this->getInput('q')).'&sort='.$this->getInput('sort'); $html = getSimpleHTMLDOM($uri) or returnServerError('Could not request Amazon.'); foreach($html->find('li.s-result-item') as $element) { $item = array(); // Title $title = $element->find('h2', 0); $item['title'] = html_entity_decode($title->innertext, ENT_QUOTES); // Url $uri = $title->parent()->getAttribute('href'); $uri = substr($uri, 0, strrpos($uri, '/')); $item['uri'] = substr($uri, 0, strrpos($uri, '/')); // Content $image = $element->find('img', 0); $price = $element->find('span.s-price', 0); $price = ($price) ? $price->innertext : ''; $item['content'] = '
'.$price; $this->items[] = $item; } } } rss-bridge-2017-08-03/bridges/AnimeUltimeBridge.php000066400000000000000000000100711314067031700216320ustar00rootroot00000000000000 array( 'name' => 'Type', 'type' => 'list', 'values' => array( 'Everything' => '', 'Anime' => 'A', 'Drama' => 'D', 'Tokusatsu' => 'T' ) ) )); private $filter = 'Releases'; public function collectData(){ //Add type filter if provided $typeFilter = array_search( $this->getInput('type'), self::PARAMETERS[$this->queriedContext]['type']['values'] ); //Build date and filters for making requests $thismonth = date('mY') . $typeFilter; $lastmonth = date('mY', mktime(0, 0, 0, date('n') - 1, 1, date('Y'))) . $typeFilter; //Process each HTML page until having 10 releases $processedOK = 0; foreach (array($thismonth, $lastmonth) as $requestFilter) { //Retrive page contents $url = self::URI . 'history-0-1/' . $requestFilter; $html = getSimpleHTMLDOM($url) or returnServerError('Could not request Anime-Ultime: ' . $url); //Relases are sorted by day : process each day individually foreach($html->find('div.history', 0)->find('h3') as $daySection) { //Retrieve day and build date information $dateString = $daySection->plaintext; $day = intval(substr($dateString, strpos($dateString, ' ') + 1, 2)); $item_date = strtotime(str_pad($day, 2, '0', STR_PAD_LEFT) . '-' . substr($requestFilter, 0, 2) . '-' . substr($requestFilter, 2, 4)); //

day


<-- useful data in table rows $release = $daySection->next_sibling()->next_sibling()->first_child(); //Process each release of that day, ignoring first table row: contains table headers while(!is_null($release = $release->next_sibling())) { if(count($release->find('td')) > 0) { //Retrieve metadata from table columns $item_link_element = $release->find('td', 0)->find('a', 0); $item_uri = self::URI . $item_link_element->href; $item_name = html_entity_decode($item_link_element->plaintext); $item_episode = html_entity_decode( str_pad( $release->find('td', 1)->plaintext, 2, '0', STR_PAD_LEFT ) ); $item_fansub = $release->find('td', 2)->plaintext; $item_type = $release->find('td', 4)->plaintext; if(!empty($item_uri)) { // Retrieve description from description page and // convert relative image src info absolute image src $html_item = getContents($item_uri) or returnServerError('Could not request Anime-Ultime: ' . $item_uri); $item_description = substr( $html_item, strpos($html_item, 'class="principal_contain" align="center">') + 41 ); $item_description = substr($item_description, 0, strpos($item_description, '
') ); $item_description = str_replace( 'src="images', 'src="' . self::URI . 'images', $item_description ); $item_description = str_replace("\r", '', $item_description); $item_description = str_replace("\n", '', $item_description); $item_description = utf8_encode($item_description); //Build and add final item $item = array(); $item['uri'] = $item_uri; $item['title'] = $item_name . ' ' . $item_type . ' ' . $item_episode; $item['author'] = $item_fansub; $item['timestamp'] = $item_date; $item['content'] = $item_description; $this->items[] = $item; $processedOK++; //Stop processing once limit is reached if ($processedOK >= 10) return; } } } } } } public function getName() { if(!is_null($this->getInput('type'))) { $typeFilter = array_search( $this->getInput('type'), self::PARAMETERS[$this->queriedContext]['type']['values'] ); return 'Latest ' . $typeFilter . ' - Anime-Ultime Bridge'; } return parent::getName(); } } rss-bridge-2017-08-03/bridges/Arte7Bridge.php000066400000000000000000000056121314067031700204100ustar00rootroot00000000000000 array( 'catfr' => array( 'type' => 'list', 'name' => 'Catégorie', 'values' => array( 'Toutes les vidéos (français)' => 'toutes-les-videos', 'Actu & société' => 'actu-société', 'Séries & fiction' => 'séries-fiction', 'Cinéma' => 'cinéma', 'Arts & spectacles classiques' => 'arts-spectacles-classiques', 'Culture pop' => 'culture-pop', 'Découverte' => 'découverte', 'Histoire' => 'histoire', 'Junior' => 'junior' ) ) ), 'Catégorie (Allemand)' => array( 'catde' => array( 'type' => 'list', 'name' => 'Catégorie', 'values' => array( 'Alle Videos (deutsch)' => 'alle-videos', 'Aktuelles & Gesellschaft' => 'aktuelles-gesellschaft', 'Fernsehfilme & Serien' => 'fernsehfilme-serien', 'Kino' => 'kino', 'Kunst & Kultur' => 'kunst-kultur', 'Popkultur & Alternativ' => 'popkultur-alternativ', 'Entdeckung' => 'entdeckung', 'Geschichte' => 'geschichte', 'Junior' => 'junior' ) ) ) ); public function collectData(){ switch($this->queriedContext) { case 'Catégorie (Français)': $category = $this->getInput('catfr'); $lang = 'fr'; break; case 'Catégorie (Allemand)': $category = $this->getInput('catde'); $lang = 'de'; break; } $url = self::URI . 'guide/' . $lang . '/plus7/' . $category; $input = getContents($url) or die('Could not request ARTE.'); if(strpos($input, 'categoryVideoSet') !== false) { $input = explode('categoryVideoSet="', $input); $input = explode('}}', $input[1]); $input = $input[0] . '}}'; } else { $input = explode('videoSet="', $input); $input = explode('}]}', $input[1]); $input = $input[0] . '}]}'; } $input_json = json_decode(html_entity_decode($input, ENT_QUOTES), true); foreach($input_json['videos'] as $element) { $item = array(); $item['uri'] = str_replace("autoplay=1", "", $element['url']); $item['id'] = $element['id']; $hack_broadcast_time = $element['rights_end']; $hack_broadcast_time = strtok($hack_broadcast_time, 'T'); $hack_broadcast_time = strtok('T'); $item['timestamp'] = strtotime($element['scheduled_on'] . 'T' . $hack_broadcast_time); $item['title'] = $element['title']; if(!empty($element['subtitle'])) $item['title'] = $element['title'] . ' | ' . $element['subtitle']; $item['duration'] = round((int)$element['duration'] / 60); $item['content'] = $element['teaser'] . '

' . $item['duration'] . 'min
'; $this->items[] = $item; } } } rss-bridge-2017-08-03/bridges/AskfmBridge.php000066400000000000000000000042521314067031700204660ustar00rootroot00000000000000 array( 'u' => array( 'name' => 'Username', 'required' => true ) ) ); public function collectData(){ $html = getSimpleHTMLDOM($this->getURI()) or returnServerError('Requested username can\'t be found.'); foreach($html->find('div.streamItem-answer') as $element) { $item = array(); $item['uri'] = self::URI . $element->find('a.streamItemsAge', 0)->href; $question = trim($element->find('h1.streamItemContent-question', 0)->innertext); $item['title'] = trim( htmlspecialchars_decode($element->find('h1.streamItemContent-question', 0)->plaintext, ENT_QUOTES ) ); $answer = trim($element->find('p.streamItemContent-answer', 0)->innertext); // Doesn't work, DOM parser doesn't seem to like data-hint, dunno why #$item['update'] = $element->find('a.streamitemsage',0)->data-hint; // This probably should be cleaned up, especially for YouTube embeds $visual = $element->find('div.streamItemContent-visual', 0)->innertext; //Fix tracking links, also doesn't work foreach($element->find('a') as $link) { if(strpos($link->href, 'l.ask.fm') !== false) { // Too slow #$link->href = str_replace('#_=_', '', get_headers($link->href, 1)['Location']); $link->href = $link->plaintext; } } $content = '

' . $question . '

' . $answer . '

' . $visual . '

'; // Fix relative links without breaking // scheme used by YouTube stuff $content = preg_replace('#href="\/(?!\/)#', 'href="' . self::URI, $content); $item['content'] = $content; $this->items[] = $item; } } public function getName(){ if(!is_null($this->getInput('u'))) { return self::NAME . ' : ' . $this->getInput('u'); } return parent::getName(); } public function getURI(){ if(!is_null($this->getInput('u'))) { return self::URI . urlencode($this->getInput('u')) . '/answers/more?page=0'; } return parent::getURI(); } } rss-bridge-2017-08-03/bridges/BandcampBridge.php000066400000000000000000000031771314067031700211370ustar00rootroot00000000000000 array( 'name' => 'tag', 'type' => 'text', 'required' => true ) )); public function collectData(){ $html = getSimpleHTMLDOM($this->getURI()) or returnServerError('No results for this query.'); foreach($html->find('li.item') as $release) { $script = $release->find('div.art', 0)->getAttribute('onclick'); $uri = ltrim($script, "return 'url("); $uri = rtrim($uri, "')"); $item = array(); $item['author'] = $release->find('div.itemsubtext', 0)->plaintext . ' - ' . $release->find('div.itemtext', 0)->plaintext; $item['title'] = $release->find('div.itemsubtext', 0)->plaintext . ' - ' . $release->find('div.itemtext', 0)->plaintext; $item['content'] = '
' . $release->find('div.itemsubtext', 0)->plaintext . ' - ' . $release->find('div.itemtext', 0)->plaintext; $item['id'] = $release->find('a', 0)->getAttribute('href'); $item['uri'] = $release->find('a', 0)->getAttribute('href'); $this->items[] = $item; } } public function getURI(){ if(!is_null($this->getInput('tag'))) { return self::URI . 'tag/' . urlencode($this->getInput('tag')) . '?sort_field=date'; } return parent::getURI(); } public function getName(){ if(!is_null($this->getInput('tag'))) { return $this->getInput('tag') . ' - Bandcamp Tag'; } return parent::getName(); } } rss-bridge-2017-08-03/bridges/BastaBridge.php000066400000000000000000000021101314067031700204460ustar00rootroot00000000000000find('item') as $element) { if($limit < 10) { $item = array(); $item['title'] = $element->find('title', 0)->innertext; $item['uri'] = $element->find('guid', 0)->plaintext; $item['timestamp'] = strtotime($element->find('dc:date', 0)->plaintext); $item['content'] = replaceImageUrl(getSimpleHTMLDOM($item['uri'])->find('div.texte', 0)->innertext); $this->items[] = $item; $limit++; } } } } rss-bridge-2017-08-03/bridges/BlaguesDeMerdeBridge.php000066400000000000000000000017601314067031700222360ustar00rootroot00000000000000find('article.joke_contener') as $element) { $item = array(); $temp = $element->find('a'); if(isset($temp[2])) { $item['content'] = trim($element->find('div.joke_text_contener', 0)->innertext); $uri = $temp[2]->href; $item['uri'] = $uri; $item['title'] = substr($uri, (strrpos($uri, "/") + 1)); $date = $element->find('li.bdm_date', 0)->innertext; $time = mktime(0, 0, 0, substr($date, 3, 2), substr($date, 0, 2), substr($date, 6, 4)); $item['timestamp'] = $time; $item['author'] = $element->find('li.bdm_pseudo', 0)->innertext; $this->items[] = $item; } } } } rss-bridge-2017-08-03/bridges/BooruprojectBridge.php000066400000000000000000000016121314067031700220770ustar00rootroot00000000000000 array( 'p' => array( 'name' => 'page', 'type' => 'number' ), 't' => array( 'name' => 'tags' ) ), 'Booru subdomain (subdomain.booru.org)' => array( 'i' => array( 'name' => 'Subdomain', 'required' => true ) ) ); const PIDBYPAGE = 20; public function getURI(){ if(!is_null($this->getInput('i'))) { return 'http://' . $this->getInput('i') . '.booru.org/'; } return parent::getURI(); } public function getName(){ if(!is_null($this->getInput('i'))) { return static::NAME . ' ' . $this->getInput('i'); } return parent::getName(); } } rss-bridge-2017-08-03/bridges/CADBridge.php000066400000000000000000000023461314067031700200160ustar00rootroot00000000000000collectExpandableDatas('http://cdn2.cad-comic.com/rss.xml', 10); } protected function parseItem($newsItem){ $item = parent::parseItem($newsItem); $item['content'] = $this->extractCADContent($item['uri']); return $item; } private function extractCADContent($url) { $html3 = getSimpleHTMLDOMCached($url); // The request might fail due to missing https support or wrong URL if($html3 == false) return 'Daily comic not released yet'; $htmlpart = explode("/", $url); switch ($htmlpart[3]) { case 'cad': preg_match_all("/http:\/\/cdn2\.cad-comic\.com\/comics\/cad-\S*png/", $html3, $url2); break; case 'sillies': preg_match_all("/http:\/\/cdn2\.cad-comic\.com\/comics\/sillies-\S*gif/", $html3, $url2); break; default: return 'Daily comic not released yet'; } $img = implode($url2[0]); $html3->clear(); unset($html3); if ($img == '') return 'Daily comic not released yet'; return ''; } } rss-bridge-2017-08-03/bridges/CNETBridge.php000066400000000000000000000061271314067031700201610ustar00rootroot00000000000000 You may specify a topic found in some section URLs, else all topics are selected.'; const PARAMETERS = array( array( 'topic' => array( 'name' => 'Topic name' ) )); public function collectData(){ function extractFromDelimiters($string, $start, $end){ if(strpos($string, $start) !== false) { $section_retrieved = substr($string, strpos($string, $start) + strlen($start)); $section_retrieved = substr($section_retrieved, 0, strpos($section_retrieved, $end)); return $section_retrieved; } return false; } function stripWithDelimiters($string, $start, $end){ while(strpos($string, $start) !== false) { $section_to_remove = substr($string, strpos($string, $start)); $section_to_remove = substr($section_to_remove, 0, strpos($section_to_remove, $end) + strlen($end)); $string = str_replace($section_to_remove, '', $string); } return $string; } function cleanArticle($article_html){ $article_html = '

' . substr($article_html, strpos($article_html, '

') + 3); $article_html = stripWithDelimiters($article_html, '', ''); $article_html = stripWithDelimiters($article_html, ''); $article_html = stripWithDelimiters($article_html, '

'); //strip thead $html = stristr($html, ''); //remove tbody $html = str_get_html(stristr($html, '', true)); //remove last tbody and get back as an array foreach($html->find('tr') as $element) { $item = array(); $item['uri'] = $element->find('td', 2)->find('a', 0)->href; $item['title'] = $element->find('td', 2)->find('a', 0)->plaintext; $item['team'] = $element->find('td', 1)->innertext; $item['timestamp'] = strtotime($element->find('td', 0)->plaintext); $item['content'] = '' . $this->seriesTitle . ' - ' . $item['title'] . ' by ' . $item['team'] . '
' . $fullhtml->find('div.seriesimg', 0)->innertext . ''; $this->items[] = $item; } } public function getName(){ if(!empty($this->seriesTitle)) { return $this->seriesTitle . ' - ' . static::NAME; } return parent::getName(); } } rss-bridge-2017-08-03/bridges/OpenClassroomsBridge.php000066400000000000000000000025471314067031700224010ustar00rootroot00000000000000 array( 'name' => 'Catégorie', 'type' => 'list', 'required' => true, 'values' => array( 'Arts & Culture' => 'arts', 'Code' => 'code', 'Design' => 'design', 'Entreprise' => 'business', 'Numérique' => 'digital', 'Sciences' => 'sciences', 'Sciences Humaines' => 'humainities', 'Systèmes d\'information' => 'it', 'Autres' => 'others' ) ) )); public function getURI(){ if(!is_null($this->getInput('u'))) { return self::URI . '/courses?categories=' . $this->getInput('u') . '&title=&sort=updatedAt+desc'; } return parent::getURI(); } public function collectData(){ $html = getSimpleHTMLDOM($this->getURI()) or returnServerError('Could not request OpenClassrooms.'); foreach($html->find('.courseListItem') as $element) { $item = array(); $item['uri'] = self::URI . $element->find('a', 0)->href; $item['title'] = $element->find('h3', 0)->plaintext; $item['content'] = $element->find('slidingItem__descriptionContent', 0)->plaintext; $this->items[] = $item; } } } rss-bridge-2017-08-03/bridges/ParuVenduImmoBridge.php000066400000000000000000000047041314067031700221620ustar00rootroot00000000000000 array( 'name' => 'Minimal surface m²', 'type' => 'number' ), 'maxprice' => array( 'name' => 'Max price', 'type' => 'number' ), 'pa' => array( 'name' => 'Country code', 'exampleValue' => 'FR' ), 'lo' => array( 'name' => 'department numbers or postal codes, comma-separated' ) )); public function collectData(){ $html = getSimpleHTMLDOM($this->getURI()) or returnServerError('Could not request paruvendu.'); foreach($html->find('div.annonce a') as $element) { if(!$element->title) { continue; } $img = ''; foreach($element->find('span.img img') as $img) { if($img->original) { $img = ''; } } $desc = $element->find('span.desc')[0]->innertext; $desc = str_replace("voir l'annonce", '', $desc); $price = $element->find('span.price')[0]->innertext; list($href) = explode('#', $element->href); $item = array(); $item['uri'] = self::URI . $href; $item['title'] = $element->title; $item['content'] = $img . $desc . $price; $this->items[] = $item; } } public function getURI(){ $appartment = '&tbApp=1&tbDup=1&tbChb=1&tbLof=1&tbAtl=1&tbPla=1'; $maison = '&tbMai=1&tbVil=1&tbCha=1&tbPro=1&tbHot=1&tbMou=1&tbFer=1'; $link = self::URI . '/immobilier/annonceimmofo/liste/listeAnnonces?tt=1' . $appartment . $maison; if($this->getInput('minarea')) { $link .= '&sur0=' . urlencode($this->getInput('minarea')); } if($this->getInput('maxprice')) { $link .= '&px1=' . urlencode($this->getInput('maxprice')); } if($this->getInput('pa')) { $link .= '&pa=' . urlencode($this->getInput('pa')); } if($this->getInput('lo')) { $link .= '&lo=' . urlencode($this->getInput('lo')); } return $link; } public function getName(){ if(!is_null($this->getInput('minarea'))) { $request = ''; $minarea = $this->getInput('minarea'); if(!empty($minarea)) { $request .= ' ' . $minarea . ' m2'; } $location = $this->getInput('lo'); if(!empty($location)) { $request .= ' In: ' . $location; } return 'Paru Vendu Immobilier' . $request; } return parent::getName(); } } rss-bridge-2017-08-03/bridges/PickyWallpapersBridge.php000066400000000000000000000044451314067031700225430ustar00rootroot00000000000000 array( 'name' => 'category', 'required' => true ), 's' => array( 'name' => 'subcategory' ), 'm' => array( 'name' => 'Max number of wallpapers', 'defaultValue' => 12, 'type' => 'number' ), 'r' => array( 'name' => 'resolution', 'exampleValue' => '1920x1200, 1680x1050,…', 'defaultValue' => '1920x1200', 'pattern' => '[0-9]{3,4}x[0-9]{3,4}' ) )); public function collectData(){ $lastpage = 1; $num = 0; $max = $this->getInput('m'); $resolution = $this->getInput('r'); // Wide wallpaper default for($page = 1; $page <= $lastpage; $page++) { $html = getSimpleHTMLDOM($this->getURI() . '/page-' . $page . '/') or returnServerError('No results for this query.'); if($page === 1) { preg_match('/page-(\d+)\/$/', $html->find('.pages li a', -2)->href, $matches); $lastpage = min($matches[1], ceil($max / 12)); } foreach($html->find('.items li img') as $element) { $item = array(); $item['uri'] = str_replace('www', 'wallpaper', self::URI) . '/' . $resolution . '/' . basename($element->src); $item['timestamp'] = time(); $item['title'] = $element->alt; $item['content'] = $item['title'] . '
' . $element . ''; $this->items[] = $item; $num++; if ($num >= $max) break 2; } } } public function getURI(){ if(!is_null($this->getInput('s')) && !is_null($this->getInput('r')) && !is_null($this->getInput('c'))) { $subcategory = $this->getInput('s'); $link = self::URI . $this->getInput('r') . '/' . $this->getInput('c') . '/' . $subcategory; return $link; } return parent::getURI(); } public function getName(){ if(!is_null($this->getInput('s'))) { $subcategory = $this->getInput('s'); return 'PickyWallpapers - ' . $this->getInput('c') . ($subcategory ? ' > ' . $subcategory : '') . ' [' . $this->getInput('r') . ']'; } return parent::getName(); } } rss-bridge-2017-08-03/bridges/PinterestBridge.php000066400000000000000000000113221314067031700213760ustar00rootroot00000000000000 array( 'u' => array( 'name' => 'username', 'required' => true ), 'b' => array( 'name' => 'board', 'required' => true ), 'r' => array( 'name' => 'Use custom RSS', 'type' => 'checkbox', 'required' => false, 'title' => 'Uncheck to return data via custom filters (more data)' ) ), 'From search' => array( 'q' => array( 'name' => 'Keyword', 'required' => true ) ) ); public function collectData(){ switch($this->queriedContext) { case 'By username and board': if($this->getInput('r')) { $html = getSimpleHTMLDOMCached($this->getURI()); $this->getUserResults($html); } else { $this->collectExpandableDatas($this->getURI() . '.rss'); } break; case 'From search': default: $html = getSimpleHTMLDOMCached($this->getURI()); $this->getSearchResults($html); } } private function getUserResults($html){ $json = json_decode($html->find('#jsInit1', 0)->innertext, true); $results = $json['tree']['children'][0]['children'][0]['children'][0]['options']['props']['data']['board_feed']; $username = $json['resourceDataCache'][0]['data']['owner']['username']; $fullname = $json['resourceDataCache'][0]['data']['owner']['full_name']; $avatar = $json['resourceDataCache'][0]['data']['owner']['image_small_url']; foreach($results as $result) { $item = array(); $item['uri'] = $result['link']; // Some use regular titles, others provide 'advanced' infos, a few // provide even less info. Thus we attempt multiple options. $item['title'] = trim($result['title']); if($item['title'] === "") $item['title'] = trim($result['rich_summary']['display_name']); if($item['title'] === "") $item['title'] = trim($result['description']); $item['timestamp'] = strtotime($result['created_at']); $item['username'] = $username; $item['fullname'] = $fullname; $item['avatar'] = $avatar; $item['author'] = $item['username'] . ' (' . $item['fullname'] . ')'; $item['content'] = '

' . $item['username'] . '
' . $item['fullname'] . '



' . $result['description'] . '

'; $item['enclosures'] = array($result['images']['orig']['url']); $this->items[] = $item; } } private function getSearchResults($html){ $json = json_decode($html->find('#jsInit1', 0)->innertext, true); $results = $json['resourceDataCache'][0]['data']['results']; foreach($results as $result) { $item = array(); $item['uri'] = self::URI . $result['board']['url']; // Some use regular titles, others provide 'advanced' infos, a few // provide even less info. Thus we attempt multiple options. $item['title'] = trim($result['title']); if($item['title'] === "") $item['title'] = trim($result['rich_summary']['display_name']); if($item['title'] === "") $item['title'] = trim($result['grid_description']); $item['timestamp'] = strtotime($result['created_at']); $item['username'] = $result['pinner']['username']; $item['fullname'] = $result['pinner']['full_name']; $item['avatar'] = $result['pinner']['image_small_url']; $item['author'] = $item['username'] . ' (' . $item['fullname'] . ')'; $item['content'] = '

' . $item['username'] . '
' . $item['fullname'] . '



' . $result['description'] . '

'; $item['enclosures'] = array($result['images']['orig']['url']); $this->items[] = $item; } } public function getURI(){ switch($this->queriedContext) { case 'By username and board': $uri = self::URI . '/' . urlencode($this->getInput('u')) . '/' . urlencode($this->getInput('b'));// . '.rss'; break; case 'From search': $uri = self::URI . '/search/?q=' . urlencode($this->getInput('q')); break; default: return parent::getURI(); } return $uri; } public function getName(){ switch($this->queriedContext) { case 'By username and board': $specific = $this->getInput('u') . ' - ' . $this->getInput('b'); break; case 'From search': $specific = $this->getInput('q'); break; default: return parent::getName(); } return $specific . ' - ' . self::NAME; } } rss-bridge-2017-08-03/bridges/PlanetLibreBridge.php000066400000000000000000000017671314067031700216360ustar00rootroot00000000000000find('div[class="post-text"]', 0)->innertext; return $text; } public function collectData(){ $html = getSimpleHTMLDOM(self::URI) or returnServerError('Could not request PlanetLibre.'); $limit = 0; foreach($html->find('div.post') as $element) { if($limit < 5) { $item = array(); $item['title'] = $element->find('h1', 0)->plaintext; $item['uri'] = $element->find('a', 0)->href; $item['timestamp'] = strtotime( str_replace( '/', '-', $element->find('div[class="post-date"]', 0)->plaintext ) ); $item['content'] = $this->extractContent($item['uri']); $this->items[] = $item; $limit++; } } } } rss-bridge-2017-08-03/bridges/RTBFBridge.php000066400000000000000000000033501314067031700201600ustar00rootroot00000000000000 array( 'name' => 'series id', 'exampleValue' => 9500, 'required' => true ) )); public function collectData(){ $html = ''; $limit = 10; $count = 0; $html = getSimpleHTMLDOM($this->getURI()) or returnServerError('Could not request RTBF.'); foreach($html->find('section[id!=widget-ml-avoiraussi-] .rtbf-media-grid article') as $element) { if($count >= $limit) { break; } $item = array(); $item['id'] = $element->getAttribute('data-id'); $item['uri'] = self::URI . 'detail?id=' . $item['id']; $thumbnailUriSrcSet = explode( ',', $element->find('figure .www-img-16by9 img', 0)->getAttribute('data-srcset') ); $thumbnailUriLastSrc = end($thumbnailUriSrcSet); $thumbnailUri = explode(' ', $thumbnailUriLastSrc)[0]; $item['title'] = trim($element->find('h3', 0)->plaintext) . ' - ' . trim($element->find('h4', 0)->plaintext); $item['timestamp'] = strtotime($element->find('time', 0)->getAttribute('datetime')); $item['content'] = ''; $this->items[] = $item; $count++; } } public function getURI(){ if(!is_null($this->getInput('c'))) { return self::URI . 'emissions/detail?id=' . $this->getInput('c'); } return parent::getURI() . 'emissions/'; } public function getName(){ if(!is_null($this->getInput('c'))) { return $this->getInput('c') .' - RTBF Bridge'; } return parent::getName(); } } rss-bridge-2017-08-03/bridges/RainbowSixSiegeBridge.php000066400000000000000000000025321314067031700224660ustar00rootroot00000000000000find('h3 a', 0)->href; $uri = 'https://rainbow6.ubisoft.com' . $uri; $item['uri'] = $uri; $item['title'] = $article->find('h3', 0)->plaintext; $item['content'] = $article->find('img', 0)->outertext . '
' . $article->find('strong', 0)->plaintext; $item['timestamp'] = strtotime($article->find('p.news_date', 0)->plaintext); $this->items[] = $item; } } } rss-bridge-2017-08-03/bridges/ReadComicsBridge.php000066400000000000000000000025461314067031700214420ustar00rootroot00000000000000 array( 'name' => 'keywords, separated by semicolons', 'exampleValue' => 'first list;second list;...', 'required' => true ), )); public function collectData(){ function parseDateTimestamp($element){ $guessedDate = $element->find('span', 0)->plaintext; $guessedDate = strptime($guessedDate, '%m/%d/%Y'); $timestamp = mktime(0, 0, 0, $guessedDate['tm_mon'] + 1, $guessedDate['tm_mday'], date('Y')); return $timestamp; } $keywordsList = explode(";", $this->getInput('q')); foreach($keywordsList as $keywords) { $html = $this->getSimpleHTMLDOM(self::URI . 'comic/' . rawurlencode($keywords)) or $this->returnServerError('Could not request readcomics.tv.'); foreach($html->find('li') as $element) { $item = array(); $item['uri'] = $element->find('a.ch-name', 0)->href; $item['id'] = $item['uri']; $item['timestamp'] = parseDateTimestamp($element); $item['title'] = $element->find('a.ch-name', 0)->plaintext; if(isset($item['title'])) $this->items[] = $item; } } } } rss-bridge-2017-08-03/bridges/Releases3DSBridge.php000066400000000000000000000117411314067031700215030ustar00rootroot00000000000000', $xml)) as $element) { if($limit >= 5) { break; } if(strpos($element, '') === false) { continue; } $releasename = extractFromDelimiters($element, '', ''); if(empty($releasename)) { continue; } $id = extractFromDelimiters($element, '', ''); $name = extractFromDelimiters($element, '', ''); $publisher = extractFromDelimiters($element, '', ''); $region = extractFromDelimiters($element, '', ''); $group = extractFromDelimiters($element, '', ''); $imagesize = extractFromDelimiters($element, '', ''); $serial = extractFromDelimiters($element, '', ''); $titleid = extractFromDelimiters($element, '', ''); $imgcrc = extractFromDelimiters($element, '', ''); $filename = extractFromDelimiters($element, '', ''); $trimmedsize = extractFromDelimiters($element, '', ''); $firmware = extractFromDelimiters($element, '', ''); $type = extractFromDelimiters($element, '', ''); $card = extractFromDelimiters($element, '', ''); //Retrieve cover art and short desc from IGN? $ignResult = false; $ignDescription = ''; $ignLink = ''; $ignDate = time(); $ignCoverArt = ''; $ignSearchUrl = 'http://www.ign.com/search?q=' . urlencode($name); if($ignResult = getSimpleHTMLDOM($ignSearchUrl)) { $ignCoverArt = $ignResult->find('div.search-item-media', 0)->find('img', 0)->src; $ignDesc = $ignResult->find('div.search-item-description', 0)->plaintext; $ignLink = $ignResult->find('div.search-item-sub-title', 0)->find('a', 1)->href; $ignDate = strtotime(trim($ignResult->find('span.publish-date', 0)->plaintext)); $ignDescription = '
' . $ignDesc . ' More at IGN
'; } //Main section : Release description from 3DS database $releaseDescription = '

Release Details

Release ID: ' . $id . '
Game Name: ' . $name . '
Publisher: ' . $publisher . '
Region: ' . $region . '
Group: ' . $group . '
Image size: ' . (intval($imagesize) / 8) . 'MB
Serial: ' . $serial . '
Title ID: ' . $titleid . '
Image CRC: ' . $imgcrc . '
File Name: ' . $filename . '
Release Name: ' . $releasename . '
Trimmed size: ' . intval(intval($trimmedsize) / 1048576) . 'MB
Firmware: ' . $firmware . '
Type: ' . typeToString($type) . '
Card: ' . cardToString($card) . '
'; //Build search links section to facilitate release search using search engines $releaseNameEncoded = urlencode(str_replace(' ', '+', $releasename)); $searchLinkGoogle = 'https://google.com/?q=' . $releaseNameEncoded; $searchLinkDuckDuckGo = 'https://duckduckgo.com/?q=' . $releaseNameEncoded; $searchLinkQwant = 'https://lite.qwant.com/?q=' . $releaseNameEncoded . '&t=web'; $releaseSearchLinks = '

Search this release

'; //Build and add final item with the above three sections $item = array(); $item['title'] = $name; $item['author'] = $publisher; $item['timestamp'] = $ignDate; $item['uri'] = empty($ignLink) ? $searchLinkDuckDuckGo : $ignLink; $item['content'] = $ignDescription . $releaseDescription . $releaseSearchLinks; $this->items[] = $item; $limit++; } } } rss-bridge-2017-08-03/bridges/ReporterreBridge.php000066400000000000000000000024071314067031700215560ustar00rootroot00000000000000find('div[style=text-align:justify]') as $e) { $text = $e->outertext; } $html2->clear(); unset($html2); // Replace all relative urls with absolute ones $text = preg_replace( '/(href|src)(\=[\"\'])(?!http)([^"\']+)/ims', "$1$2" . self::URI . "$3", $text ); $text = strip_tags($text, '


'); return $text; } public function collectData(){ $html = getSimpleHTMLDOM(self::URI . 'spip.php?page=backend') or returnServerError('Could not request Reporterre.'); $limit = 0; foreach($html->find('item') as $element) { if($limit < 5) { $item = array(); $item['title'] = html_entity_decode($element->find('title', 0)->plaintext); $item['timestamp'] = strtotime($element->find('dc:date', 0)->plaintext); $item['uri'] = $element->find('guid', 0)->innertext; $item['content'] = html_entity_decode($this->extractContent($item['uri'])); $this->items[] = $item; $limit++; } } } } rss-bridge-2017-08-03/bridges/Rue89Bridge.php000066400000000000000000000012201314067031700203310ustar00rootroot00000000000000collectExpandableDatas('http://api.rue89.nouvelobs.com/feed'); } } rss-bridge-2017-08-03/bridges/Rule34Bridge.php000066400000000000000000000004101314067031700204730ustar00rootroot00000000000000find('article') as $article) { $item = array(); $item['uri'] = self::URI . $article->find('p.summary a', 0)->href; $item['title'] = $article->find('header h1 a', 0)->innertext; // remove text "En savoir plus" from anecdote content $article->find('span.read-more', 0)->outertext = ''; $content = $article->find('p.summary a', 0)->innertext; // remove superfluous spaces at the end $content = substr($content, 0, strlen($content) - 17); // get publication date $str_date = $article->find('time', 0)->datetime; list($date, $time) = explode(' ', $str_date); list($y, $m, $d) = explode('-', $date); list($h, $i) = explode(':', $time); $timestamp = mktime($h, $i, 0, $m, $d, $y); $item['timestamp'] = $timestamp; $item['content'] = $content; $this->items[] = $item; } } } rss-bridge-2017-08-03/bridges/ScoopItBridge.php000066400000000000000000000020221314067031700207760ustar00rootroot00000000000000 array( 'name' => 'keyword', 'required' => true ) )); public function collectData(){ $this->request = $this->getInput('u'); $link = self::URI . 'search?q=' . urlencode($this->getInput('u')); $html = getSimpleHTMLDOM($link) or returnServerError('Could not request ScoopIt. for : ' . $link); foreach($html->find('div.post-view') as $element) { $item = array(); $item['uri'] = $element->find('a', 0)->href; $item['title'] = preg_replace( '~[[:cntrl:]]~', '', $element->find('div.tCustomization_post_title', 0)->plaintext ); $item['content'] = preg_replace( '~[[:cntrl:]]~', '', $element->find('div.tCustomization_post_description', 0)->plaintext ); $this->items[] = $item; } } } rss-bridge-2017-08-03/bridges/SensCritiqueBridge.php000066400000000000000000000046511314067031700220460ustar00rootroot00000000000000 array( 'name' => 'Movies', 'type' => 'checkbox' ), 's' => array( 'name' => 'Series', 'type' => 'checkbox' ), 'g' => array( 'name' => 'Video Games', 'type' => 'checkbox' ), 'b' => array( 'name' => 'Books', 'type' => 'checkbox' ), 'bd' => array( 'name' => 'BD', 'type' => 'checkbox' ), 'mu' => array( 'name' => 'Music', 'type' => 'checkbox' ) )); public function collectData(){ $categories = array(); foreach(self::PARAMETERS[$this->queriedContext] as $category => $properties) { if($this->getInput($category)) { $uri = self::URI; switch($category) { case 'm': $uri .= 'films/cette-semaine'; break; case 's': $uri .= 'series/actualite'; break; case 'g': $uri .= 'jeuxvideo/actualite'; break; case 'b': $uri .= 'livres/actualite'; break; case 'bd': $uri .= 'bd/actualite'; break; case 'mu': $uri .= 'musique/actualite'; break; } $html = getSimpleHTMLDOM($uri) or returnServerError('No results for this query.'); $list = $html->find('ul.elpr-list', 0); $this->extractDataFromList($list); } } } private function extractDataFromList($list){ if($list === null) { returnClientError('Cannot extract data from list'); } foreach($list->find('li') as $movie) { $item = array(); $item['author'] = htmlspecialchars_decode($movie->find('.elco-title a', 0)->plaintext, ENT_QUOTES) . ' ' . $movie->find('.elco-date', 0)->plaintext; $item['title'] = $movie->find('.elco-title a', 0)->plaintext . ' ' . $movie->find('.elco-date', 0)->plaintext; $item['content'] = '' . $movie->find('.elco-original-title', 0)->plaintext . '

' . $movie->find('.elco-baseline', 0)->plaintext . '
' . $movie->find('.elco-baseline', 1)->plaintext . '

' . $movie->find('.elco-description', 0)->plaintext . '

' . trim($movie->find('.erra-ratings .erra-global', 0)->plaintext) . ' / 10'; $item['id'] = $this->getURI() . $movie->find('.elco-title a', 0)->href; $item['uri'] = $this->getURI() . $movie->find('.elco-title a', 0)->href; $this->items[] = $item; } } } rss-bridge-2017-08-03/bridges/SexactuBridge.php000066400000000000000000000046071314067031700210450ustar00rootroot00000000000000 'href', 'src' => 'src', 'data-original' => 'src' ); public function getURI(){ return self::URI . '/sexactu'; } public function collectData(){ $html = getSimpleHTMLDOM($this->getURI()) or returnServerError('Could not request ' . $this->getURI()); $sexactu = $html->find('.container_sexactu', 0); $rowList = $sexactu->find('.row'); foreach($rowList as $row) { // only use first list as second one only contains pages numbers $title = $row->find('.title', 0); if($title) { $item = array(); $item['author'] = self::AUTHOR; $item['title'] = $title->plaintext; $urlAttribute = "data-href"; $uri = $title->$urlAttribute; if($uri === false) continue; if(substr($uri, 0, 1) === 'h') { // absolute uri $item['uri'] = $uri; } else if(substr($uri, 0, 1) === '/') { // domain relative url $item['uri'] = self::URI . $uri; } else { $item['uri'] = $this->getURI() . $uri; } $article = $this->loadFullArticle($item['uri']); $item['content'] = $this->replaceUriInHtmlElement($article->find('.article_content', 0)); $publicationDate = $article->find('time[itemprop=datePublished]', 0); $short_date = $publicationDate->datetime; $item['timestamp'] = strtotime($short_date); } else { // Sometimes we get rubbish, ignore. continue; } $this->items[] = $item; } } /** * Loads the full article and returns the contents * @param $uri The article URI * @return The article content */ private function loadFullArticle($uri){ $html = getSimpleHTMLDOMCached($uri); $content = $html->find('#article', 0); if($content) { return $content; } return null; } /** * Replaces all relative URIs with absolute ones * @param $element A simplehtmldom element * @return The $element->innertext with all URIs replaced */ private function replaceUriInHtmlElement($element){ $returned = $element->innertext; foreach (self::REPLACED_ATTRIBUTES as $initial => $final) { $returned = str_replace($initial . '="/', $final . '="' . self::URI . '/', $returned); } return $returned; } } rss-bridge-2017-08-03/bridges/ShanaprojectBridge.php000066400000000000000000000075231314067031700220520ustar00rootroot00000000000000getURI() . '/seasons'); if(!$html) returnServerError('Could not load \'seasons\' page!'); $season = $html->find('div.follows_menu/a', 1); if(!$season) returnServerError('Could not find \'Season Anime List\'!'); $html = getSimpleHTMLDOM($this->getURI() . $season->href); if(!$html) returnServerError( 'Could not load \'Season Anime List\' from \'' . $season->innertext . '\'!' ); return $html; } // Extracts the anime title private function extractAnimeTitle($anime){ $title = $anime->find('a', 0); if(!$title) returnServerError('Could not find anime title!'); return trim($title->innertext); } // Extracts the anime URI private function extractAnimeUri($anime){ $uri = $anime->find('a', 0); if(!$uri) returnServerError('Could not find anime URI!'); return $this->getURI() . $uri->href; } // Extracts the anime release date (timestamp) private function extractAnimeTimestamp($anime){ $timestamp = $anime->find('span.header_info_block', 1); if(!$timestamp) return null; return strtotime($timestamp->innertext); } // Extracts the anime studio name (author) private function extractAnimeAuthor($anime){ $author = $anime->find('span.header_info_block', 2); if(!$author) return; // Sometimes the studio is unknown, so leave empty return trim($author->innertext); } // Extracts the episode information (x of y released) private function extractAnimeEpisodeInformation($anime){ $episode = $anime->find('div.header_info_episode', 0); if(!$episode) returnServerError('Could not find anime episode information!'); return preg_replace('/\r|\n/', ' ', $episode->plaintext); } // Extracts the background image private function extractAnimeBackgroundImage($anime){ // Getting the picture is a little bit tricky as it is part of the style. // Luckily the style is part of the parent div :) if(preg_match("/url\(\/\/([^\)]+)\)/i", $anime->parent->style, $matches)) return $matches[1]; returnServerError('Could not extract background image!'); } // Builds an URI to search for a specific anime (subber is left empty) private function buildAnimeSearchUri($anime){ return $this->getURI() . '/search/?title=' . urlencode($this->extractAnimeTitle($anime)) . '&subber='; } // Builds the content string for a given anime private function buildAnimeContent($anime){ // We'll use a template string to place our contents return '
'
		. htmlspecialchars($this->extractAnimeTitle($anime))
		. '

' . $this->extractAnimeEpisodeInformation($anime) . '


Search episodes

'; } public function collectData(){ $html = $this->loadSeasonAnimeList(); $animes = $html->find('div.header_display_box_info'); if(!$animes) returnServerError('Could not find anime headers!'); foreach($animes as $anime) { $item = array(); $item['title'] = $this->extractAnimeTitle($anime); $item['author'] = $this->extractAnimeAuthor($anime); $item['uri'] = $this->extractAnimeUri($anime); $item['timestamp'] = $this->extractAnimeTimestamp($anime); $item['content'] = $this->buildAnimeContent($anime); $this->items[] = $item; } } } rss-bridge-2017-08-03/bridges/Shimmie2Bridge.php000066400000000000000000000017741314067031700211100ustar00rootroot00000000000000getURI() . 'post/list/' . $this->getInput('t') . '/' . $this->getInput('p'); } protected function getItemFromElement($element){ $item = array(); $item['uri'] = $this->getURI() . $element->href; $item['id'] = (int)preg_replace("/[^0-9]/", '', $element->getAttribute(static::IDATTRIBUTE)); $item['timestamp'] = time(); $thumbnailUri = $this->getURI() . $element->find('img', 0)->src; $item['tags'] = $element->getAttribute('data-tags'); $item['title'] = $this->getName() . ' | ' . $item['id']; $item['content'] = '
Tags: ' . $item['tags']; return $item; } } rss-bridge-2017-08-03/bridges/SoundcloudBridge.php000066400000000000000000000031701314067031700215420ustar00rootroot00000000000000 array( 'name' => 'username', 'required' => true ) )); const CLIENT_ID = '0aca19eae3843844e4053c6d8fdb7875'; public function collectData(){ $res = json_decode(getContents( 'https://api.soundcloud.com/resolve?url=http://www.soundcloud.com/' . urlencode($this->getInput('u')) . '&client_id=' . self::CLIENT_ID )) or returnServerError('No results for this query'); $tracks = json_decode(getContents( 'https://api.soundcloud.com/users/' . urlencode($res->id) . '/tracks?client_id=' . self::CLIENT_ID )) or returnServerError('No results for this user'); for($i = 0; $i < 10; $i++) { $item = array(); $item['author'] = $tracks[$i]->user->username . ' - ' . $tracks[$i]->title; $item['title'] = $tracks[$i]->user->username . ' - ' . $tracks[$i]->title; $item['content'] = '