summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohannes 'josch' Schauer <josch@debian.org>2020-03-07 10:30:21 +0100
committerJohannes 'josch' Schauer <josch@debian.org>2020-03-07 10:30:21 +0100
commit432eb165b83d4483780a279b02929b05b3e09fa5 (patch)
tree53ff708fcd05370af1595fd720440cde85a46891
parent779ac0902d2586e1ac31ad41881d8922ec40a7ea (diff)
New upstream version 2020-02-26+dfsg1
-rw-r--r--README.md9
-rw-r--r--actions/DisplayAction.php4
-rw-r--r--bridges/AllocineFRBridge.php84
-rw-r--r--bridges/AtmoNouvelleAquitaineBridge.php6
-rw-r--r--bridges/AtmoOccitanieBridge.php58
-rw-r--r--bridges/DaveRamseyBlogBridge.php24
-rw-r--r--bridges/DevToBridge.php15
-rw-r--r--bridges/DonnonsBridge.php123
-rw-r--r--bridges/ExtremeDownloadBridge.php2
-rw-r--r--bridges/FacebookBridge.php1
-rw-r--r--bridges/FirstLookMediaTechBridge.php50
-rw-r--r--bridges/FolhaDeSaoPauloBridge.php51
-rw-r--r--bridges/GithubIssueBridge.php49
-rw-r--r--bridges/GithubSearchBridge.php8
-rw-r--r--bridges/GoComicsBridge.php2
-rw-r--r--bridges/IGNBridge.php34
-rw-r--r--bridges/InstagramBridge.php23
-rw-r--r--bridges/JustETFBridge.php1
-rw-r--r--bridges/MozillaSecurityBridge.php2
-rw-r--r--bridges/NewOnNetflixBridge.php59
-rw-r--r--bridges/PcGamerBridge.php33
-rw-r--r--bridges/PhoronixBridge.php22
-rw-r--r--bridges/PornhubBridge.php99
-rw-r--r--bridges/RainbowSixSiegeBridge.php59
-rw-r--r--bridges/RedditBridge.php2
-rw-r--r--bridges/RevolutBridge.php81
-rw-r--r--bridges/RoosterTeethBridge.php107
-rw-r--r--bridges/ScribdBridge.php83
-rw-r--r--bridges/SoundcloudBridge.php6
-rw-r--r--bridges/TinyLetterBridge.php54
-rw-r--r--bridges/TorrentGalaxyBridge.php120
-rw-r--r--bridges/TwitterBridge.php8
-rw-r--r--bridges/VkBridge.php2
-rw-r--r--bridges/ZoneTelechargementBridge.php4
-rw-r--r--formats/AtomFormat.php5
-rw-r--r--index.php2
-rw-r--r--lib/Configuration.php2
37 files changed, 1082 insertions, 212 deletions
diff --git a/README.md b/README.md
index a9db8ea..2239826 100644
--- a/README.md
+++ b/README.md
@@ -109,8 +109,8 @@ We are RSS-Bridge community, a group of developers continuing the project initia
Use this script to generate the list automatically (using the GitHub API):
https://gist.github.com/LogMANOriginal/da00cd1e5f0ca31cef8e193509b17fd8
-->
-
* [16mhz](https://github.com/16mhz)
+* [86423355844265459587182778](https://github.com/86423355844265459587182778)
* [adamchainz](https://github.com/adamchainz)
* [Ahiles3005](https://github.com/Ahiles3005)
* [Albirew](https://github.com/Albirew)
@@ -126,6 +126,7 @@ https://gist.github.com/LogMANOriginal/da00cd1e5f0ca31cef8e193509b17fd8
* [azdkj532](https://github.com/azdkj532)
* [b1nj](https://github.com/b1nj)
* [benasse](https://github.com/benasse)
+* [Binnette](https://github.com/Binnette)
* [captn3m0](https://github.com/captn3m0)
* [chemel](https://github.com/chemel)
* [ckiw](https://github.com/ckiw)
@@ -161,10 +162,12 @@ https://gist.github.com/LogMANOriginal/da00cd1e5f0ca31cef8e193509b17fd8
* [IceWreck](https://github.com/IceWreck)
* [j0k3r](https://github.com/j0k3r)
* [JackNUMBER](https://github.com/JackNUMBER)
+* [jdesgats](https://github.com/jdesgats)
* [jdigilio](https://github.com/jdigilio)
* [JeremyRand](https://github.com/JeremyRand)
* [Jocker666z](https://github.com/Jocker666z)
* [johnnygroovy](https://github.com/johnnygroovy)
+* [johnpc](https://github.com/johnpc)
* [killruana](https://github.com/killruana)
* [klimplant](https://github.com/klimplant)
* [kranack](https://github.com/kranack)
@@ -187,7 +190,6 @@ https://gist.github.com/LogMANOriginal/da00cd1e5f0ca31cef8e193509b17fd8
* [metaMMA](https://github.com/metaMMA)
* [mitsukarenai](https://github.com/mitsukarenai)
* [MonsieurPoutounours](https://github.com/MonsieurPoutounours)
-* [mr-flibble](https://github.com/mr-flibble)
* [mro](https://github.com/mro)
* [mxmehl](https://github.com/mxmehl)
* [nel50n](https://github.com/nel50n)
@@ -221,6 +223,7 @@ https://gist.github.com/LogMANOriginal/da00cd1e5f0ca31cef8e193509b17fd8
* [sysadminstory](https://github.com/sysadminstory)
* [tameroski](https://github.com/tameroski)
* [teromene](https://github.com/teromene)
+* [tgkenney](https://github.com/tgkenney)
* [thefranke](https://github.com/thefranke)
* [ThePadawan](https://github.com/ThePadawan)
* [TheRadialActive](https://github.com/TheRadialActive)
@@ -232,7 +235,7 @@ https://gist.github.com/LogMANOriginal/da00cd1e5f0ca31cef8e193509b17fd8
* [xurxof](https://github.com/xurxof)
* [yardenac](https://github.com/yardenac)
* [ZeNairolf](https://github.com/ZeNairolf)
-
+
Licenses
===
diff --git a/actions/DisplayAction.php b/actions/DisplayAction.php
index 89930cf..579630a 100644
--- a/actions/DisplayAction.php
+++ b/actions/DisplayAction.php
@@ -190,7 +190,7 @@ class DisplayAction extends ActionAbstract {
$items[] = $item;
} elseif(Configuration::getConfig('error', 'output') === 'http') {
- header('Content-Type: text/html', true, get_return_code($e));
+ header('Content-Type: text/html', true, $this->get_return_code($e));
die(buildTransformException($e, $bridge));
}
}
@@ -222,7 +222,7 @@ class DisplayAction extends ActionAbstract {
$items[] = $item;
} elseif(Configuration::getConfig('error', 'output') === 'http') {
- header('Content-Type: text/html', true, get_return_code($e));
+ header('Content-Type: text/html', true, $this->get_return_code($e));
die(buildTransformException($e, $bridge));
}
}
diff --git a/bridges/AllocineFRBridge.php b/bridges/AllocineFRBridge.php
index 17da903..40ef9a9 100644
--- a/bridges/AllocineFRBridge.php
+++ b/bridges/AllocineFRBridge.php
@@ -8,14 +8,25 @@ class AllocineFRBridge extends BridgeAbstract {
const DESCRIPTION = 'Bridge for allocine.fr';
const PARAMETERS = array( array(
'category' => array(
- 'name' => 'category',
+ 'name' => 'Emission',
'type' => 'list',
- 'exampleValue' => 'Faux Raccord',
- 'title' => 'Select your category',
+ 'title' => 'Sélectionner l\'emission',
'values' => array(
'Faux Raccord' => 'faux-raccord',
- 'Top 5' => 'top-5',
- 'Tueurs en Séries' => 'tueurs-en-serie'
+ 'Fanzone' => 'fanzone',
+ 'Game In Ciné' => 'game-in-cine',
+ 'Pour la faire courte' => 'pour-la-faire-courte',
+ 'Home Cinéma' => 'home-cinema',
+ 'PILS - Par Ici Les Sorties' => 'pils-par-ici-les-sorties',
+ 'AlloCiné : l\'émission, sur LeStream' => 'allocine-lemission-sur-lestream',
+ 'Give Me Five' => 'give-me-five',
+ 'Aviez-vous remarqué ?' => 'aviez-vous-remarque',
+ 'Et paf, il est mort' => 'et-paf-il-est-mort',
+ 'The Big Fan Theory' => 'the-big-fan-theory',
+ 'Clichés' => 'cliches',
+ 'Complètement...' => 'completement',
+ '#Fun Facts' => 'fun-facts',
+ 'Origin Story' => 'origin-story',
)
)
));
@@ -23,19 +34,30 @@ class AllocineFRBridge extends BridgeAbstract {
public function getURI(){
if(!is_null($this->getInput('category'))) {
- switch($this->getInput('category')) {
- case 'faux-raccord':
- $uri = static::URI . 'video/programme-12284/saison-32180/';
- 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;
- }
+ $categories = array(
+ 'faux-raccord' => 'video/programme-12284/saison-37054/',
+ 'fanzone' => 'video/programme-12298/saison-37059/',
+ 'game-in-cine' => 'video/programme-12288/saison-22971/',
+ 'pour-la-faire-courte' => 'video/programme-20960/saison-29678/',
+ 'home-cinema' => 'video/programme-12287/saison-34703/',
+ 'pils-par-ici-les-sorties' => 'video/programme-25789/saison-37253/',
+ 'allocine-lemission-sur-lestream' => 'video/programme-25123/saison-36067/',
+ 'give-me-five' => 'video/programme-21919/saison-34518/',
+ 'aviez-vous-remarque' => 'video/programme-19518/saison-37084/',
+ 'et-paf-il-est-mort' => 'video/programme-25113/saison-36657/',
+ 'the-big-fan-theory' => 'video/programme-20403/saison-37419/',
+ 'cliches' => 'video/programme-24834/saison-35591/',
+ 'completement' => 'video/programme-23859/saison-34102/',
+ 'fun-facts' => 'video/programme-23040/saison-32686/',
+ 'origin-story' => 'video/programme-25667/saison-37041/'
+ );
- return $uri;
+ $category = $this->getInput('category');
+ if(array_key_exists($category, $categories)) {
+ return static::URI . $categories[$category];
+ } else {
+ returnClientError('Emission inconnue');
+ }
}
return parent::getURI();
@@ -63,23 +85,23 @@ class AllocineFRBridge extends BridgeAbstract {
self::PARAMETERS[$this->queriedContext]['category']['values']
);
- foreach($html->find('.media-meta-list figure.media-meta-fig') as $element) {
+ foreach($html->find('div[class=col-left]', 0)->find('div[class*=video-card]') as $element) {
$item = array();
- $title = $element->find('div.titlebar h3.title a', 0);
- $content = trim($element->innertext);
- $figCaption = strpos($content, $category);
+ $title = $element->find('a[class*=meta-title-link]', 0);
+ $content = trim($element->outertext);
- 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;
- }
+ // Replace image 'src' with the one in 'data-src'
+ $content = preg_replace('@src="data:image/gif;base64,[A-Za-z0-9+\/]*"@', '', $content);
+ $content = preg_replace('@data-src=@', 'src=', $content);
+
+ // Remove date in the content to prevent content update while the video is getting older
+ $content = preg_replace('@<div class="meta-sub light">.*<span>[^<]*</span>[^<]*</div>@', '', $content);
+
+ $item['content'] = $content;
+ $item['title'] = trim($title->innertext);
+ $item['uri'] = static::URI . substr($title->href, 1);
+ $this->items[] = $item;
}
}
}
diff --git a/bridges/AtmoNouvelleAquitaineBridge.php b/bridges/AtmoNouvelleAquitaineBridge.php
index d395fa7..7766bd9 100644
--- a/bridges/AtmoNouvelleAquitaineBridge.php
+++ b/bridges/AtmoNouvelleAquitaineBridge.php
@@ -2,8 +2,8 @@
class AtmoNouvelleAquitaineBridge extends BridgeAbstract {
const NAME = 'Atmo Nouvelle Aquitaine';
- const URI = 'https://www.atmo-nouvelleaquitaine.org/monair/commune/';
- const DESCRIPTION = 'Fetches the latest air polution of Bordeaux from Atmo Nouvelle Aquitaine';
+ const URI = 'https://www.atmo-nouvelleaquitaine.org';
+ const DESCRIPTION = 'Fetches the latest air polution of cities in Nouvelle Aquitaine from Atmo';
const MAINTAINER = 'floviolleau';
const PARAMETERS = array(array(
'cities' => array(
@@ -27,7 +27,7 @@ class AtmoNouvelleAquitaineBridge extends BridgeAbstract {
}
public function collectData() {
- $uri = self::URI . $this->getInput('cities');
+ $uri = self::URI . '/monair/commune/' . $this->getInput('cities');
$html = getSimpleHTMLDOM($uri)
or returnServerError('Could not request ' . $uri);
diff --git a/bridges/AtmoOccitanieBridge.php b/bridges/AtmoOccitanieBridge.php
new file mode 100644
index 0000000..24f6383
--- /dev/null
+++ b/bridges/AtmoOccitanieBridge.php
@@ -0,0 +1,58 @@
+<?php
+class AtmoOccitanieBridge extends BridgeAbstract {
+
+ const NAME = 'Atmo Occitanie';
+ const URI = 'https://www.atmo-occitanie.org/';
+ const DESCRIPTION = 'Fetches the latest air polution of cities in Occitanie from Atmo';
+ const MAINTAINER = 'floviolleau';
+ const PARAMETERS = array(array(
+ 'city' => array(
+ 'name' => 'Ville',
+ 'required' => true
+ )
+ ));
+ const CACHE_TIMEOUT = 7200;
+
+ public function collectData() {
+ $uri = self::URI . $this->getInput('city');
+
+ $html = getSimpleHTMLDOM($uri)
+ or returnServerError('Could not request ' . $uri);
+
+ $generalMessage = $html->find('.landing-ville .city-banner .iqa-avertissement', 0)->innertext;
+ $recommendationsDom = $html->find('.landing-ville .recommandations', 0);
+ $recommendationsItemDom = $recommendationsDom->find('.recommandation-item .label');
+
+ $recommendationsMessage = '';
+
+ $i = 0;
+ $len = count($recommendationsItemDom);
+ foreach ($recommendationsItemDom as $key => $value) {
+ if ($i == 0) {
+ $recommendationsMessage .= trim($value->innertext) . '.';
+ } else {
+ $recommendationsMessage .= ' ' . trim($value->innertext) . '.';
+ }
+ $i++;
+ }
+
+ $lastRecommendationsDom = $recommendationsDom->find('.col-md-6', -1);
+ $informationHeaderMessage = $lastRecommendationsDom->find('.heading', 0)->innertext;
+ $indice = $lastRecommendationsDom->find('.current-indice .indice div', 0)->innertext;
+ $informationDescriptionMessage = $lastRecommendationsDom->find('.current-indice .description p', 0)->innertext;
+
+ $message = "$generalMessage L'indice est de $indice/10. $informationDescriptionMessage. $recommendationsMessage";
+ $city = $this->getInput('city');
+
+ $item['uri'] = $uri;
+ $today = date('d/m/Y');
+ $item['title'] = "Bulletin de l'air du $today pour la ville : $city.";
+ //$item['title'] .= ' Retrouvez plus d\'informations en allant sur atmo-occitanie.org #QualiteAir. ' . $message;
+ $item['title'] .= ' #QualiteAir. ' . $message;
+ $item['author'] = 'floviolleau';
+ $item['content'] = $message;
+ $item['uid'] = hash('sha256', $item['title']);
+
+ $this->items[] = $item;
+ }
+}
diff --git a/bridges/DaveRamseyBlogBridge.php b/bridges/DaveRamseyBlogBridge.php
new file mode 100644
index 0000000..34c9044
--- /dev/null
+++ b/bridges/DaveRamseyBlogBridge.php
@@ -0,0 +1,24 @@
+<?php
+
+class DaveRamseyBlogBridge extends BridgeAbstract {
+ const MAINTAINER = 'johnpc';
+ const NAME = 'Dave Ramsey Blog';
+ const URI = 'https://www.daveramsey.com/blog';
+ const CACHE_TIMEOUT = 7200; // 2h
+ const DESCRIPTION = 'Returns blog posts from daveramsey.com';
+
+ public function collectData()
+ {
+ $html = getSimpleHTMLDOM(self::URI)
+ or returnServerError('Could not request daveramsey.com.');
+
+ foreach ($html->find('.Post') as $element) {
+ $this->items[] = array(
+ 'uri' => 'https://www.daveramsey.com' . $element->find('header > a', 0)->href,
+ 'title' => $element->find('header > h2 > a', 0)->plaintext,
+ 'tags' => $element->find('.Post-topic', 0)->plaintext,
+ 'content' => $element->find('.Post-body', 0)->plaintext,
+ );
+ }
+ }
+}
diff --git a/bridges/DevToBridge.php b/bridges/DevToBridge.php
index 868ac97..c298d46 100644
--- a/bridges/DevToBridge.php
+++ b/bridges/DevToBridge.php
@@ -51,15 +51,10 @@ apple-icon-5c6fa9f2bce280428589c6195b7f1924206a53b782b371cfe2d02da932c8c173.png'
$html = defaultLinkTo($html, static::URI);
- $articles = $html->find('div[class="single-article"]')
+ $articles = $html->find('div.single-article')
or returnServerError('Could not find articles!');
foreach($articles as $article) {
-
- if($article->find('[class*="cta"]', 0)) { // Skip ads
- continue;
- }
-
$item = array();
$item['uri'] = $article->find('a[id*=article-link]', 0)->href;
@@ -92,6 +87,14 @@ EOD;
}
+ public function getName() {
+ if (!is_null($this->getInput('tag'))) {
+ return ucfirst($this->getInput('tag')) . ' - dev.to';
+ }
+
+ return parent::getName();
+ }
+
private function getFullArticle($url) {
$html = getSimpleHTMLDOMCached($url)
or returnServerError('Unable to load article from "' . $url . '"!');
diff --git a/bridges/DonnonsBridge.php b/bridges/DonnonsBridge.php
new file mode 100644
index 0000000..7741349
--- /dev/null
+++ b/bridges/DonnonsBridge.php
@@ -0,0 +1,123 @@
+<?php
+/**
+ * Retourne les dons d'une recherche filtrée sur le site Donnons.org
+ * Example: https://donnons.org/Sport/Ile-de-France
+ */
+class DonnonsBridge extends BridgeAbstract {
+
+ const MAINTAINER = 'Binnette';
+ const NAME = 'Donnons.org';
+ const URI = 'https://donnons.org';
+ const CACHE_TIMEOUT = 1800; // 30min
+ const DESCRIPTION = 'Retourne les dons depuis le site Donnons.org.';
+
+ const PARAMETERS = array(
+ array(
+ 'q' => array(
+ 'name' => 'Url de recherche',
+ 'required' => true,
+ 'exampleValue' => '/Sport/Ile-de-France',
+ 'pattern' => '\/.*',
+ 'title' => 'Faites une recherche sur le site. Puis copiez ici la fin de l’url. Doit commencer par /',
+ ),
+ 'p' => array(
+ 'name' => 'Nombre de pages à scanner',
+ 'type' => 'number',
+ 'defaultValue' => 5,
+ 'title' => 'Indique le nombre de pages de donnons.org qui seront scannées'
+ )
+ )
+ );
+
+ public function collectData() {
+ $pages = $this->getInput('p');
+
+ for($i = 1; $i <= $pages; $i++) {
+ $this->collectDataByPage($i);
+ }
+ }
+
+ private function collectDataByPage($page) {
+ $uri = $this->getPageURI($page);
+
+ $html = getSimpleHTMLDOM($uri)
+ or returnServerError('No results for this query.');
+
+ $searchDiv = $html->find('div[id=search]', 0);
+
+ if(!is_null($searchDiv)) {
+ $elements = $searchDiv->find('a.lst-annonce');
+ foreach($elements as $element) {
+ $item = array();
+
+ // Lien vers le don
+ $item['uri'] = self::URI . $element->href;
+ // Id de l'objet
+ $item['uid'] = $element->getAttribute('data-id');
+
+ // Grab info from json
+ $jsonString = $element->find('script', 0)->innertext;
+ $json = json_decode($jsonString, true);
+
+ $name = $json['name'];
+ $category = $json['category'];
+ $date = $json['availabilityStarts'];
+ $description = $json['description'];
+ $city = $json['availableAtOrFrom']['address']['addressLocality'];
+ $region = $json['availableAtOrFrom']['address']['addressRegion'];
+
+ // Grab info from HTML
+ $imageSrc = $element->find('img.ima-center', 0)->getAttribute('data-src');
+ $image = self::URI . $imageSrc;
+ $author = $element->find('div.avatar-holder', 0)->plaintext;
+
+ $content = '
+ <img style="margin-right:1em;" src="' . $image . '">
+ <div>
+ <h1>' . $name . '</h1>
+ <p>' . $description . '</p>
+ <p>Lieu : <b>' . $city . '</b> - ' . $region . '</p>
+ <p>Par : ' . $author . '</p>
+ <p>Date : ' . $date . '</p>
+ </div>
+ ';
+
+ // Titre du don
+ $item['title'] = '[' . $category . '] ' . $name;
+ $item['timestamp'] = $date;
+ $item['author'] = $author;
+ $item['content'] = $content;
+ $item['enclosures'] = array($image);
+
+ $this->items[] = $item;
+ }
+ }
+ }
+
+ private function getPageURI($page) {
+ $uri = $this->getURI();
+ $haveQueryParams = strpos($uri, '?') !== false;
+
+ if($haveQueryParams) {
+ return $uri . '&page=' . $page;
+ } else {
+ return $uri . '?page=' . $page;
+ }
+ }
+
+ public function getURI() {
+ if(!is_null($this->getInput('q'))) {
+ return self::URI . $this->getInput('q');
+ }
+
+ return parent::getURI();
+ }
+
+ public function getName() {
+ if(!is_null($this->getInput('q'))) {
+ return 'Donnons.org - ' . $this->getInput('q');
+ }
+
+ return parent::getName();
+ }
+}
diff --git a/bridges/ExtremeDownloadBridge.php b/bridges/ExtremeDownloadBridge.php
index 1b4aa9a..bca3997 100644
--- a/bridges/ExtremeDownloadBridge.php
+++ b/bridges/ExtremeDownloadBridge.php
@@ -1,7 +1,7 @@
<?php
class ExtremeDownloadBridge extends BridgeAbstract {
const NAME = 'Extreme Download';
- const URI = 'https://wvw.extreme-down.xyz/';
+ const URI = 'https://www.extreme-down.ninja/';
const DESCRIPTION = 'Suivi de série sur Extreme Download';
const MAINTAINER = 'sysadminstory';
const PARAMETERS = array(
diff --git a/bridges/FacebookBridge.php b/bridges/FacebookBridge.php
index 5ce67f9..13ccb27 100644
--- a/bridges/FacebookBridge.php
+++ b/bridges/FacebookBridge.php
@@ -729,6 +729,7 @@ EOD;
}
}
}
+
#endregion (User)
}
diff --git a/bridges/FirstLookMediaTechBridge.php b/bridges/FirstLookMediaTechBridge.php
new file mode 100644
index 0000000..114bf62
--- /dev/null
+++ b/bridges/FirstLookMediaTechBridge.php
@@ -0,0 +1,50 @@
+<?php
+class FirstLookMediaTechBridge extends BridgeAbstract {
+ const NAME = 'First Look Media - Technology';
+ const URI = 'https://tech.firstlook.media';
+ const DESCRIPTION = 'First Look Media Technology page';
+ const MAINTAINER = 'somini';
+ const PARAMETERS = array(
+ array(
+ 'projects' => array(
+ 'type' => 'checkbox',
+ 'name' => 'Include Projects?',
+ )
+ )
+ );
+
+ public function collectData() {
+ $html = getSimpleHTMLDOM(self::URI)
+ or returnServerError('Could not load content');
+
+ if ($this->getInput('projects')) {
+ $top_projects = $html->find('.PromoList-ul', 0);
+ foreach($top_projects->find('li.PromoList-item') as $element) {
+ $item = array();
+
+ $item_uri = $element->find('a', 0);
+ $item['uri'] = $item_uri->href;
+ $item['title'] = strip_tags($item_uri->innertext);
+ $item['content'] = $element->find('div > div', 0);
+
+ $this->items[] = $item;
+ }
+ }
+
+ $top_articles = $html->find('.PromoList-ul', 1);
+ foreach($top_articles->find('li.PromoList-item') as $element) {
+ $item = array();
+
+ $item_left = $element->find('div > div', 0);
+ $item_date = $element->find('.PromoList-date', 0);
+ $item['timestamp'] = strtotime($item_date->innertext);
+ $item_date->outertext = ''; /* Remove */
+ $item['author'] = $item_left->innertext;
+ $item_uri = $element->find('a', 0);
+ $item['uri'] = self::URI . $item_uri->href;
+ $item['title'] = strip_tags($item_uri);
+
+ $this->items[] = $item;
+ }
+ }
+}
diff --git a/bridges/FolhaDeSaoPauloBridge.php b/bridges/FolhaDeSaoPauloBridge.php
new file mode 100644
index 0000000..acd8d25
--- /dev/null
+++ b/bridges/FolhaDeSaoPauloBridge.php
@@ -0,0 +1,51 @@
+<?php
+class FolhaDeSaoPauloBridge extends FeedExpander {
+ const MAINTAINER = 'somini';
+ const NAME = 'Folha de São Paulo';
+ const URI = 'https://www1.folha.uol.com.br';
+ const DESCRIPTION = 'Returns the newest posts from Folha de São Paulo (full text)';
+ const PARAMETERS = array(
+ array(
+ 'feed' => array(
+ 'name' => 'Feed sub-URL',
+ 'type' => 'text',
+ 'title' => 'Select the sub-feed (see https://www1.folha.uol.com.br/feed/)',
+ 'exampleValue' => 'emcimadahora/rss091.xml',
+ )
+ )
+ );
+
+ protected function parseItem($item){
+ $item = parent::parseItem($item);
+
+ $articleHTMLContent = getSimpleHTMLDOMCached($item['uri']);
+ if($articleHTMLContent) {
+ foreach ($articleHTMLContent->find('div.c-news__body .is-hidden') as $toRemove) {
+ $toRemove->innertext = '';
+ }
+ $item_content = $articleHTMLContent->find('div.c-news__body', 0);
+ if ($item_content) {
+ $text = $item_content->innertext;
+ $text = strip_tags($text, '<p><b><a><blockquote><img><em>');
+ $item['content'] = $text;
+ }
+ } else {
+ Debug::log('???: ' . $item['uri']);
+ }
+
+ return $item;
+ }
+
+ public function collectData(){
+ $feed_input = $this->getInput('feed');
+ if (substr($feed_input, 0, strlen(self::URI)) === self::URI) {
+ Debug::log('Input:: ' . $feed_input);
+ $feed_url = $feed_input;
+ } else {
+ /* TODO: prepend `/` if missing */
+ $feed_url = self::URI . '/' . $this->getInput('feed');
+ }
+ Debug::log('URL: ' . $feed_url);
+ $this->collectExpandableDatas($feed_url);
+ }
+}
diff --git a/bridges/GithubIssueBridge.php b/bridges/GithubIssueBridge.php
index 2eddeb2..29a336b 100644
--- a/bridges/GithubIssueBridge.php
+++ b/bridges/GithubIssueBridge.php
@@ -82,17 +82,20 @@ class GithubIssueBridge extends BridgeAbstract {
$uri = $this->buildGitHubIssueCommentUri($issueNbr, $comment->id);
- $author = $comment->find('.author', 0)->plaintext;
+ $author = $comment->find('.author', 0);
+ if ($author) {
+ $author = $author->plaintext;
+ } else {
+ $author = '';
+ }
- $title .= ' / ' . trim($comment->plaintext);
+ $title .= ' / '
+ . trim(str_replace(
+ array('octicon','-'), array(''),
+ $comment->find('.octicon', 0)->getAttribute('class')
+ ));
- $content = $title;
- if (null !== $comment->nextSibling()) {
- $content = $comment->nextSibling()->innertext;
- if ($comment->nextSibling()->nodeName() === 'span') {
- $content = $comment->nextSibling()->nextSibling()->innertext;
- }
- }
+ $content = $comment->plaintext;
$item = array();
$item['author'] = $author;
@@ -135,32 +138,20 @@ class GithubIssueBridge extends BridgeAbstract {
substr($issue->find('.gh-header-number', 0)->plaintext, 1)
);
- $comments = $issue->find('
- [id^="issue-"] > .comment,
- [id^="issuecomment-"] > .comment,
- [id^="event-"],
- [id^="ref-"]
- ');
- foreach($comments as $comment) {
-
- if (!$comment->hasChildNodes()) {
- continue;
- }
+ $comments = $issue->find(
+ '.comment, .TimelineItem-badge'
+ );
- if (!$comment->hasClass('discussion-item-header')) {
+ foreach($comments as $comment) {
+ if ($comment->hasClass('comment')) {
+ $comment = $comment->parent;
$item = $this->extractIssueComment($issueNbr, $title, $comment);
$items[] = $item;
continue;
- }
-
- while ($comment->hasClass('discussion-item-header')) {
+ } else {
+ $comment = $comment->parent;
$item = $this->extractIssueEvent($issueNbr, $title, $comment);
$items[] = $item;
- $comment = $comment->nextSibling();
- if (null == $comment) {
- break;
- }
- $classes = explode(' ', $comment->getAttribute('class'));
}
}
diff --git a/bridges/GithubSearchBridge.php b/bridges/GithubSearchBridge.php
index fd90934..9c1face 100644
--- a/bridges/GithubSearchBridge.php
+++ b/bridges/GithubSearchBridge.php
@@ -27,16 +27,16 @@ class GithubSearchBridge extends BridgeAbstract {
foreach($html->find('li.repo-list-item') as $element) {
$item = array();
- $uri = $element->find('h3 a', 0)->href;
+ $uri = $element->find('.f4 a', 0)->href;
$uri = substr(self::URI, 0, -1) . $uri;
$item['uri'] = $uri;
- $title = $element->find('h3', 0)->plaintext;
+ $title = $element->find('.f4', 0)->plaintext;
$item['title'] = $title;
// Description
- if (count($element->find('p.d-inline-block')) != 0) {
- $content = $element->find('p.d-inline-block', 0)->innertext;
+ if (count($element->find('p.mb-1')) != 0) {
+ $content = $element->find('p.mb-1', 0)->innertext;
} else{
$content = 'No description';
}
diff --git a/bridges/GoComicsBridge.php b/bridges/GoComicsBridge.php
index 3223d19..7512d84 100644
--- a/bridges/GoComicsBridge.php
+++ b/bridges/GoComicsBridge.php
@@ -28,7 +28,7 @@ class GoComicsBridge extends BridgeAbstract {
$page = getSimpleHTMLDOM($link)
or returnServerError('Could not request GoComics: ' . $link);
- $imagelink = $page->find('.img-fluid', 1)->src;
+ $imagelink = $page->find('.comic.container', 0)->getAttribute('data-image');
$date = explode('/', $link);
$item['id'] = $imagelink;
diff --git a/bridges/IGNBridge.php b/bridges/IGNBridge.php
index 6a254b3..ef5088f 100644
--- a/bridges/IGNBridge.php
+++ b/bridges/IGNBridge.php
@@ -19,6 +19,27 @@ class IGNBridge extends FeedExpander {
// $articlePage gets the entire page's contents
$articlePage = getSimpleHTMLDOM($newsItem->link);
+ // List of BS elements
+ $uselessElements = array(
+ '.wiki-page-tools',
+ '.feedback-container',
+ '.paging-container',
+ '.dropdown-wrapper',
+ '.mw-editsection',
+ '.jsx-4115608983',
+ '.jsx-4213937408',
+ '.commerce-container',
+ '.widget-container',
+ '.newsletter-signup-button'
+ );
+
+ // Remove useless elements
+ foreach($uselessElements as $uslElement) {
+ foreach($articlePage->find($uslElement) as $jsWidget) {
+ $jsWidget->remove();
+ }
+ }
+
/*
* NOTE: Though articles and wiki/howtos have seperate styles of pages, there is no mechanism
* for handling them seperately as it just ignores the DOM querys which it does not find.
@@ -33,19 +54,8 @@ class IGNBridge extends FeedExpander {
}
// For Wikis and HowTos
- $uselessWikiElements = array(
- '.wiki-page-tools',
- '.feedback-container',
- '.paging-container'
- );
foreach($articlePage->find('.wiki-page') as $wikiContents) {
- $copy = clone $wikiContents;
- // Remove useless elements present in IGN wiki/howtos
- foreach($uselessWikiElements as $uslElement) {
- $toRemove = $wikiContents->find($uslElement, 0);
- $copy = str_replace($toRemove, '', $copy);
- }
- $article = $article . $copy;
+ $article = $article . $wikiContents;
}
// Add content to feed
diff --git a/bridges/InstagramBridge.php b/bridges/InstagramBridge.php
index 679c4c0..0a6dbaa 100644
--- a/bridges/InstagramBridge.php
+++ b/bridges/InstagramBridge.php
@@ -123,6 +123,12 @@ class InstagramBridge extends BridgeAbstract {
$item['title'] = substr($item['title'], 0, $titleLinePos) . '...';
}
+ if($directLink) {
+ $mediaURI = $media->display_url;
+ } else {
+ $mediaURI = self::URI . 'p/' . $media->shortcode . '/media?size=l';
+ }
+
switch($media->__typename) {
case 'GraphSidecar':
$data = $this->getInstagramSidecarData($item['uri'], $item['title']);
@@ -130,24 +136,20 @@ class InstagramBridge extends BridgeAbstract {
$item['enclosures'] = $data[1];
break;
case 'GraphImage':
- if($directLink) {
- $mediaURI = $media->display_url;
- } else {
- $mediaURI = self::URI . 'p/' . $media->shortcode . '/media?size=l';
- }
$item['content'] = '<a href="' . htmlentities($item['uri']) . '" target="_blank">';
$item['content'] .= '<img src="' . htmlentities($mediaURI) . '" alt="' . $item['title'] . '" />';
$item['content'] .= '</a><br><br>' . nl2br(htmlentities($textContent));
$item['enclosures'] = array($mediaURI);
break;
case 'GraphVideo':
- $data = $this->getInstagramVideoData($item['uri']);
+ $data = $this->getInstagramVideoData($item['uri'], $mediaURI);
$item['content'] = $data[0];
if($directLink) {
$item['enclosures'] = $data[1];
} else {
- $item['enclosures'] = array(self::URI . 'p/' . $media->shortcode . '/media?size=l');
+ $item['enclosures'] = array($mediaURI);
}
+ $item['thumbnail'] = $mediaURI;
break;
default: break;
}
@@ -185,11 +187,14 @@ class InstagramBridge extends BridgeAbstract {
}
// returns Video post's contents and enclosures
- protected function getInstagramVideoData($uri) {
+ protected function getInstagramVideoData($uri, $mediaURI) {
$mediaInfo = $this->getSinglePostData($uri);
$textContent = $this->getTextContent($mediaInfo);
- $content = '<video controls><source src="' . $mediaInfo->video_url . '" type="video/mp4"></video><br>';
+ $content = '<video controls>';
+ $content .= '<source src="' . $mediaInfo->video_url . '" poster="' . $mediaURI . '" type="video/mp4">';
+ $content .= '<img src="' . $mediaURI . '" alt="">';
+ $content .= '</video><br>';
$content .= '<br>' . nl2br(htmlentities($textContent));
return array($content, array($mediaInfo->video_url));
diff --git a/bridges/JustETFBridge.php b/bridges/JustETFBridge.php
index 8d5b3d5..746f1c9 100644
--- a/bridges/JustETFBridge.php
+++ b/bridges/JustETFBridge.php
@@ -347,5 +347,6 @@ class JustETFBridge extends BridgeAbstract {
return $element->plaintext;
}
+
#endregion
}
diff --git a/bridges/MozillaSecurityBridge.php b/bridges/MozillaSecurityBridge.php
index 52672f5..1e7dc31 100644
--- a/bridges/MozillaSecurityBridge.php
+++ b/bridges/MozillaSecurityBridge.php
@@ -15,7 +15,7 @@ class MozillaSecurityBridge extends BridgeAbstract {
$html = defaultLinkTo($html, self::WEBROOT);
$item = array();
- $articles = $html->find('div[itemprop="articleBody"] h2');
+ $articles = $html->find('div[id="main-content"] h2');
foreach ($articles as $element) {
$item['title'] = $element->innertext;
diff --git a/bridges/NewOnNetflixBridge.php b/bridges/NewOnNetflixBridge.php
new file mode 100644
index 0000000..bb35e71
--- /dev/null
+++ b/bridges/NewOnNetflixBridge.php
@@ -0,0 +1,59 @@
+<?php
+
+class NewOnNetflixBridge extends BridgeAbstract {
+ const NAME = 'NewOnNetflix removals bridge';
+ const URI = 'https://www.newonnetflix.info';
+ const DESCRIPTION = 'Upcoming removals from Netflix (NewOnNetflix already provides additions as RSS)';
+ const MAINTAINER = 'jdesgats';
+ const PARAMETERS = array(array(
+ 'country' => array(
+ 'name' => 'Country',
+ 'type' => 'list',
+ 'values' => array(
+ 'Australia/New Zealand' => 'anz',
+ 'Canada' => 'can',
+ 'United Kingdom' => 'uk',
+ 'United States' => 'usa',
+ ),
+ 'defaultValue' => 'uk',
+ )
+ ));
+ const CACHE_TIMEOUT = 3600 * 24;
+
+ public function collectData() {
+ $baseURI = 'https://' . $this->getInput('country') . '.newonnetflix.info';
+ $html = getSimpleHTMLDOMCached($baseURI . '/lastchance', self::CACHE_TIMEOUT)
+ or returnServerError('Could not request NewOnNetflix (U FAILED LOL).');
+
+ foreach($html->find('article.oldpost') as $element) {
+ $title = $element->find('a.infopop[title]', 0);
+ $img = $element->find('img[lazy_src]', 0);
+ $date = $element->find('span[title]', 0);
+
+ // format sholud be 'dd/mm/yy - dd/mm/yy'
+ // (the added date might be "unknown")
+ $fromTo = array();
+ if (preg_match('/^\s*(.*?)\s*-\s*(.*?)\s*$/', $date->title, $fromTo)) {
+ $from = $fromTo[1];
+ $to = $fromTo[2];
+ } else {
+ $from = 'unknown';
+ $to = 'unknown';
+ }
+ $summary = <<<EOD
+ <img src="{$img->lazy_src}" loading="lazy">
+ <div>{$title->title}</div>
+ <div><strong>Added on:</strong>$from</div>
+ <div><strong>Removed on:</strong>$to</div>
+EOD;
+
+ $item = array();
+ $item['uri'] = $baseURI . $title->href;
+ $item['title'] = $to . ' - ' . $title->plaintext;
+ $item['content'] = $summary;
+ // some movies are added and removed multiple times
+ $item['uid'] = $title->href . '-' . $to;
+ $this->items[] = $item;
+ }
+ }
+}
diff --git a/bridges/PcGamerBridge.php b/bridges/PcGamerBridge.php
index e0e55ce..c4bcccf 100644
--- a/bridges/PcGamerBridge.php
+++ b/bridges/PcGamerBridge.php
@@ -2,22 +2,43 @@
class PcGamerBridge extends BridgeAbstract
{
const NAME = 'PC Gamer';
- const URI = 'https://www.pcgamer.com/';
+ const URI = 'https://www.pcgamer.com/archive/';
const DESCRIPTION = 'PC Gamer Most Read Stories';
- const MAINTAINER = 'mdemoss';
+ const CACHE_TIMEOUT = 3600;
+ const MAINTAINER = 'IceWreck, mdemoss';
public function collectData()
{
$html = getSimpleHTMLDOMCached($this->getURI(), 300);
- $stories = $html->find('div#popularcontent li.most-popular-item');
+ $stories = $html->find('ul.basic-list li.day-article');
+ $i = 0;
+ // Find induvidual stories in the archive page
foreach ($stories as $element) {
+ if($i == 15) break;
$item['uri'] = $element->find('a', 0)->href;
+ // error_log(print_r($item['uri'], TRUE));
$articleHtml = getSimpleHTMLDOMCached($item['uri']);
- $item['title'] = $element->find('h4 a', 0)->plaintext;
+ $item['title'] = $element->find('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;
+ $item['author'] = $articleHtml->find('span.by-author a', 0)->plaintext;
+
+ // Get the article content
+ $articleContents = $articleHtml->find('#article-body', 0);
+
+ /*
+ By default the img src has a link to an error image and then the actual image
+ is added in by JS. So we replace the error image with the actual full size image
+ whoose link is in one of the attributes of the img tag
+ */
+ foreach($articleContents->find('img') as $img) {
+ $imgsrc = $img->getAttribute('data-original-mos');
+ // error_log($imgsrc);
+ $img->src = $imgsrc;
+ }
+
+ $item['content'] = $articleContents;
$this->items[] = $item;
+ $i++;
}
}
}
diff --git a/bridges/PhoronixBridge.php b/bridges/PhoronixBridge.php
new file mode 100644
index 0000000..c5ded27
--- /dev/null
+++ b/bridges/PhoronixBridge.php
@@ -0,0 +1,22 @@
+<?php
+class PhoronixBridge extends FeedExpander {
+
+ const MAINTAINER = 'IceWreck';
+ const NAME = 'Phoronix Bridge';
+ const URI = 'https://www.phoronix.com';
+ const CACHE_TIMEOUT = 3600;
+ const DESCRIPTION = 'RSS feed for Linux news website Phoronix';
+
+ public function collectData(){
+ $this->collectExpandableDatas('https://www.phoronix.com/rss.php', 15);
+ }
+
+ protected function parseItem($newsItem){
+ $item = parent::parseItem($newsItem);
+ // $articlePage gets the entire page's contents
+ $articlePage = getSimpleHTMLDOM($newsItem->link);
+ $article = $articlePage->find('.content', 0);
+ $item['content'] = $article;
+ return $item;
+ }
+}
diff --git a/bridges/PornhubBridge.php b/bridges/PornhubBridge.php
new file mode 100644
index 0000000..b8da99a
--- /dev/null
+++ b/bridges/PornhubBridge.php
@@ -0,0 +1,99 @@
+<?php
+
+class PornhubBridge extends BridgeAbstract {
+
+ const MAINTAINER = 'Mitsukarenai';
+ const NAME = 'Pornhub';
+ const URI = 'https://www.pornhub.com/';
+ const CACHE_TIMEOUT = 3600; // 1h
+ const DESCRIPTION = 'Returns videos from specified user,model,pornstar';
+
+ const PARAMETERS = array(array(
+ 'q' => array(
+ 'name' => 'User name',
+ 'required' => true,
+ ),
+ 'type' => array(
+ 'name' => 'User type',
+ 'type' => 'list',
+ 'values' => array(
+ 'user' => 'users',
+ 'model' => 'model',
+ 'pornstar' => 'pornstar',
+ ),
+ 'defaultValue' => 'users',
+ ),
+ 'sort' => array(
+ 'name' => 'Sort by',
+ 'type' => 'list',
+ 'values' => array(
+ 'Most recent' => '?',
+ 'Most views' => '?o=mv',
+ 'Top rated' => '?o=tr',
+ 'Longest' => '?o=lg',
+ ),
+ 'defaultValue' => '?',
+ ),
+ 'show_images' => array(
+ 'name' => 'Show thumbnails',
+ 'type' => 'checkbox',
+ ),
+ ));
+
+ public function getName(){
+ if(!is_null($this->getInput('type')) && !is_null($this->getInput('q'))) {
+ return 'PornHub ' . $this->getInput('type') . ':' . $this->getInput('q');
+ }
+
+ return parent::getName();
+ }
+
+ public function collectData() {
+
+ $uri = 'https://www.pornhub.com/' . $this->getInput('type') . '/';
+ switch($this->getInput('type')) { // select proper permalink format per user type...
+ case 'model':
+ $uri .= urlencode($this->getInput('q')) . '/videos' . $this->getInput('sort'); break;
+ case 'users':
+ $uri .= urlencode($this->getInput('q')) . '/videos/public' . $this->getInput('sort'); break;
+ case 'pornstar':
+ $uri .= urlencode($this->getInput('q')) . '/videos/upload' . $this->getInput('sort'); break;
+ }
+
+ $show_images = $this->getInput('show_images');
+
+ $html = getSimpleHTMLDOM($uri)
+ or returnServerError('Could not request PornHub.');
+
+ foreach($html->find('div.videoUList ul.videos li.videoblock') as $element) {
+
+ $item = array();
+
+ $item['author'] = $this->getInput('q');
+
+ // Title
+ $title = $element->find('a', 0)->getAttribute('title');
+ if (is_null($title)) {
+ continue;
+ }
+ $item['title'] = $title;
+
+ // Url
+ $url = $element->find('a', 0)->href;
+ $item['uri'] = 'https://www.pornhub.com' . $url;
+
+ // Content
+ $image = $element->find('img', 0)->getAttribute('data-src');
+ if($show_images === true) {
+ $item['content'] = '<a href="' . $item['uri'] . '"><img src="' . $image . '"></a>';
+ }
+
+ // date hack, guess upload YYYYMMDD from thumbnail URL (format: https://ci.phncdn.com/videos/201907/25/--- )
+ $uploaded = explode('/', $image);
+ $uploaded = strtotime($uploaded[4] . $uploaded[5]);
+ $item['timestamp'] = $uploaded;
+
+ $this->items[] = $item;
+ }
+ }
+}
diff --git a/bridges/RainbowSixSiegeBridge.php b/bridges/RainbowSixSiegeBridge.php
index 724edc8..62ea482 100644
--- a/bridges/RainbowSixSiegeBridge.php
+++ b/bridges/RainbowSixSiegeBridge.php
@@ -2,19 +2,18 @@
class RainbowSixSiegeBridge extends BridgeAbstract {
const MAINTAINER = 'corenting';
- const NAME = 'Rainbow Six Siege Blog';
- const URI = 'https://rainbow6.ubisoft.com/siege/en-us/news/';
+ const NAME = 'Rainbow Six Siege News';
+ const URI = 'https://www.ubisoft.com/en-us/game/rainbow-six/siege/news-updates';
const CACHE_TIMEOUT = 7200; // 2h
- const DESCRIPTION = 'Latest articles from the Rainbow Six Siege blog';
+ const DESCRIPTION = 'Latest news about Rainbow Six Siege';
public function getIcon() {
- return 'https://ubistatic19-a.akamaihd.net/resource/en-us/game/rainbow6/siege-v3/r6s-favicon_316592.ico';
+ return 'https://static-dm.akamaized.net/siege/prod/favicon-144x144.png';
}
public function collectData(){
- $dlUrl = 'https://prod-tridionservice.ubisoft.com/live/v1/News/Latest?templateId=tcm%3A152-7677';
- $dlUrl .= '8-32&pageIndex=0&pageSize=10&language=en-US&detailPageId=tcm%3A150-194572-64';
- $dlUrl .= '&keywordList=233416%2C316144%2C233418%2C233417&siteId=undefined&useSeoFriendlyUrl=true';
+ $dlUrl = 'https://www.ubisoft.com/api/updates/items?categoriesFilter=all';
+ $dlUrl = $dlUrl . '&limit=6&mediaFilter=all&skip=0&startIndex=undefined&locale=en-us';
$jsonString = getContents($dlUrl) or returnServerError('Error while downloading the website content');
$json = json_decode($jsonString, true);
@@ -22,17 +21,47 @@ class RainbowSixSiegeBridge extends BridgeAbstract {
// Start at index 2 to remove highlighted articles
for($i = 0; $i < count($json); $i++) {
- $jsonItem = $json[$i]['Content'];
- $article = str_get_html($jsonItem);
+ $jsonItem = $json[$i];
- $item = array();
+ $uri = 'https://www.ubisoft.com/en-us/game/rainbow-six/siege';
+ $uri = $uri . $jsonItem['button']['buttonUrl'];
+
+ $thumbnail = '<img src="' . $jsonItem['thumbnail']['url'] . '" alt="Thumbnail">';
+ $content = $thumbnail . '<br />' . $jsonItem['content'];
+
+ // Markdown parsing from https://gist.github.com/jbroadway/2836900
+
+ // Line breaks
+ $content = preg_replace("/\r\n|\r|\n/", '<br/>', $content);
+
+ // Links
+ $regex = '/\[([^\[]+)\]\(([^\)]+)\)/';
+ $replacement = '<a href=\'\2\'>\1</a>';
+ $content = preg_replace($regex, $replacement, $content);
- $uri = $article->find('h3 a', 0)->href;
- $uri = 'https://rainbow6.ubisoft.com' . $uri;
+ // Bold text
+ $regex = '/(\*\*|__)(.*?)\1/';
+ $replacement = '<strong>\2</strong>';
+ $content = preg_replace($regex, $replacement, $content);
+
+ // Lists
+ $regex = '/\n\s*[\*|\-](.*)/';
+ $content = preg_replace_callback($regex, function($regs) {
+ $item = $regs[1];
+ return sprintf ('<ul><li>%s</li></ul>', trim ($item));
+ }, $content);
+
+ // Italic text
+ $regex = '/(\*\*|\*)(.*?)\1/';
+ $replacement = '<i>\2</i>';
+ $content = preg_replace($regex, $replacement, $content);
+
+ $item = array();
$item['uri'] = $uri;
- $item['title'] = $article->find('h3', 0)->plaintext;
- $item['content'] = $article->find('img', 0)->outertext . '<br />' . $article->find('strong', 0)->plaintext;
- $item['timestamp'] = strtotime($article->find('p.news_date', 0)->plaintext);
+ $item['id'] = $jsonItem['id'];
+ $item['title'] = $jsonItem['title'];
+ $item['content'] = $content;
+ $item['timestamp'] = strtotime($jsonItem['date']);
$this->items[] = $item;
}
diff --git a/bridges/RedditBridge.php b/bridges/RedditBridge.php
index d83c0a3..8de499f 100644
--- a/bridges/RedditBridge.php
+++ b/bridges/RedditBridge.php
@@ -27,7 +27,7 @@ class RedditBridge extends FeedExpander {
public function collectData(){
- switch($this->queriedcontext) {
+ switch($this->queriedContext) {
case 'single': $subreddits[] = $this->getInput('r'); break;
case 'multi': $subreddits = explode(',', $this->getInput('rs')); break;
}
diff --git a/bridges/RevolutBridge.php b/bridges/RevolutBridge.php
deleted file mode 100644
index 04ca377..0000000
--- a/bridges/RevolutBridge.php
+++ /dev/null
@@ -1,81 +0,0 @@
-<?php
-
-class RevolutBridge extends BridgeAbstract {
-
- const NAME = 'Revolut Blog';
- const URI = 'https://blog.revolut.com/';
- const DESCRIPTION = 'Returns recent blog posts from Revolut.';
- const MAINTAINER = 'dominik-th';
-
- public function getIcon() {
- return self::URI . 'favicon.png';
- }
-
- public function collectData() {
- $articleOverview = getSimpleHTMLDOM(self::URI . 'sitemap-posts.xml')
- or returnServerError('Error while downloading the website content');
-
- $articles = array_slice($articleOverview->find('url'), 0, 15);
-
- foreach($articles as $article) {
- $item = array();
-
- $item['uri'] = $article->find('loc', 0)->plaintext;
- $item['timestamp'] = $article->find('lastmod', 0)->plaintext;
- $item['enclosures'] = array(
- $article->find('image:loc', 0)->plaintext
- );
-
- $fullArticle = getSimpleHTMLDOMCached($item['uri'])
- or returnServerError('Error while downloading the full article');
-
- $item['author'] = $fullArticle
- ->find('h4[class="author-card-name"] a', 0)
- ->plaintext;
- $item['title'] = $fullArticle
- ->find('h1[class="post-full-title"]', 0)
- ->plaintext;
-
- $content = $fullArticle
- ->find('section[class="post-full-content"]', 0);
-
- foreach($content->find('img') as $image) {
- $image->src = $this->generateAbsoluteUrl($image->src);
- }
-
- foreach($content->find('a') as $hyperlink) {
- $hyperlink->href = $this->generateAbsoluteUrl($hyperlink->href);
- }
-
- foreach($content->find('iframe') as $iframe) {
- $iframe->outertext = $this->generateYoutubeReplacement($iframe);
- }
-
- $item['content'] = $content->innertext;
- $this->items[] = $item;
- }
- }
-
- private function generateAbsoluteUrl($path) {
- if (filter_var($path, FILTER_VALIDATE_URL)) {
- return $path;
- } else {
- return self::URI . $path;
- }
- }
-
- private function generateYoutubeReplacement($iframe) {
- $embedUrl = $iframe->src;
- if (parse_url($embedUrl, PHP_URL_HOST) === 'www.youtube.com') {
- $urlParts = explode('/', parse_url($embedUrl, PHP_URL_PATH));
- $videoId = end($urlParts);
- $thumbnailUrl = 'https://img.youtube.com/vi/' . $videoId . '/0.jpg';
- $videoUrl = 'https://www.youtube.com/watch?v=' . $videoId;
- $videoReplacement = str_get_html('<a><img /></a>');
- $videoReplacement->find('a', 0)->href = $videoUrl;
- $videoReplacement->find('img', 0)->src = $thumbnailUrl;
- return $videoReplacement;
- }
- return $iframe->outertext;
- }
-}
diff --git a/bridges/RoosterTeethBridge.php b/bridges/RoosterTeethBridge.php
new file mode 100644
index 0000000..496c7de
--- /dev/null
+++ b/bridges/RoosterTeethBridge.php
@@ -0,0 +1,107 @@
+<?php
+
+class RoosterTeethBridge extends BridgeAbstract {
+
+ const MAINTAINER = 'tgkenney';
+ const NAME = 'Rooster Teeth';
+ const URI = 'https://roosterteeth.com';
+ const DESCRIPTION = 'Gets the latest channel videos from the Rooster Teeth website';
+ const API = 'https://svod-be.roosterteeth.com/';
+
+ const PARAMETERS = array(
+ 'Options' => array(
+ 'channel' => array(
+ 'type' => 'list',
+ 'name' => 'Channel',
+ 'title' => 'Select a channel to filter by',
+ 'values' => array(
+ 'All channels' => 'all',
+ 'Achievement Hunter' => 'achievement-hunter',
+ 'Cow Chop' => 'cow-chop',
+ 'Death Battle' => 'death-battle',
+ 'Funhaus' => 'funhaus',
+ 'Inside Gaming' => 'inside-gaming',
+ 'JT Music' => 'jt-music',
+ 'Kinda Funny' => 'kinda-funny',
+ 'Rooster Teeth' => 'rooster-teeth',
+ 'Sugar Pine 7' => 'sugar-pine-7'
+ )
+ ),
+ 'sort' => array(
+ 'type' => 'list',
+ 'name' => 'Sort',
+ 'title' => 'Select a sort order',
+ 'values' => array(
+ 'Newest -> Oldest' => 'desc',
+ 'Oldest -> Newest' => 'asc'
+ ),
+ 'defaultValue' => 'desc'
+ ),
+ 'first' => array(
+ 'type' => 'list',
+ 'name' => 'RoosterTeeth First',
+ 'title' => 'Select whether to include "First" videos before they are public',
+ 'values' => array(
+ 'True' => true,
+ 'False' => false
+ )
+ ),
+ 'limit' => array(
+ 'name' => 'Limit',
+ 'type' => 'number',
+ 'required' => false,
+ 'title' => 'Maximum number of items to return',
+ 'defaultValue' => 10
+ )
+ )
+ );
+
+ public function collectData() {
+ if ($this->getInput('channel') !== 'all') {
+ $uri = self::API
+ . 'api/v1/episodes?per_page='
+ . $this->getInput('limit')
+ . '&channel_id='
+ . $this->getInput('channel')
+ . '&order=' . $this->getInput('sort')
+ . '&page=1';
+
+ $htmlJSON = getSimpleHTMLDOM($uri)
+ or returnServerError('Could not contact Rooster Teeth: ' . $uri);
+ } else {
+ $uri = self::API
+ . '/api/v1/episodes?per_page='
+ . $this->getInput('limit')
+ . '&filter=all&order='
+ . $this->getInput('sort')
+ . '&page=1';
+
+ $htmlJSON = getSimpleHTMLDOM($uri)
+ or returnServerError('Could not contact Rooster Teeth: ' . $uri);
+ }
+
+ $htmlArray = json_decode($htmlJSON, true);
+
+ foreach($htmlArray['data'] as $key => $value) {
+ $item = array();
+
+ if (!$this->getInput('first') && $value['attributes']['is_sponsors_only']) {
+ continue;
+ }
+
+ $publicDate = date_create($value['attributes']['member_golive_at']);
+ $dateDiff = date_diff($publicDate, date_create(), false);
+
+ if (!$this->getInput('first') && $dateDiff->invert == 1) {
+ continue;
+ }
+
+ $item['uri'] = self::URI . $value['canonical_links']['self'];
+ $item['title'] = $value['attributes']['title'];
+ $item['timestamp'] = $value['attributes']['member_golive_at'];
+ $item['author'] = $value['attributes']['show_title'];
+
+ $this->items[] = $item;
+ }
+ }
+}
diff --git a/bridges/ScribdBridge.php b/bridges/ScribdBridge.php
new file mode 100644
index 0000000..3cb4199
--- /dev/null
+++ b/bridges/ScribdBridge.php
@@ -0,0 +1,83 @@
+<?php
+class ScribdBridge extends BridgeAbstract {
+ const NAME = 'Scribd Bridge';
+ const URI = 'https://www.scribd.com';
+ const DESCRIPTION = 'Returns documents uploaded by a user.';
+ const MAINTAINER = 'VerifiedJoseph';
+ const PARAMETERS = array(array(
+ 'profile' => array(
+ 'name' => 'Profile URL',
+ 'type' => 'text',
+ 'required' => true,
+ 'title' => 'Profile URL. Example: https://www.scribd.com/user/489040929/number10leaks-com',
+ 'exampleValue' => 'https://www.scribd.com/user/'
+ ),
+ ));
+
+ const CACHE_TIMEOUT = 3600;
+
+ private $profileUrlRegex = '/scribd\.com\/(user\/[0-9]+\/[\w-]+)\/?/';
+ private $feedName = '';
+
+ public function collectData() {
+
+ $html = getSimpleHTMLDOM($this->getURI())
+ or returnServerError('Could not request: ' . $this->getURI());
+
+ $header = $html->find('div.header', 0);
+ $this->feedName = $header->find('a', 0)->plaintext;
+
+ foreach($html->find('div.content ul li') as $index => $li) {
+ $item = array();
+
+ $item['title'] = $li->find('div.under_title', 0)->plaintext;
+ $item['uri'] = $li->find('a', 0)->href;
+ $item['author'] = $li->find('span.uploader', 0)->plaintext;
+ //$item['timestamp'] =
+ $item['uid'] = $li->find('a', 0)->href;
+
+ $pageHtml = getSimpleHTMLDOMCached($item['uri'], 3600)
+ or returnServerError('Could not request: ' . $item['uri']);
+
+ $image = $pageHtml->find('meta[property="og:image"]', 0)->content;
+ $description = $pageHtml->find('meta[property="og:description"]', 0)->content;
+
+ foreach ($pageHtml->find('ul.interest_pills li') as $pills) {
+ $item['categories'][] = $pills->plaintext;
+ }
+
+ $item['content'] = <<<EOD
+<p>{$description}<p><p><img src="{$image}"></p>
+EOD;
+
+ $item['enclosures'][] = $image;
+
+ $this->items[] = $item;
+
+ if (count($this->items) >= 15) {
+ break;
+ }
+ }
+ }
+
+ public function getName() {
+
+ if ($this->feedName) {
+ return $this->feedName . ' - Scribd';
+ }
+
+ return parent::getName();
+ }
+
+ public function getURI() {
+
+ if (!is_null($this->getInput('profile'))) {
+ preg_match($this->profileUrlRegex, $this->getInput('profile'), $user)
+ or returnServerError('Could not extract user ID and name from given profile URL.');
+
+ return self::URI . '/' . $user[1] . '/uploads';
+ }
+
+ return parent::getURI();
+ }
+}
diff --git a/bridges/SoundcloudBridge.php b/bridges/SoundcloudBridge.php
index 9607d33..99a2117 100644
--- a/bridges/SoundcloudBridge.php
+++ b/bridges/SoundcloudBridge.php
@@ -59,9 +59,13 @@ class SoundCloudBridge extends BridgeAbstract {
return parent::getIcon();
}
+ public function getURI(){
+ return 'https://soundcloud.com/' . $this->getInput('u');
+ }
+
public function getName(){
if(!is_null($this->getInput('u'))) {
- return self::NAME . ' - ' . $this->getInput('u');
+ return $this->getInput('u') . ' - ' . self::NAME;
}
return parent::getName();
diff --git a/bridges/TinyLetterBridge.php b/bridges/TinyLetterBridge.php
new file mode 100644
index 0000000..e9860b5
--- /dev/null
+++ b/bridges/TinyLetterBridge.php
@@ -0,0 +1,54 @@
+<?php
+class TinyLetterBridge extends BridgeAbstract {
+ const NAME = 'Tiny Letter';
+ const URI = 'https://tinyletter.com/';
+ const DESCRIPTION = 'Tiny Letter is a mailing list service';
+ const MAINTAINER = 'somini';
+ const PARAMETERS = array(
+ array(
+ 'username' => array(
+ 'name' => 'User Name',
+ 'exampleValue' => 'forwards',
+ )
+ )
+ );
+
+ public function getName() {
+ $username = $this->getInput('username');
+ if (!is_null($username)) {
+ return static::NAME . ' | ' . $username;
+ }
+
+ return parent::getName();
+ }
+
+ public function getURI() {
+ $username = $this->getInput('username');
+ if (!is_null($username)) {
+ return static::URI . urlencode($username);
+ }
+
+ return parent::getURI();
+ }
+
+ public function collectData() {
+ $archives = self::getURI() . '/archive';
+ $html = getSimpleHTMLDOMCached($archives)
+ or returnServerError('Could not load content');
+
+ foreach($html->find('.message-list li') as $element) {
+ $item = array();
+
+ $snippet = $element->find('p.message-snippet', 0);
+ $link = $element->find('.message-link', 0);
+
+ $item['title'] = $link->plaintext;
+ $item['content'] = $snippet->innertext;
+ $item['uri'] = $link->href;
+ $item['timestamp'] = strtotime($element->find('.message-date', 0)->plaintext);
+
+ $this->items[] = $item;
+ }
+
+ }
+}
diff --git a/bridges/TorrentGalaxyBridge.php b/bridges/TorrentGalaxyBridge.php
new file mode 100644
index 0000000..b71d2a5
--- /dev/null
+++ b/bridges/TorrentGalaxyBridge.php
@@ -0,0 +1,120 @@
+<?php
+
+class TorrentGalaxyBridge extends BridgeAbstract {
+
+ const NAME = 'Torrent Galaxy Bridge';
+ const URI = 'https://torrentgalaxy.to';
+ const DESCRIPTION = 'Returns latest torrents';
+ const MAINTAINER = 'GregThib';
+ const CACHE_TIMEOUT = 14400; // 24h = 86400s
+
+ const PARAMETERS = array(
+ array(
+ 'search' => array(
+ 'name' => 'search',
+ 'required' => true,
+ 'title' => 'Type your query'
+ ),
+ 'lang' => array(
+ 'name' => 'language',
+ 'type' => 'list',
+ 'exampleValue' => 'All languages',
+ 'title' => 'Select your language',
+ 'values' => array(
+ 'All languages' => '0',
+ 'English' => '1',
+ 'French' => '2',
+ 'German' => '3',
+ 'Italian' => '4',
+ 'Japanese' => '5',
+ 'Spanish' => '6',
+ 'Russian' => '7',
+ 'Hindi' => '8',
+ 'Other / Multiple' => '9',
+ 'Korean' => '10',
+ 'Danish' => '11',
+ 'Norwegian' => '12',
+ 'Dutch' => '13',
+ 'Manderin' => '14',
+ 'Portuguese' => '15',
+ 'Bengali' => '16',
+ 'Polish' => '17',
+ 'Turkish' => '18',
+ 'Telugu' => '19',
+ 'Urdu' => '20',
+ 'Arabic' => '21',
+ 'Swedish' => '22',
+ 'Romanian' => '23'
+ )
+ )
+ )
+ );
+
+ public function collectData(){
+ $url = self::URI
+ . '/torrents.php?search=' . urlencode($this->getInput('search'))
+ . '&lang=' . $this->getInput('lang')
+ . '&sort=id&order=desc';
+ $html = getSimpleHTMLDOM($url)
+ or returnServerError("Error querying the server at $url");
+
+ foreach($html->find('div.tgxtablerow') as $result) {
+ $identity = $result->find('div.tgxtablecell', 3)->find('div a', 0);
+ $authorid = $result->find('div.tgxtablecell', 6)->find('a', 0);
+ $creadate = $result->find('div.tgxtablecell', 11)->plaintext;
+ $glxlinks = $result->find('div.tgxtablecell', 4);
+
+ $item = array();
+ $item['uri'] = self::URI . $identity->href;
+ $item['title'] = $identity->plaintext;
+ $item['timestamp'] = DateTime::createFromFormat('d/m/y H:i', $creadate)->format('U');
+ $item['author'] = $authorid->plaintext;
+ $item['content'] = <<<HTML
+<h1>{$identity->plaintext}</h1>
+<h2>Links</h2>
+<p><a href="{$glxlinks->find('a', 1)->href}" title="magnet link">magnet</a></p>
+<p><a href="{$glxlinks->find('a', 0)->href}" title="torrent link">torrent</a></p>
+<h2>Infos</h2>
+<p>Size: {$result->find('div.tgxtablecell', 7)->plaintext}</p>
+<p>Added by: <a href="{$authorid->href}" title="author profile">{$authorid->plaintext}</a></p>
+<p>Upload time: {$creadate}</p>
+HTML;
+ $item['enclosures'] = array($glxlinks->find('a', 0)->href);
+ $item['categories'] = array($result->find('div.tgxtablecell', 0)->plaintext);
+ if (preg_match('#/torrent/([^/]+)/#', self::URI . $identity->href, $torrentid)) {
+ $item['uid'] = $torrentid[1];
+ }
+ $this->items[] = $item;
+ }
+ }
+
+ public function getName(){
+ if(!is_null($this->getInput('search'))) {
+ return $this->getInput('search') . ' : ' . self::NAME;
+ }
+ return parent::getName();
+ }
+
+ public function getURI(){
+ if(!is_null($this->getInput('search'))) {
+ return self::URI
+ . '/torrents.php?search=' . urlencode($this->getInput('search'))
+ . '&lang=' . $this->getInput('lang');
+ }
+ return parent::getURI();
+ }
+
+ public function getDescription(){
+ if(!is_null($this->getInput('search'))) {
+ return 'Latest torrents for "' . $this->getInput('search') . '"';
+ }
+ return parent::getDescription();
+ }
+
+ public function getIcon(){
+ if(!is_null($this->getInput('search'))) {
+ return self::URI . '/common/favicon/favicon.ico';
+ }
+ return parent::getIcon();
+ }
+}
diff --git a/bridges/TwitterBridge.php b/bridges/TwitterBridge.php
index 2f5565b..0d8b024 100644
--- a/bridges/TwitterBridge.php
+++ b/bridges/TwitterBridge.php
@@ -172,11 +172,15 @@ EOD
$html = '';
$page = $this->getURI();
+ $header = array(
+ 'User-Agent: Mozilla/5.0 (Windows NT 9.0; WOW64; Trident/7.0; rv:11.0) like Gecko'
+ );
+
if(php_sapi_name() === 'cli' && empty(ini_get('curl.cainfo'))) {
$cookies = $this->getCookies($page);
- $html = getSimpleHTMLDOM($page, array("Cookie: $cookies"));
+ $html = getSimpleHTMLDOM($page, array_merge($header, array("Cookie: $cookies")));
} else {
- $html = getSimpleHTMLDOM($page, array(), array(CURLOPT_COOKIEFILE => ''));
+ $html = getSimpleHTMLDOM($page, $header, array(CURLOPT_COOKIEFILE => ''));
}
if(!$html) {
diff --git a/bridges/VkBridge.php b/bridges/VkBridge.php
index 713b86f..ea81a2b 100644
--- a/bridges/VkBridge.php
+++ b/bridges/VkBridge.php
@@ -374,6 +374,8 @@ class VkBridge extends BridgeAbstract
} elseif (strstr($strdate, 'yesterday ') !== false) {
$time = time() - 60 * 60 * 24;
$strdate = date('d-m-Y', $time) . ' ' . $strdate;
+ } elseif ($date['month'] && intval(date('m')) < $date['month']) {
+ $strdate = $strdate . ' ' . (date('Y') - 1);
} else {
$strdate = $strdate . ' ' . date('Y');
}
diff --git a/bridges/ZoneTelechargementBridge.php b/bridges/ZoneTelechargementBridge.php
index ab7b947..79723fc 100644
--- a/bridges/ZoneTelechargementBridge.php
+++ b/bridges/ZoneTelechargementBridge.php
@@ -8,7 +8,7 @@ class ZoneTelechargementBridge extends BridgeAbstract {
*/
const NAME = 'Zone Telechargement';
- const URI = 'https://www.zone-telechargement.net/';
+ const URI = 'https://www.zone-annuaire.com/';
const DESCRIPTION = 'Suivi de série sur Zone Telechargement';
const MAINTAINER = 'sysadminstory';
const PARAMETERS = array(
@@ -17,7 +17,7 @@ class ZoneTelechargementBridge extends BridgeAbstract {
'name' => 'URL de la série',
'type' => 'text',
'required' => true,
- 'title' => 'URL d\'une série sans le https://wwv.zone-telechargement.net/',
+ 'title' => 'URL d\'une série sans le https://www.zone-annuaire.com/',
'exampleValue' => 'telecharger-series/31079-halt-and-catch-fire-saison-4-french-hd720p.html'
)
)
diff --git a/formats/AtomFormat.php b/formats/AtomFormat.php
index a1ecfcf..c1bde25 100644
--- a/formats/AtomFormat.php
+++ b/formats/AtomFormat.php
@@ -89,6 +89,10 @@ class AtomFormat extends FormatAbstract{
. PHP_EOL;
}
+ $entryThumbnail = $item->thumbnail;
+ if (!empty($entryThumbnail))
+ $entryThumbnail = '<media:thumbnail url="' . $this->xml_encode($entryThumbnail) . '"/>';
+
$entryLinkAlternate = '';
if (!empty($entryUri)) {
$entryLinkAlternate = '<link rel="alternate" type="text/html" href="'
@@ -114,6 +118,7 @@ class AtomFormat extends FormatAbstract{
<content type="html">{$entryContent}</content>
{$entryEnclosures}
{$entryCategories}
+ {$entryThumbnail}
</entry>
EOD;
diff --git a/index.php b/index.php
index 666b9e4..ee37b22 100644
--- a/index.php
+++ b/index.php
@@ -18,7 +18,7 @@ if (isset($argv)) {
}
define('USER_AGENT',
- 'Mozilla/5.0 (X11; Linux x86_64; rv:30.0) Gecko/20121202 Firefox/30.0(rss-bridge/'
+ 'Mozilla/5.0 (X11; Linux x86_64; rv:72.0) Gecko/20100101 Firefox/72.0(rss-bridge/'
. Configuration::$VERSION
. ';+'
. REPOSITORY
diff --git a/lib/Configuration.php b/lib/Configuration.php
index 6d52423..76a34af 100644
--- a/lib/Configuration.php
+++ b/lib/Configuration.php
@@ -28,7 +28,7 @@ final class Configuration {
*
* @todo Replace this property by a constant.
*/
- public static $VERSION = '2019-12-01';
+ public static $VERSION = 'dev.2020-02-26';
/**
* Holds the configuration data.